Ruby on Rails 的可伸缩性/性能?

我已经使用 PHP 一段时间了,并且在 CodeIgniter 中使用得很好,这是一个很棒的框架。我正在开始一个新的个人项目,上次我在考虑使用什么(PHP vs ROR) ,我使用 PHP 是因为我听说 ROR 存在可伸缩性问题,特别是在读了 Twitter 开发人员对它的看法之后。可伸缩性在 ROR 中仍然是一个问题吗? 还是已经对其进行了改进?

我想学习一门新的语言,ROR 看起来很有趣。PHP 完成了这项工作,但是每个人都知道它的语法和组织是丑陋的,感觉就像一个大黑客。

44410 次浏览

RoR 的分解之处在于,除非您进入了 Alexa 的前100名,否则不会有任何可伸缩性问题。除非你能够挤出 Phusion、 Passyor 或者 Mongrel,否则你将会在共享主机的稳定性方面遇到更多的问题。

RoR 已经被许多大型网站使用,但是与 任何语言或框架一样,它需要一个良好的架构(db 伸缩、缓存、调优等)来扩展到大量用户。

对 RoR 做了一些小的改动,使其更容易扩展,但是不要指望它能为您神奇地扩展。每个网站都有不同的缩放问题,所以你必须做一些工作,使其规模。

开发能够给你的项目带来最大成功机会的技术——快速开发,易于调试,易于部署,好的工具,你对它了如指掌(除非你的目的是学习一门新的语言) ,等等。

如果你一个月有几千万的独特性,你总是可以雇佣几个人,如果你需要的话,可以用不同的技术来重写..。

... 你将在 缓存台上进行 耙子(对不起,忍不住了! !)

花点时间看看 Twitter 用户必须处理的问题,然后问问自己,你的应用是否需要扩展到那个级别。

然后无论如何在 Rails 中构建它,因为您知道它是有意义的。如果你达到了 Twitter 级别的卷,那么你将处于考虑性能优化选项的愉快位置。至少你可以用一种漂亮的语言来应用它们!

为了进一步阐述 Ryan Doherty 的回答..。

