来 DTDS 全球数字人才发展峰会,与刘润、叶军、快刀青衣畅聊成长>> 了解详情
写点什么

范凯观点:Ruby 社区应该去 Rails 化

2013 年 3 月 28 日

InfoQ 中文站报道过一些公司从 Ruby 转移到其他语言的新闻,包括 Iron.io 从 Ruby 迁移到 Go:减少了 28 台服务器并避免了连锁故障从Ruby 向Java 的迁移帮助Twitter 挺过了美国大选在LinkedIn 的Ruby on Rails 和Node.js 对决。最近,IT 元老范凯在博客中详细地分析了Rails 目前在Web 服务方面的局限和原因,针对“继续沿用Ruby on rails 重写或者重构应用,性能可能会有一两倍的提升,但无法弥合10 倍以上的性能差距,难道说Ruby 真的如此不堪吗?注定要被Node.js 或者Go 所取代吗?”这个问题给出了自己的观点,即:使用其他Ruby 轻量级框架取代Rails,而不是使用Node.js 和Go 取代Ruby。

针对Ruby 的性能问题,范凯首先做了澄清,存在性能问题的是Rails,而不是Ruby 语言本身,他引用了Ruby 的纤程框架 Goliath 的实际应用数据:

  • VPS 上总共使用了 16 个 CPU 内核,跑了 16 个单进程实例
  • 每个进程实例稳定消耗 50MB 内存
  • Web 框架使用 Goliath, URL 分发是 grape,数据库访问使用 ActiveRecord,缓存使用 Redis
  • 应用吞吐量达到了 1800 request/s

这个数据意味着一台配备了 4 颗 4 核 CPU,2G 内存的服务器,每天可以处理 1.5 亿次 web 请求。由此可见,Ruby 完全可以做到高并发 IO 的应用。问题主要不在 Ruby 解释器上,而在 Rails 框架上。更准确的说就是, Ruby on R****ails 作为一个 full-stack 的 web 开发框架,并不适合用来开发 Linkedin 和 Iron.io 的后台 web 服务,从某种意义上来说,属于 Rails 的时代已经过去了。

范凯表示:移动时代,Web 服务将取代 Web 网站。为什么 Rails 不适合 Web 服务呢,他认为主要原因包括:

  • Rails 调用堆栈过深,URL 请求处理性能很差Rails 的设计目标是提供 Web 开发的 最佳实践 ,所以无论你需要不需要,Rails 默认提供了开发 Website 所有可能的组件,但其中绝大部分你可能一辈子都用不上。其中最夸张的是ActionDispatch::RequestIdmiddleware,只有在大型应用部署在群集环境下进行线上调试才可能用到的功能,有什么必要做成默认的功能呢? Rails 的哲学是:提供最全的功能集给你,如果你用不到,你自己手工一个一个关闭掉 ,但是这样带来的结果就是默认带了太多不必要的冗余功能,造成性能损耗极大。
  • Rails 加载的框架和依赖库过多,内存消耗过度。Rails 自身依赖库非常多,造成的结果就是 Rails 应用持续运行以后内存消耗非常高。举个例子:如果你用到了 Rails 的 asset pipeline 功能,那么项目需要依赖一个 JS 引擎来编译 JS 和 CSS,默认会使用 libv8 这个库。尽管只是编译阶段使用 libv8,运行期并不需要它,但是仍然会加载 libv8,这意味着你的每个 ruby 进程会多占 20MB 内存。在我们其中一个大项目上,总共开了 40 个 Ruby 进程,直接浪费了 800MB 内存。于是我们不得不在生产服务器上安装了 Node.js,替换了 libv8。此外,一旦其中某个依赖库有内存泄露,整个应用也可能出现内存泄露,这种内存泄露是很讨厌的事情,Rails 如此肆无忌惮不加限制的使用第三方依赖库也是一个潜在的隐患。
  • Rails 传统多进程模型的 IO 并发能力很低。Rails 的多进程并发模型的 IO 并发能力很低,开多少个进程,就只能同时响应多少个并发请求,但 Ruby 进程的内存消耗是很大的,多进程调度的 CPU 开销也很高,这决定了单台服务器上能开的进程数是非常有限的,一般不会超过 30 个。但是对于 Web Service 类型的应用,需要很高的 IO 并发处理能力,传统 Rails 多进程很容易就会出现负载的瓶颈。从 Rails4.0 开始,默认也开启了多线程模式,也可以支持多线程方式运行 Rails 应用。但就目前来说,Rails 使用多线程,还面临一些兼容性问题:大量的 Rails 插件和代码不是线程安全的,在多线程模型下运行,会出现意想不到的 bug;另外 Rails 的多线程应用尚未得到广泛应用,可能会有潜在的 bug。

