Ruby Ruby Web 框架简单介绍

robbin · 2013年03月29日 · 最后由 dingyiming 回复于 2015年12月10日 · 28116 次阅读
本帖已被管理员设置为精华贴

既然提倡去 Rails 化我很想介绍一下 Rails 之外的 Web 框架,懒得长篇大论写文章了,简单写个帖子。

比较适合写 Web 服务接口的轻量级 Web 框架我推荐两个:Grape 和 Sinatra,两个的区别主要是:

Grape 是个纯粹的写 API 的框架,提供了很多写 API 很方便的功能,用 Grape 写 API 很爽,应该是首选,他只提供 json/xml/txt 格式输出。

Sinatra 是个相对完善点的 Web 框架,带有模板渲染功能,但单纯写 API 的话,没有 Grape 爽。不过如果你的 API Server 有可能输出 HTML 页面片段,需要模板功能的话,还是 Sinatra 更合适,否则用 Grape 在代码里面拼字符串还是很麻烦的事情。

Grape 和 Sinatra 都是基于 Rack 之上很轻量级的封装,我做了框架处理请求速度的测试,以及多线程并发的简单测试,基本上性能差异非常小,Grape 稍微快一点点,但不超过 5%。测试结果

比较适合写 Website 的框架,功能最完善的当然是 Rails,不过我用 Padrino 做了自己的网站项目,发现也很不错,推荐大家用用。

最后说到并发性能,我自己的测试结果表明,Ruby 的多线程性能在并发量并不是超高的情况下,还是很不错的,对比 Fiber 的来说,性能差异非常小。我做了 Goliath(raw code), Goliath(Grape), Rainbows(Grape), Puma(Grape), Rainbows(Sinatra), Puma(Sinatra), 的并发性能测试,基本在同一水平线上。测试结果

所以如果用 Ruby 写高并发的 API Server,即使不用 Goliath 也行,用 Grape/Sinatra 写 API,用 Rainbows 来跑即可,性能也非常好,而且 Rainbows 的可管理性也非常棒,和 Unicorn 一样方便。

Grape 可以嵌在 rails 里用么,同样的 Model 不想写两遍呀 另外,楼主你终于凑够 10 个回帖啦?

一直用 Grape,这样做还是为了所有的 model 不用单独维护,website 和 API 都可以共用

#1 楼 @ywencn grape 和 sinatra 都可以嵌入到 Rails 里面用。

谢谢@robbin ,关注下,打算下个项目试试

#4 楼 @robbin 同一个 app 能 mount 两次么?

padrino 真心不错

#4 楼 @robbin 就是相当于 sinatra 的 modular 风格吧?

谢谢@robbin ,又省了我们自己测试对比了

貌似 espresso 和 cuba 很快就被忘了...

grape 有点不爽,它的 before after filter 不支持 only 或者 except 参数,只能用于全部

多谢 LZ,赞测试对比。

@robbin 问个问题,在 云时代 移动互联网时代,还有 Ruby 的发展空间吗?!是不是 Go 等静态编译的语言更有发展前景?

#13 楼 @diguage 没有了,学「云时代的语言」去吧。

#14 楼 @blacktulip 哈哈,在一个群里大家讨论时,说移动互联网时代,用户会突然暴增!还没等优化,服务器已经受不了了。 所以,当时,群里就说推荐学习 Go。

其实,我挺喜欢 Ruby,虽然刚刚开始学。所以,看看 Ruby 以后会不会有更好的发展。啊哈

我错把移动互联网时代说成云时代。抱歉!哈哈

喜欢 ruby 也关注学习 go

#3 楼 @robbin 那您觉得 社交类 model 不多 但是并发可能会高一点的站 Rails 还是 padrino 更好呢

#15 楼 @diguage 我觉得移动互联网时代嘛,这么多用户都把服务器挤爆了,所以一定要用 erlang,再搞个分布式什么的 靠谱

#20 楼 @knwang 已经差不多了 但是我个人来讲关心的是技术水平 而不是产品发布 也仅仅是小范围好友圈使用的 不对外 所以我想要不要重构下

