71

我已经使用 PHP 有一段时间了,并且已经很好地将它与 CodeIgniter 一起使用,这是一个很棒的框架。我正在开始一个新的个人项目,上次我在考虑使用什么(PHP 与 ROR)我使用 PHP,因为我听说 ROR 存在可伸缩性问题,尤其是在阅读了 Twitter 开发人员对此的评价之后。可扩展性在 ROR 中是否仍然是一个问题,或者是否已经对其进行了改进?

我想学习一门新语言,ROR 似乎很有趣。PHP 完成了工作,但众所周知,它的语法和组织结构很糟糕,感觉就像一个大黑客。

4

9 回答 9

161

为了扩展 Ryan Doherty 的答案......

我在日常工作中使用静态类型语言(.NET/C#),同时将 Ruby 作为副业。在我目前的日常工作之前,我是一家 Ruby 开发公司的首席程序员,为 New York Times Syndication 服务工作。在此之前,我也在 PHP 中工作过(虽然很久很久以前)。

我这么说只是为了这样说:我亲身经历过 Rails(以及更普遍的 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 问题),但更好的方法是动用你的大脑并停止做这样的查询:D 当你需要原始性能时,大多数 ORM图层不会轻易处理非常自定义的查询,因此您不妨手写它们。

我们也做了常识性的事情。我们为我们不断增长的数据库购买了一个强大的服务器,并将它移到它自己的专用盒子上。我们还必须不断进行大量的处理和数据导入。我们也将我们的处理转移到自己的盒子上。我们还停止为我们的数据导入实用程序加载整个该死的堆栈。我们只加载了我们绝对需要的内容(从而减少了内存开销!)。

如果你还不能说...一般来说,当涉及到 ruby​​/rails/merb 时,你必须向外扩展,将硬件扔到问题上。但归根结底,硬件很便宜;虽然这不是伪劣代码的借口!:D

即使有这些困难,如果我能提供帮助,我个人永远不会在另一个框架中启动项目。我爱上了这种语言,并且每天都在不断地了解它。这是我从 C# 中得不到的东西,尽管 C# 更快。

我也喜欢开源工具,开始使用该语言的低成本,从那里得到一些东西并尝试看看它是否有市场的低成本,同时使用一种通常可以优雅和美丽的语言工作...

最后,在选择框架时,一切都取决于您日复一日地生活、呼吸、饮食和睡眠。如果您喜欢 Microsoft 的思维方式,请选择 .NET。如果您想要开源但仍然想要结构,请尝试 Java。如果您想拥有一种动态语言并且仍然具有比 ruby​​ 更多的结构,请尝试使用 python。如果你想要优雅,试试 Ruby(我小子,我小子......还有许多其他优雅的语言符合要求。不要试图引发一场激烈的战争:D)

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

所以简而言之,是的,你必须克服一些困难,但是语言的优雅,恕我直言,远远超过了这些缺点。

很抱歉这本小说,但我一直因为性能问题而反复出现。它是可以克服的。所以不要让这把你吓跑。

于 2009-02-02T20:14:08.460 回答
27

RoR 被用于许多大型网站,但与任何语言或框架一样,它需要良好的架构(数据库扩展、缓存、调整等)才能扩展到大量用户。

RoR 进行了一些小的更改,使其更易于扩展,但不要指望它会为您神奇地扩展。每个网站都有不同的扩展问题,因此您必须投入一些工作才能使其扩展。

于 2009-02-02T16:07:39.770 回答
16

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

如果您每月获得数以千万计的独特性,您可以随时雇用几个人并在需要时用不同的技术重写...

......你会在缓存中- ing (对不起 - 无法抗拒!)

于 2009-02-02T16:17:37.627 回答
14

首先,将 Rails 与 Symfony、CodeIgniter 或 CakePHP 进行比较可能更有意义,因为 Ruby on Rails 是一个完整的 Web 应用程序框架。与 PHP 或 PHP 框架相比,Rails 应用程序具有体积小、干净且易读的优点。PHP 非常适合小型个人页面(最初它代表“个人主页”),而 Rails 是一个完整的 MVC 框架,可用于构建大型站点。

Ruby on Rails没有比同类 PHP 框架更大的可扩展性问题。如果您只有中等数量的用户(10,000-100,000)操作类似数量的对象,Rails 和 PHP 都可以很好地扩展。对于几千个用户来说,一个经典的单体架构就足够了。通过一点 M&M(Memcached 和 MySQL),您还可以处理数百万个对象。M&M 架构使用 MySQL 服务器处理写入,使用 Memcached 处理高读取负载。传统的存储模式,即使用规范化关系表(或充其量是 SQL Master/Multiple Read Slave 设置)的单个 SQL 服务器,不再适用于非常大的站点。

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

于 2011-07-18T09:05:31.797 回答
6

使用 RoR 的原因在于,除非您进入 Alexa 的前 100 名,否则您不会遇到任何可扩展性问题。除非您可以挤出 Phusion、Passenger 或 Mongrel,否则您将在共享主机上遇到更多稳定性问题。

于 2009-02-02T16:01:20.077 回答
5

花点时间看看 Twitter 人员必须处理的问题,然后问问自己,您的应用程序是否需要扩展到该级别。

然后无论如何都要在 Rails 中构建它,因为你知道它是有意义的。如果您达到 Twitter 级别的音量,那么您将乐于考虑性能优化选项。至少你会用一种很好的语言来应用它们!

于 2009-02-02T20:02:56.953 回答
2

你不能比较 PHP 和 ROR,PHP 是一种脚本语言,如 Ruby,Rails 是一个框架,如 CakePHP。
说,我强烈建议您使用 Rails,因为您将拥有一个严格按照 MVC 模式组织的应用程序,这对于您的可伸缩性要求是必须的。(使用 PHP 您必须自己处理项目组织)。
但是关于可扩展性,Rails 不仅仅是 MVC:例如,您可以开始使用数据库开发您的应用程序,在路上毫不费力地更改它(在大多数情况下),因此我们可以声明 Rails 应用程序(几乎)是数据库独立的,因为它是 ORM(允许您避免数据库查询),您可以做很多其他的事情。
(看看这个视频http://www.youtube.com/watch?v=p5EIrSM8dCA

于 2011-06-17T14:20:28.717 回答
2

只是想在 Keith Hanson 关于 1 + N 问题的聪明点中添加更多信息,他说:

DataMapper 是处理上述问题的好方法(它没有 1 + N 问题),但更好的方法是动用你的大脑并停止做这样的查询:D 当你需要原始性能时,大多数 ORM图层不会轻易处理非常自定义的查询,因此您不妨手写它们。

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

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

于 2012-02-16T10:45:41.500 回答
1

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

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.Owner.Siblings.Pets 对象层次结构中。但是有人可以编写一个自动执行此操作的 ORM,以便上面的示例会导致到数据库的一次往返和一个 SQL 语句,而不是可能的数百个?完全。只需将这些表连接到一个数据集中,然后执行一些逻辑将其拼接起来。使该逻辑具有通用性有点棘手,因此它可以处理任何对象集,但不能处理世界末日。最后,表和对象仅在三个类别之一(1:1、1:many、many:many)中相互关联。只是没有人构建过那个 ORM。

您需要一种语法来预先告诉系统您要为此特定加载哪些子级询问。您可以通过“急切”加载 LinqToSql (C#) 来做到这一点,这不是 ROR 的一部分,但即使这会导致到数据库的一次往返,它仍然是数百个单独的 SQL 语句。目前已经成立。它实际上更多地是关于 ORM 的历史。他们只是开始走上错误的道路,并且在我看来从未真正恢复过。“延迟加载”是大多数 ORM 的默认行为,即每次提及子对象都会引发另一次往返,这很疯狂。然后使用“急切”加载 - 预先加载孩子,这是在我知道的 LinqToSql 之外的所有内容中静态设置的 - 即哪些孩子总是加载某些对象 - 就好像你在加载集合时总是需要加载相同的孩子的狗。

您需要某种强类型语法来说明这次我要加载这些子孙。即,类似:

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 语句。

于 2014-06-24T21:39:48.220 回答