不用 Rails,Ruby 社区又能用什么呢?范凯提供了自己的建议:

  • Sinatra ——Sinatra 本身也是 Ruby 社区非常流行和著名的轻量级 Web 框架,核心源代码不超过 1000 行,文档只有 1 页。对于 Rails 开发者来说,花了几个小时,就可以快速使用 Sinatra 开发 Web Service 了。Sinatra 对多线程支持的非常好,可以用 rainbows 来跑多线程 Sinatra,IO 并发处理能力很好。Github 也是用它来提供开放 API 服务的。我自己写了一个 Sinatra 的项目模版,如果你用 Sinatra 开发 Web Service,可以参考。
  • Padrino ——Padrino 是一个基于 Sinatra 之上的轻量级 Web 框架,在 Sinatra 基础之上提供了命名路由,模块化项目组织,页面 helpers 和 generators 等等。Padrino 是一个高度模仿 Rails 的框架,API 的命名和 Rails 很像,Rails 开发者花 1-2 天看看文档就可以快速上手开发了。Padrino 相比 Rails 易学易用,多线程支持良好,性能比 Rails 好很多,开发 Website 推荐使用。我自己的网站也是用 Padrino 开发的,源代码在: robbin_site
  • Goliath ——Goliath 是一个 Ruby 的纤程开发框架,性能非常好,作者本身是在开发 PostRank 产品过程中开发的 Goliath。PostRank 是一个用户社交行为实时跟踪工具,需要很高的性能来支撑,PostRank 被 Google 收购了,作者现在在 Google 工作。Goliath 适合用来开发对性能非常敏感的 Web Service 或者 real-time 的应用,但使用 Goliath 有一些门槛,你不能使用普通的阻塞 IO 库,必须使用作者封装的一些纤程的库。

所谓的“去 Rails 化”,范凯认为不必大惊小怪:

学习 Rails 无非意味着你花了时间熟悉 ActiveRecord 和 ActionPack 以及相关库的功能而已,所谓去 Rails 化也仅仅只是放弃使用 ActionPack,换一个更轻量级更简单的 URL 路由处理器,例如换成 Grape,Sinatra,Padrino 或者 Camping 而已。这对一个长期使用 Rails 的 Ruby 开发者来说,应该是举手之劳的事情。所以自己动手,根据实际应用场景挑选最合适的组件。例如 ActionPack 不太适合写 Web Service,那我换成 Sinatra 就行了,但是 ActiveRecord 照常用,这并不需要你付出多少学习成本,更不需要你放弃什么。

目前有一些公司从 Ruby/Rails 转向 Node.js 和 Go,范凯经过调研,认为 Ruby 更适合自己:

  • 用 Sinatra 或者 Goliath 这样的轻量级框架写 Web Service,性能已经足够好了,特别是 @黄志敏的案例证明,16 核已经可以支撑每天 1.5 亿次请求了,对我来说已经不太可能遇到超过这个负载量的应用了。而 Ruby 的开发效率,代码表达能力和可维护性对我来说还是很重要的。
  • Node.js 的 Event IO 编程风格在我看来是“反人类”的,极其变态的。用来写代码上规模的应用,代码的可读性和可维护性都很差。Event IO 是很底层的技术,我很难理解为何不封装成 coroutine 来使用。Node.js 只适合用来开发 real-time 类型的应用。
  • Go 的主要问题在于现阶段还不成熟:一方面 Go 自身还在演进当中;另一方面 Go 的类库还是过于贫瘠了,用来开发项目还是需要自己写很多东西的,感觉很不方便。

