https://ourway.ir/Why_And_How_I_Switched_From_Python_To_Erlang.html
注意我的 Chrome 直接打开这篇会崩不知道为什么,要 Safari 才能顺利打开。
通常情况下对这种文章我是直接忽略的,因为多半是神经病一样的“看我的 Hello World 请求在 BEAM 下跑的飞快,再看你那慢如狗的 Rails”。。。但是这篇文章说到点子上了,而且很多对于 Python 的论据也适合于 Rails,或者是 Ruby(是的我天天鼓吹的 Cuba 架构也有这个问题)。Rails/Ruby 发展到现在,绝大多数问题都是有解决的方案的,Sidekiq,Russian Doll Caching 等等都是为了解决所谓的慢而出现的。但是在工程圈里,有解决方案并不是唯一的 metric,很多时候我们要考虑投入产出比。虽然用上面的许多方案可以解决 Rails 的问题,但是考虑这样的场景:一个资深工程师充分设计并调优之后的一个 Rails codebase,可能也就是跟一个初学者随便写写的 OpenResty,或者是 node.js 框架跑的差不多快,我不知道大家,这时候我是很有挫败感的。
所以我最近反思的一个主题是:是不是真的有必要追求 Rails/Ruby 那可能只有 10% 或者 20% 的生产力提升,而抛弃整个框架设计层面的许多可能性。这已经不是 Rails 刚出现的那个时代了,现在其他语言的框架 (包括 Java) 也充分吸收了 Rails 的很多优点,生产力也已经大幅提升,Rails 已经没有那种数量级上的差距了 (当然从这个角度来说 Rails 很成功,这个我十分赞同)。说的偏激一点,这 10% 或者 20% 现在是否存在,也是一件有争议的事情,并不是每个人都认同。
当然也不是说 Ruby 就这样完了,我觉得 HTTP/2 就是一个 Ruby 可以利用的好机会,配合 HTTP/2 带有 Push 机制的架构,这正是一个我们反思 Rack 是不是适合 HTTP/2 的机会,完全可以趁这股潮流重新设计 Rack,做一个基于 Fiber 的结构,虽然这样跟 HTTP/1 会有非常大的冲突,但是这给了 Ruby 社区一个可能性:传统项目完全可以继续走 HTTP/1 以及 Rack 1.x 继续走原来的路,如果想做新一代的 web app,这样的全新架构也可以提供跟 OpenResty,Elixir 竞争的底气。
无奈现实不给力,现在 Ruby 社区对 HTTP/2 的使用真的很让人痛心:一部分人在忙着把 Rack 的 API 从 hash-based 改成 object-based,另一部分人把 nginx 换成新版本然后就此标榜 Rails 是 HTTP/2 的了,这是在过家家么 -_-
另外我在广义层面上不赞同 "Right Tool For The Right Job" 的观点。这个观点只适用于大公司,初创企业即使有工程师出身的开发人员,也要身兼数职,更何况很多初创企业是其他行业的人半专职过来写代码,这种情况下面对 HTML/JS/CSS/Ruby 就已经很头痛了,我们还不帮忙把这个 list 减少反而要引入更多的工具,究竟是在做项目还是在玩工具。。。
求大神把我骂醒
很多观点和楼主不谋而合,我也很期待 Ruby 社区发力 http/2,不过貌似其他语言框架也很少跟进。 也许大家使用习惯还没发生改变吧,push 时代更像是 live 时代,场景想不到太多
#1 楼 @small_fish__ 我个人觉得这个不是缺场景的问题,Firebase 的 API 里已经开始做 Real Time 的东西了,在客户端主动去服务器端拉数据之外,服务器也可以把新数据主动推送到客户端。
我的想法是这个和当年的下拉刷新一样,只需要一个引爆点,一旦有一个流行的 app 把这个东西引入,培养出来习惯之后,所有的 PM 都会要求工程师同样去做这些事。这时如果没有解决方案,那不是工程师的锅,但是既然 HTTP/2 给出了这样的架构我们还不去这样做的话,那就是我们的问题了。如果真到了每个 app 都这样做的时代,Ruby 才去应对就晚了
是不是真的有必要追求 Rails/Ruby 那可能只有 10% 或者 20% 的生产力提升,而抛弃整个框架设计层面的许多可能性。
肯定要参考公司规模和盈利水平了,社区方向是折衷,有金主支持社区的另说了。
这只是一个调度器和 supervisor 在哪里的问题。
http2 push 的问题加个 link rel=preload 头自然就能用上 push 的特性 (nghttpx, h2o 都支持). nginx 系的 cloudflare 也支持这个 (感觉是私有实现,没开源). 没有 http2 push 这个 link 头也是有意义的。
#8 楼 @fcicq 我理解你是想说 http2 协议自己的 server push 是只能推到 cache 推不到 application 层的,但是还有个东西叫做 Server Sent Events。同时 HTTP2 只是我举的一个例子而已,我的核型观点是 Ruby 圈不务正业好久了
是不是真的有必要追求 Rails/Ruby 那可能只有 10% 或者 20% 的生产力提升 ...
其实 Ruby Rails 给我们带来的不适开发效率提升,而是一套理念,引领潮流的理念,做事解决问题的方式
文中的 benchmark 有点问题,事实上通过 Python/Rails 和通过 SQL 查询的区别达不到 10 倍,快查询 2 到 3 倍的差别是应该有的,慢查询大头还是在 SQL
openresty 啊我试过,感觉啥都干不了... 我是被宠坏了
前两天 Teddy Wang 给我看了他们用 Elixir 写的 api,生产环境居然有 2ms 的 response time。瞬间毁了我的三观,好快,好快,好快。
学一下 Elixir,扩充一下知识体系挺好。
#25 楼 @xiaoronglv 现在就是这样,Ruby 拼死拼活优化之后,可能都没有别的技术随便拿来写写的快(当然我不是在暗示这里提到的 Teddy Wang 他们只是随便写写,2ms 还是很牛的,不过随便写写可能也有几十 ms 的级别的了,这基本上跟合理优化过后的 Rails 是一个量级了)
这已经是一个很危险的信号了:如果我们再不反思如何变通,而是继续死心眼的坚持“瓶颈在 SQL 而不在 Rais”,或者是“你需要那么快么”,或者是“机器比人便宜”,那从 Ruby 圈流失的人只会越来越多。
#30 楼 @zgm 这个结论太没有意义了,ruby 最后也是生成机器码,activerecord 也是生成 SQL
html 尤其是 DOM 树是非常低效的,看看 atom 的表现就知道了。看到 shadow dom,我觉得眼前一亮,不过这个 shadow 好像还不是 COW 的概念,设想如果 HTML 有 COW,把相同的 DOM 集合在一起,内存也会得到充分利用。
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/
#32 楼 @luikore 这是一方面,另一方面是基于 Rack 的这套系统也从来没为性能考虑过。参考 OpenResty 里面是可以跑 Lua 官方的实现以及 LuaJIT 的,根据场景的不同,很多重 IO 轻计算的需求中,Lua 官方实现即使就是一个 interpreter,也没有比 LuaJIT 慢很多,归根结底是基于 coroutine 的结构减轻了很多架构上的负担。
所以我赞同 Ruby 本身的语言设计就不适合优化性能,但是 ecosystem 的方向也没有为性能考虑过,假如大家都在 fiber 的方向上努力,那即使达不到 2ms 那种级别的性能,至少也不会是现在赤裸裸的被嘲笑的现实了。所以我觉得总把锅放在虚拟机上面是不对的。
PS:ActiveRecord 真心不熟这个就不直接评论了,省的被抓到小辫子,毕竟吕神歪楼的能力还是一等一的
很多都是 trade off, Lua 为了实现简单容易优化,实际用起来很多限制,例如最多 512 个变量。而由于 Lua 设计统一 list 和 map 为一个 table 数据结构,LuaJIT 还会猜 table 实际是当成什么用的而作特化优化。
我觉得 Rack 中一些可能影响性能的问题:
Rails 的一些可能影响性能的问题:
redirect_to :back
改成了 redirect_back
HTTP/2 也不是万能药,连接断了或者中间有 proxy 就不行了... 实际上 websocket 甚至退化成 long polling 做 server push 更实用。在资源加载上,HTTP/2 也不一定比简单粗暴的 asset 打包快。HTTP/2 还有一个作用是 multiplexing, 一个 TCP 连接完成多个连接,但其实传输层已经有 multiplexing 了,就是新开 TCP 连接比较慢而已,现在 TFO(TCP Fast Open) 已经标准化,HTTP/2 对比开 TFO 的机器应该也没明显的优势。
应不应该 Fiber 化呢?其实 Ruby 的 Fiber 在很多地方都像线程... 预分配的栈也比较大。但是基于线程的话兼容性无疑是更好的,调用很多 C-library 不会有线程安全问题。基于线程实现上万连接的服务器也有... 就看操作系统的线程调度了。
在 eventmachine 和 goroutine 的发展过程中也暴露了不少坑。例如一个 coroutine 花时间很久没交出控制权怎么办... 得用一个定时器过一段时间去打断一下它,保证不会因为某个 routine 而卡住。而 coroutine 和操作系统的事件队列配合也是有坑的,例如你收到一个事件但处理延后了,这个事件过时了怎么办... 那都是要处理的。
服务器的优化不完全是 Rails 的锅,例如操作系统改个内核什么的往往有奇效... 但现在各种用 docker 之类的就是在牺牲操作系统调优的可能性哇...
Rails/Rack 发展到现在功能已经太多,而做个简单的服务往往用不到很多功能,这也是 trade off...
#37 楼 @small_fish__ 是的我们也有同样的体验,从来就不需要那些无聊的 Russian Doll Caching,感觉就是自己给自己找麻烦。
另外就是如同上面 @nouse 说的(虽说我觉得这位同学吵架朝偏了),现在越来越多的 startup 的架构是前段直接 native app,或者是 web app,然后通过基于 JSON 的 API 来跟服务器通信,这样 Rails 提供的很多拼模版的功能完全没有必要了,而且还带来额外的性能负担。从这个角度讲,可以认为 Rails 这一套已经逐渐过时了(是的我了解有 Rails API 的存在,但是性能还是很拙急)
同时 H2 Server Push/Web Socket 带来的 Real Time 架构是 Rails,甚至基于 Rack 的 Ruby 都没有办法处理的。从这里来说,我感觉现在再选择这一套就是先给自己挖了个大坑,然后安慰自己这个坑还不够深。。。
最后再给一刀,虽然我尽一切可能不用 Elixir,但是 Elixir/Phoenix 这一套也已经挤压到传统的 Rails 生存空间了,这是刀刀把人往死路上逼啊
还是那句话,我个人的观点是,虽然现在 Rails 看起来还可以,但是其实已经到了很危险的时刻了,社区再不做些什么,就只能是走向衰落了
#36 楼 @jasl 最近刚刚有 VM 级的大神表示这条路不是很好:https://www.youtube.com/watch?v=b1NTaVQPt1E,我很尊敬 Yehuda 这个人,但是每个人都是有自己擅长的领域的,涉及底层性能优化部分,个人认为 Yehuda 不是很懂。
另外就是跟我之前回复吕神的观点一样:现在问题不仅仅是 VM 层,更多的是这个 ecosystem 导致的架构上没有什么灵活性,而且问题起源甚至不在 Rails,而在 Rack 层。
我对 Rails 了解越多就越不喜欢 Rails 的很多理念,虽然带来了一些书写上的方便,和前期开发效率的高效。比如 ActiveRecord(查询和表示的耦合、callback 等)、Rails 自造的 Autoload、试图自己实现前端的工作等等。感觉因为 Rails 一直都是从 Ruby 分裂的状态,使得整个 Ruby 社区都有点被 Rails 带着(带跑?)的感觉,很多时候其实已经不是在写 Ruby 了,Rails 本身已经是一门语言了
当然,简单的应用还是可以用 Rails 写啦
#38 楼 @luikore 太长了就不逐条回复了,况且很多观点我是支持的,我只写几点:
CGI 的历史遗留
,这个真的是我遗漏了,我一直以为 hash based API 改成 object based API 更多的只是语法糖的处理,真没想到这个就像我反复提到的,这里不是说 Rails 完全不好,这里更多的是说,我们需要给大家提供更多的 options,不然现在 Ruby 圈的弱点会远远压倒仅剩不多的好处
@luikore 再补充一点,反复提到用 Fiber 的另一个好处是针对合适的项目可以直接上 mruby 了,没有必要搞 CRuby 这一套,配合 nginx 或者 h2o 嵌入使用 mruby 又是新的一片天
@nouse 的观点我非常赞同。rails 适合那种服务端渲染 html 的应用,当现在普遍习惯写富前端 app 的时候,rails 在 api 服务器编程方面并没有体现出比 node.js 更多的优势。最好用的就是 activemodel 咯,但慢也慢在它,而且其他语言的 orm 也是存在的嘛。
#49 楼 @joshhu Thanks for the information, it seems they started with Rails 2.3 in 2009, and now they also adopts nodejs in backend. http://www.slideshare.net/spikebrehm/the-evolution-of-airbnbs-frontend/53
感觉如果能把缓存覆盖率做高,gevent 这类并发机制就尽量可以不用了,我们这边有几个 python rpc 服务摘掉 gevent 也可以做到几 ms 的延时几 w qps,与打 gevent 占用的资源差别不大,都挺吃机器的... 这时异步带来的复杂性多于好处,接口的 P95 等延时指标容易躺着受其他请求的 cpu 操作干扰影响诊断问题,设不好协程池子会傻 accept 请求容易过载,数据库池子设大了会打爆连接数设小了又限制并发
PHP 核心开发者 Laruence(鸟哥)在 QCon 2015 上说了这么一段话(大意):
我曾经用了 PHP 和某高级语言做 hello world 的 benchmark,结果某高级语言胜过 PHP 一个数量级。 然后我分别添加了一条 SQL 查询,它们变成了一个数量级,但是某高级语言还是比 PHP 快两三倍。 然后又加到 10 条 SQL 查询,他们几乎没区别了。
开发效率对我来说还是有一定优势的。。。。太讨厌 java 的各种配置和下载 jar 包。。。。
貌似现在那边也有 play 和 grails,都没有尝试过。 有 maven,gradle 和各种 jar 解决方案,但是好像资深 java 都不喜欢用。。。。他们还是喜欢到处找 jar,然后一个一个解决 CNE.
#53 楼 @imwildcat 鸟哥这种 php 死忠的话就不要深究了
orm 发展了这么多年就是为了把人从 sql 里面解放出来。建议学习学习 sequel,比如自动生成 prepared statement,http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/PreparedStatementsSafe.html 还有 rcte 支持,不要手写 common table expressions http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/RcteTree
用过 openresty,快,但是稍微复杂点的逻辑写起来就很繁琐了。 从全栈角度看 Rails 优势还是很大,毕竟周边库那么多 非全栈的话每个语言、框架都有各自的优势,没有可比性
phoenix 比 rails 简单直接的一点是可以针对不同的 request route 设置不同的 pipeline, rails 至少应该把 mount middleware 这段生成到 initializer 中去...
再扯扯对 HTTP/2 的一些思考...
其实单连接多请求好处是每个请求的 overhead 减少了,一些场景已经不需要 sprite 打包图片了 反正 Rails 的 asset pipeline 生成 sprite 和 font 又复杂又有点问题,那干脆就用 HTTP/2 serve image / svg, 的确是 nginx 换一下就能得到好处...
但如果有很多特别小的图片例如图标,http2 也没有 sprite 性能好,但为了技术栈简洁起见,把图标 base64 inline 到 CSS 里更简单。
首先不好意思挖个坟,如今各种语言各种框架大爆炸,XXX 的 YYY 框架比 Rails 快 ZZZ 倍已然成为日常。XYZ 都是变了而 Rails 总是常量,从侧面可以看出 Rails 之于 Web dev 的特殊地位。
的确 Rails 在面对日新月异的项目/业务需求时常常力不从心,比如 websockets/高并发场景,如果我有一个 realtime 的产品需要处理几十上百万的并发我会毫不犹豫地选择一门 FP 和 tool chain,比如 Elixir, Clojure, etc。
然而这种明显项目毕竟是少数,独角兽一年也出不了几个,我辈 90% 的屌丝开发者在做 90% 的屌丝项目( 自黑,请勿对号入座)。面对这些项目我认为大部分项目的需求用 Rails web2.0 那套都足够了。君不见 Basecamp Github 甚至 Shopify 用正统或类似 Turbolinks + SR view + SRJ(Stimulus/Jquery) 那一套,照样可以应付千万级别的用户,X00k 级别的并发,这已然超过 95% 的项目。SPA + SSR + VDOM 对于普通项目的提升能有多大?增加的复杂性和冗余 (NOT DRY) 又有多少?值得吗?这应该是技术选型前最值得考虑的问题。
就像 DHH 和他的小伙伴们用 TL + SRJ + Stimulus 让项目照样稳定运行持续成长 (Desktop IOS Android Mobile Email 一套通吃)。说的世俗一点,DHH 美刀大把赚,还能省出的时间每年几次带着美妻,孩子从冰天雪地的芝加哥到加州 Malibu 的海边豪宅渡假赛车(可以 follow 他的 IG: https://www.instagram.com/dhh79/?hl=en)。
No fancy“COOL KIDS”tech stack, but handy tools for solving real problems, 这不是做事的一个理想状态吗