#22 楼 @zj0713001 没有大规模的实际需求你的技术选择是空中楼阁,难以体会到轻量框架给你的好处

#20 楼 @knwang 其实想想自己写了很多有意思的应用 以前我们几个好友经常出去玩 到了外面花钱都是一人掏 比方说午饭 A 掏 晚饭 B 掏 回来几个人再算账 后来就经常出现糊涂账 于是我就写了个小应用 Model:项目 花销 参与人数 付款人 每次花钱就记下来谁花的 同时记下时间地点人物 最后 每个人能看到自己需要给别人多少钱 同时还能转移债务...

#24 楼 @zj0713001

写玩具项目是最开心的 :)

@robbin 你压力测试用的是 siege,请问这个工具和 ab 有什么区别呢?我对压力测试很感兴趣。

Grape 一直用,配合 Grape Entity 做 json 的渲染很方便。我还 hack 了一点点,基本上满足了大部分的开发需求。唯一不方便的是多模块的使用,不能很好的 reload。

#26 楼 @cgyy siege 功能比 ab 丰富一些。

#28 楼 @robbin 谢谢,我也装一个试试

总之,哪个合适用哪个

#15 楼 @diguage 用户会突然爆增这种事情是谁意淫出来的啊。。

#31 楼 @iBachue 同感 先解决你的产品足够有意思的问题,再解决用户突然爆增的问题吧

非常不错的介绍!

中国的云时代的到来,呵呵,哈哈 慢慢来,不用急

关注下,,,

#4 楼 @robbin 类似 django app

Padrino 还是挺简洁的。适合入门用。

楼主顺便加上 Rails 的测试结果对比下吧。

@robbin 肉饼问个问题,如果用了 Goliath,是否有必要用 Nginx 来做前端的代理,或者后面启动多个 Goliath Server 进程,用 Nginx 来做负载均衡。由于 Goliath 本来就是为了高并发设计的,再用 Nginx 做代理是否有必要或者是否能明显的提高并发能力?谢谢。

#39 楼 @outman nginx 可以处理静态资源,例如 css,download file。

@robbin 你做的这个太棒了:https://github.com/robbin/grape-goliath-example 我一直对新版本的 Goliath 没有个好的路由解决方案头痛不已。

#40 楼 @jimrokliu 嗯,这个我知道。我这里说的是单纯的 API SERVER,没有页面渲染,没有 CSS。

#42 楼 @outman 这个看你是否有用 nginx 干一些其他的事情,例如记录 ip 地址,防止直接攻击你的 appserver,负载均衡,还有些事情可以在 nginx 上做 lua 的脚本实现。

#43 楼 @jimrokliu 是的,用了 nginx 确实会让很多事情处理起来更加方便。只是不知道,用与不用,只考虑单纯的 api call 的情况下有多少区别,是不是用了 nginx 后,能提高并发能力?

#44 楼 @outman 使用 nginx 放在 api 请求前应该不会提高并发能力,api 的并发取决于你的 appserver 的并发能力。

#45 楼 @jimrokliu 由于 Goliath 本身就支持高并发了,所以我一直觉得,在前面放个代理貌似作用不大,除非你用代理,做负载均衡。

#46 楼 @outman 还有一些其他的原因,例如不希望 Goliath 以 root 身份运行在 80 端口。

#47 楼 @jimrokliu 还有,可以让 nginx 和 Goliath 通过 socket 进行通讯。不一定非得走 http。

#39 楼 @outman 需要,因为 Goliath 每个进程只能利用 1 颗 CPU 内核,在多核服务器上,你需要启动多个 Goliath 进程,分别监听不同的 tcp port,所以前面需要 nginx 做请求分发。

另外就一般应用而言,我没有测试出来多线程比 fiber 差多少。我还是建议用 rainbows 跑多线程,rainbows 自己有进程调度能力,而且多线程方面无论是驱动还是库兼容性都比较好。

原来你们都不会 socket 啊...

#47 楼 @jimrokliu

不希望 Goliath 以 root 身份运行在 80 端口。

