Ruby on Rails的可扩展性/性能?[关闭]


71

我已经使用PHP一段时间了,并且已经与CodeIgniter很好地结合使用,这是一个很好的框架。我开始一个新的个人项目,上次我考虑使用什么(PHP与ROR),因为我听说ROR遇到了可伸缩性问题,尤其是在阅读了Twitter开发人员对它的评价之后,我才使用PHP。可伸缩性仍然是ROR的问题还是对其进行了改进?

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

Answers:


161

为了扩大Ryan Doherty的答案,...

我在日常工作中使用静态类型的语言(.NET / C#),同时使用Ruby。在我今天的工作之前,我是一家红宝石开发公司的首席程序员,为纽约时报联合组织服务。在那之前,我还从事过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)

地狱,全部尝试!我倾向于同意以上答案,即尽早担心优化不是您应该或不应该选择框架的原因,但是我不同意这是他们唯一的答案。

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

对不起这部小说,但我去过那里又遇到了性能问题。它可以被克服。所以不要让那吓到你。


3
非常感谢,RichH :)只是觉得这是一个很深的话题,在此之前我听了太多的答案,似乎似乎不可能。但事实并非如此:)
Keith Hanson,

27

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

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


16

使用将为您的项目提供最大成功机会的技术进行开发-快速开发,轻松调试,轻松部署,良好的工具,内在地了解它(除非要学习一种新语言),等等。

如果您每个月获得数以千万计的唯一身份,则您随时可以聘请几个人,并根据需要重写另一种技术。

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


14

首先,将Ruby与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 Server(或充其量为SQL Master / Multiple Slave Slave设置),不再适用于非常大的站点。

如果您拥有数十亿用户,例如Google,Twitter和Facebook,那么分布式架构可能会更好。如果您确实想无限扩展应用程序,请使用某种廉价的商品硬件作为基础,将应用程序划分为一组服务,保持每个组件或服务本身可扩展(将每个组件设计为可扩展服务),并进行调整应用程序的体系结构。然后,您将需要合适的可伸缩数据存储(例如NoSQL数据库和分布式哈希表(DHT)),您将需要复杂的map-reduce算法来与它们配合使用,并且必须处理SOA,外部服务和消息传递。PHP和Rails都没有在这里提供任何魔术。


感谢您的评论。
Xdrone

6

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


作为记录,如果您正在运行一个内部系统,则它可能会使用大量资源,有时会访问包含数十亿个注册表的表。RoR显然不是正确的工具。
magallanes

5

花点时间看一下Twitter员工必须解决的问题,然后问问自己,您的应用是否需要扩展到该级别。

然后无论如何都要在Rails中构建它,因为您知道它是有道理的。如果您使用Twitter级别的卷,那么您将很乐于考虑性能优化选项。至少您将以一种不错的语言来应用它们!


2

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


2

只是想向Keith Hanson关于1 + N问题的聪明点添加一些更多信息,他指出:

DataMapper是解决上述问题的绝佳方法(它没有1 + N问题),但是更好的方法是动动脑筋,停止执行诸如此类的查询:D当您需要原始性能时,大多数ORM图层不会轻易处理极其自定义的查询,因此您不妨手工编写它们。

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

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


1

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

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

您需要某种强类型的语法,这些语法要求我这次要加载这些子项和grandchilren。即,类似:

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


这不是范围吗?
Nakilon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.