我的日常工作使用静态类型语言(。NET/C #) ,以及 Ruby 作为副产品。在我现在的工作之前,我是一家红宝石开发公司的首席程序员,为纽约时报联合服务公司工作。在那之前,我也在 PHP 工作(虽然很久很久以前)。

我这么说只是为了说明这一点: 我亲身经历过 Rail (以及更普遍的 Ruby)性能问题,以及其他一些替代方案。正如 Ryan 所说,你不会让它自动为你伸缩。它需要工作和巨大的耐心找到你的瓶颈。

我们从其他人甚至我们自己那里看到的大多数性能问题都是在 ORM 层中处理性能缓慢的查询。我们从 Rails/ActiveRecord 到 Rails/DataMapper,最后到 Merb/DM,每次迭代都因为底层框架而提高了速度。

缓存为性能带来了惊人的好处。不幸的是,我们无法缓存数据。我们的缓存最多每五分钟就会失效一次。我们网站的几乎每一个部分都是动态的。因此,如果你做不到这一点,也许你可以从我们的经验中学习。

我们最终必须对数据库索引进行严格的微调,确保我们的查询不会做出非常愚蠢的事情,确保我们不会执行超过绝对必要的查询,等等。当我说“非常愚蠢的事情”,我的意思是1 + N 查询问题..。

# 1 query
Dog.find(:all).each do |dog|
# N queries
dog.owner.siblings.each do |sibling|
# N queries per above N query!
sibling.pets.each do |pet|
# Do something here
end
end
end

DataMapper 是处理上述问题的一种非常好的方法(这里是 没有1 + N 的问题) ,但是更好的方法是动动脑子,停止这样的查询。当您需要原始性能时,大多数 ORM 层不能轻松处理极其自定义的查询,所以您不妨手工编写它们。

We also did common sense things. We bought a beefy server for our growing database, and moved it off onto it's own dedicated box. We also had to do TONS of processing and data importing constantly. We moved our processing off onto 它的 own box as well. We also stopped loading our entire freaking stack just for our data import utilities. We tastefully loaded only what we absolutely needed (thus reducing memory overhead!).

如果你还不能确定... ... 一般来说,当涉及到 ruby/ails/merb 时,你必须对 出去进行缩放,抛出硬件来解决这个问题。但是最终,硬件是便宜的; 尽管这不能成为伪造代码的借口!

即使有这些困难,我个人也绝不会在另一个框架中启动项目,如果我能帮助它的话。我爱上了这门语言,并且每天都在不断地学习它。这是我从 C # 中得不到的,尽管 C # 更快。

我也喜欢开源工具,开始使用这种语言的低成本,仅仅是获得一些东西的低成本,并试图看看它是否有市场,所有这些都是在一种经常可以优雅和美丽的语言中工作..。

最后,当涉及到选择你的框架时,这完全取决于你想要日复一日地生活、呼吸、吃饭和睡觉。如果你喜欢微软的思维方式,去吧。NET.如果您想要开放源码,但仍然想要结构,尝试 Java。如果您希望拥有一种动态语言,并且仍然比 Ruby 具有更多的结构,那么可以尝试 python。如果你想要优雅,试试 Ruby (我开玩笑的,我开玩笑的... ... 还有很多其他优雅的语言符合要求。而不是试图挑起一场口水战。)

见鬼,全都试试!我倾向于同意上面的答案,即早期担心优化不是您应该或不应该选择框架的原因,但我不同意这是他们唯一的答案。

所以简而言之,的确存在你必须克服的困难,但是语言的优雅,即我的意思,远远超过了这些缺点。

抱歉我写了这本小说,但我一直有表现问题。必须克服。别被吓跑了。

你不能比较 PHP 和 ROR,PHP 是 Ruby 的脚本语言,而 Rails 是 CakePHP 的框架。
我强烈建议您使用 Rails,因为您将拥有一个严格的 以 MVC 模式组织应用程序,而且这是一个满足您的可伸缩性需求的 必须的。(使用 PHP 时,您必须自己关注项目组织)。
但是关于可伸缩性,Rails 不仅仅是 MVC: 例如,你可以开始使用数据库开发你的应用程序,不费吹灰之力就可以改变它(在大多数情况下) ,所以我们可以声明一个 Rails 应用程序是(几乎) 独立于数据库,因为它是 ORM (允许你避免数据库查询) ,你可以做很多其他的事情。(请看这个视频)

首先,将 Rails 与 Symfony,CodeIgniter 或 CakePHP,因为 RubyonRails 是一个完整的 Web 应用程序 与 PHP 或 PHP 框架相比,Rails 应用程序提供了 它们的优点是体积小,干净,易读。 PHP 是完美的 个人主页(原意为“个人主页”) , 而 Rails 是一个完整的 MVC 框架,可以用来构建大型 工地。

Ruby on Rails 没有是一个比同类 PHP 框架更大的可伸缩性问题。 如果您只有一个适中的数字,那么 Rails 和 PHP 都可以很好地扩展 用户(10,000-100,000) ,他们操作类似数量的对象。 对于几千个用户来说,一个经典的整体架构 有一点 M & M (Memcached 和 MySQL) ,你也可以 M & M 架构使用一个 MySQL 服务器来处理数百万个对象 处理写操作和 Memcached 来处理高读负载 存储模式,一个使用规范化关系表的 SQL 服务器 (或者最好是一个 SQL 主/多读从设置) ,不再工作 非常大的网站。

如果你有数十亿像谷歌、 Twitter 和 Facebook 这样的用户,那么 可能分布式架构会更好。如果你真的想 无限制地扩展你的应用程序,使用某种廉价的商品硬件 作为基础,将应用程序划分为一组服务,保持 每个组件或服务本身可伸缩(将每个组件设计为 (一个可伸缩的服务) ,并使体系结构适应您的应用程序。 然后,您将需要适当的可伸缩数据存储,如 NoSQL 数据库 和分布式散列表(DHT) ,则需要复杂的 map-reduce 算法与它们一起工作,你将不得不处理 SOA,外部 PHP 和 Rails 都没有提供灵丹妙药。

只是想给 Keith Hanson 关于1 + N 问题的聪明观点补充一些信息,他说:

DataMapper 是处理上述问题的一个很好的方法(它不存在1 + N 的问题) ,但是更好的方法是使用您的大脑并停止这样的查询。当您需要原始性能时,大多数 ORM 层不能轻松处理极其自定义的查询,所以您不妨手工编写它们。

Doctrine 是最流行的用于 PHP 的 ORM 之一。它通过提供一种称为 Doctrine Query Language (DQL)的语言来解决 ORM 固有的1 + N 复杂性问题。这允许您使用现有的模型关系编写类似 SQL 的语句。例如:

$q = Doctrine_Query::Create()
->select(*)
->from(ModelA m)
->leftJoin(m.ModelB)
->execute()

我从这个线程中得到的印象是,ROR 的可伸缩性问题主要归结于 ORM 在加载子对象方面的混乱——即上面提到的“1 + N”问题。在上面的例子中,Ryan 给了狗和主人:

Dog.find(:all).each do |dog|
#N queries
dog.owner.siblings.each do |sibling|
#N queries per above N query!!
sibling.pets.each do |pet|
#Do something here
end
end
end

实际上,您可以编写一个 sql 语句来获取所有数据,还可以将这些数据“缝合”到 Dog 中。老板。兄弟姐妹。自定义对象的宠物对象层次结构。但是,是否有人可以编写一个自动执行此操作的 ORM,以便上面的示例只需要一次数据库往返和一条 SQL 语句,而不是可能有数百条?绝对的。只需要将这些表连接到一个数据集中,然后使用一些逻辑将其拼接起来。让这种逻辑具有通用性有点棘手,因为它可以处理任何一组对象,但不能处理世界末日。最后,表和对象只在三个类别中的一个(1:1,1: many,many: many)中相互关联。只是没人造过那个 ORM。

您需要一种语法来预先告诉系统您想为这个 特别查询加载哪些子级。您可以使用 LinqToSql (C #)的“热切”加载来实现这一点,这并不是 ROR 的一部分,但是即使这样会导致数据库的一个往返过程,它仍然是数百个独立的 SQL 语句,就像它当前的设置方式一样。它实际上更多的是关于 ORM 的历史。他们只是走上了一条错误的道路,在我看来从未真正恢复过来。“延迟加载”是大多数 ORM 的默认行为,即每提到一个子对象就会引起另一次往返,这太疯狂了。然后使用“急切”加载——预先加载子元素,这是在 LinqToSql 之外的所有我知道的东西中静态设置的——即子元素总是加载特定的对象——就好像你在加载 Dog 集合时总是需要加载相同的子元素一样。

您需要某种强类型的语法来说明这一次我想加载这些子子孙孙。比如:

Dog.Owners.Include()
Dog.Owners.Siblings.Include()
Dog.Owners.Siblings.Pets.Include()

然后你就可以发出这样的命令:

Dog.find(:all).each do |dog|

ORM 系统将知道它需要连接哪些表,然后将结果数据拼接到 OM 层次结构中。的确,你可以用硬件来解决当前的问题,这是我通常赞成的,但是 ORM (即 Hibernate,Entity Framework,Ruby ActiveRecord)没有理由不写得更好。硬件实际上并不能帮助您摆脱8个往返、100个 SQL 语句的查询,这些查询本应该是一个往返和一个 SQL 语句。