有关范凯完整的论述,可以查看博客原文。欢迎 InfoQ 读者发表自己的看法。

2013 年 3 月 28 日 01:093425
用户头像

发布了 501 篇内容, 共 216.3 次阅读, 收获喜欢 34 次。

关注

评论

发布
暂无评论
发现更多内容

Spring Boot 中的项目属性配置

武哥聊编程

Java springboot SpringBoot 2 28天写作

精选算法面试-优先队列

李孟

算法 队列 28天写作

静态代理,jdk动态代理以及Cglib区别

Java架构师迁哥

一文搞懂参数传递原理

云流

Java 编程 程序员

《价值》- 投资分析(4)

石云升

零售 28天写作 价值 投资分析

九个最容易出错的 Hive sql 详解及使用注意事项

五分钟学大数据

sql 大数据 hive

一致性Hash算法Java版实现

Silently9527

Java 后端 一致性Hash算法

9条消除if...else的锦囊妙计,助你写出更优雅的代码

苏三说技术

赛博时代,拿什么盛放对逝者的思念?

脑极体

LeetCode题解:236. 二叉树的最近公共祖先,存储父节点,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

案例研究之聊聊 QLExpress 源码 (四)

小诚信驿站

刘晓成 小诚信驿站 28天写作 QLExpress源码 聊聊源码

Lock锁 精讲

伯阳

Java 多线程 lock lock锁

什么是TACACS?

Python 条件判断

赵开忠

Python 28天写作

Java 程序经验小结:避免使用float和double表示精确数据

后台技术汇

28天写作

专科出身,2年进入苏宁,5年跳槽阿里,论我是怎么快速晋升的?

云流

Java 学习 程序员 面试

[3/28]保障研发反应开发需求

俊毅

面试你也能收割Offer,Java程序员必会知识清单全在这份pdf文档里

Crud的程序员

Java 架构

技术er,你还特立独行坚持技术的优雅性么?

三石

28天写作 技术与业务

潘建伟团队再登Nature:建成全球首个集成量子通信网,全长4600公里

京东科技开发者

云计算

市值管理机器人系统开发|量化策略交易系统开发搭建

W13902449729

市值管理机器人系统开发 量化策略交易系统开发搭建

在CSDN的六载时光,由你来决定今年的博客之星

谙忆

脱不花:怎样成为高效学习的人 学习笔记

魔曦

SD-WAN:网络走向业务

JiangX

创业 投资 网络 28天写作 SD-WAN

Experience Never Gets Old

三只猫

28天写作

来玩一玩Linux常见命令!

程序员的时光

Linux 程序员 28天写作

创业失败启示录|校园微生活(故事篇 2)

青城

创业 28天写作 创业失败启示录 青城 人生故事

双非本硕,拿到字节offer后才发现师兄给的算法笔记有多重要

互联网架构师小马

Java 数据结构 面试 算法 面试求职

【计算机内功修炼】四:进程切换与线程切换的区别

码农的荒岛求生

线程 进程 进程线程区别

量化交易机器人系统开发|市值管理系统开发搭建

W13902449729

量化交易机器人系统开发 市值管理系统开发搭建

人生苦短,开发用云 | 如何优雅完成程序员的侠客梦?

阿里巴巴云原生

人工智能 阿里云 Serverless 程序员 云原生

「中国技术开放日·长沙站」现场直播

「中国技术开放日·长沙站」现场直播

范凯观点:Ruby社区应该去Rails化-InfoQ