你可以先以 root 去 bind 80 端口,setuid 成 appuser,再去执行 Goliath...

比如用老土的 supervisord 就可以,假如你放心用 root 运行 supervisord,那么你可以用那个fcgi-program的功能,这个名字起得不好,其实所有 TCP/Unix domain socket 都可以。

而且用于 Unix domain socket 的时候,你可以把user设置成 appuser,把socket_owner设置成nginx,这样两者就完全隔离开了,并且以其他非 root 用户运行的程序也 connect 不了这个 unix domain socket。

当然,这样就需要 supervisord 是 root 了,这显然不是很好。当然也可以尝试去获得连进来的 socket 的 uid,gid 来判断,如果不是 nginx 的直接关掉。但这里要用到一些高级的 socket 操作,而且判断 uid/gid 的逻辑和应用代码搅在一起,这么做是否值得也说不好。

而且最新的 Linux 内核也支持 capability 了,完全可以只给一个仅用于占端口的 capability,bind 完了之后 drop 掉就是了。

#48 楼 @outman

可以让 nginx 和 Goliath 通过 socket 进行通讯。不一定非得走 http。

通过 TCP Socket 还是 Unix domain Socket 和用啥协议没啥关系。两种 socket 上面都可以是 HTTP/FastCGI/SCGI 等协议。

#49 楼 @robbin

在多核服务器上,你需要启动多个 Goliath 进程,分别监听不同的 tcp port,所以前面需要 nginx 做请求分发。

所有的 Goliath 进程当然可以监听同一个 tcp port 了。最简单的办法就是,先 bind 到某个 tcp 端口,fork 成多个进程就好了。但要想动态调整就得写点代码了。

假如你不想自己 fork,你可以试试 supervisord 的fcgi-program,这个名字起得不好,其实所有 TCP/Unix domain socket 都可以。把numprocs_start改成 5,在进程里面都listenfd=0 的那个 socket,看是不是 5 个进程都在监听同一个 tcp 端口了呢...

http://supervisord.org/configuration.html#fcgi-program-x-section-settings

#50 楼 @bhuztez 我貌似提到 socket 了吧。

#49 楼 @robbin 了解了,谢谢。

#50 楼 @bhuztez Goliath 不支持监听 unix socket。

#53 楼 @robbin socket 就是可以多个进程一起 listen 的来着,补上内容了,翻回去自己看...

读了你的 Blog,有一种豁然开朗的感觉。希望继续能写更新下去。:)

#50 楼 @bhuztez 你这种用法其实是有问题的,多个进程监听一个端口,存在惊群问题。无论如何都需要一个 dispatcher 来负责请求调度和负载均衡,无论是用 nginx,还是别的什么方式,这不仅仅只是一个端口监听的需求。

#57 楼 @robbin 难道你觉得 nginx 有特异功能

#58 楼 @bhuztez

1、请求调度 2、负载均衡

不一定是 nginx,也可以是 lighttpd,haproxy,甚至或者直接用 iptables 也可以做简单的 dispatcher。

#59 楼 @robbin 你的思维能不能别一下子就从单线程就跳到多台机器。

多个进程 listen 同一个端口,没有所说的请求调度/负载均衡的问题。你这个进程响应不过来,没 accept,另外一个进程有空,正在 accept,那这个连接当然被另外一个进程处理了。如果你希望限制单进程同时处理的连接数也是一样的啊,当当前保持的连接数等于你预先设定的值的时候,别去 accept 就是了

#27 楼 @jimrokliu 请问您是把 Grape 嵌入到 Rails 里面用的吗?还是 Standalone

我已经烦死 Rails 了!

正在学习,实践中,喜欢这种简单又很规范组件式开发方式,rails 有些 spring 的趋势,大而全

谢谢,学习了

lgn21st Unicorn fork 的多个进程之间数据是否可以共享 提及了此话题。 04月25日 09:19
anthony Ruby on Rails 入门体验 提及了此话题。 04月03日 10:56
需要 登录 后方可回复, 如果你还没有账号请 注册新账号