Ruby on Rails 的可扩展性/性能? [关闭]
Posted
技术标签:
【中文标题】Ruby on Rails 的可扩展性/性能? [关闭]【英文标题】:Ruby on Rails scalability/performance? [closed] 【发布时间】:2010-10-04 22:59:56 【问题描述】:我使用 php 已经有一段时间了,并且在 CodeIgniter 中很好地使用了它,这是一个很棒的框架。我正在开始一个新的个人项目,上次我在考虑使用什么(PHP 与 ROR)我使用 PHP,因为我听说 ROR 存在可伸缩性问题,尤其是在阅读了 Twitter 开发人员对此的评价之后。可扩展性在 ROR 中是否仍然是一个问题,或者是否已对其进行了改进?
我想学习一门新语言,ROR 似乎很有趣。 PHP 完成了工作,但众所周知,它的语法和组织结构很糟糕,感觉就像一个大黑客。
【问题讨论】:
【参考方案1】:稍微扩展一下 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)
见鬼,都试试吧!我倾向于同意上面的答案,即早期担心优化并不是你应该或不应该选择框架的原因,但我不同意这是他们唯一的答案。
所以简而言之,是的,你必须克服一些困难,但是语言的优雅,恕我直言,远远超过了这些缺点。
对于这部小说,我感到很抱歉,但我来回遇到了性能问题。 可以克服。所以不要让这把你吓跑。
【讨论】:
非常感谢,RichH :) 只是觉得这是一个如此深奥的话题,而在此之前我听到了太多的答案,这似乎是不可能的。它只是不是:)【参考方案2】:RoR 被用于许多大型网站,但与 任何 语言或框架一样,它需要良好的架构(数据库扩展、缓存、调优等)才能扩展到大量用户.
对 RoR 进行了一些小改动,使其更易于扩展,但不要指望它会为您神奇地扩展。每个网站都有不同的扩展问题,因此您必须付出一些努力才能使其扩展。
【讨论】:
【参考方案3】:开发能够为您的项目带来最大成功机会的技术 - 快速开发、易于调试、易于部署、良好的工具,您对它了如指掌(除非重点是学习一门新语言)等。
如果您每月获得数以千万计的唯一身份,您可以随时雇用几个人,并根据需要使用不同的技术重写...
...您将在 缓存中rake(抱歉 - 无法抗拒!!)
【讨论】:
【参考方案4】:首先,将 Rails 与 Symfony、CodeIgniter 或 CakePHP,因为 Ruby on Rails 是一个完整的 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 Master/Multiple Read Slave 设置),不再有效 适用于非常大的网站。
如果您拥有像 Google、Twitter 和 Facebook 这样的数十亿用户,那么 可能分布式架构会更好。如果你真的想 无限制地扩展您的应用程序,使用某种廉价的商品硬件 作为基础,将您的应用程序划分为一组服务,保持 每个组件或服务本身可扩展(将每个组件设计为 可扩展的服务),并使架构适应您的应用程序。 然后,您将需要合适的可扩展数据存储,例如 NoSQL 数据库 和分布式哈希表 (DHT),您将需要复杂的 map-reduce 与它们一起工作的算法,您将不得不处理 SOA、外部 服务和消息传递。 PHP 和 Rails 都没有提供灵丹妙药。
【讨论】:
感谢您的评论。【参考方案5】:RoR 的关键在于,除非您进入 Alexa 的前 100 名,否则您不会遇到任何可扩展性问题。除非您可以挤出 Phusion、Passenger 或 Mongrel,否则您将在共享主机上遇到更多稳定性问题。
【讨论】:
作为记录,如果您运行的是内部系统,那么它可能会使用大量资源,有时会访问具有数十亿注册表的表。 RoR 显然不是适合它的工具。【参考方案6】:花点时间看看 Twitter 人员必须处理的问题,然后问问自己,您的应用是否需要扩展到该级别。
然后无论如何都要在 Rails 中构建它,因为你知道它是有意义的。如果您达到 Twitter 级别的音量,那么您将乐于考虑性能优化选项。至少你会用一种很好的语言来应用它们!
【讨论】:
【参考方案7】:你不能比较 PHP 和 ROR,PHP 是 Ruby 的脚本语言,Rails 是 CakePHP 的框架。 也就是说,我强烈建议您使用 Rails,因为您将拥有一个严格以 MVC 模式组织的应用程序,而这是必须满足您的可伸缩性要求。 (使用 PHP 您必须自己处理项目组织)。 但是关于可扩展性,Rails 不仅仅是 MVC:例如,您可以开始使用数据库开发您的应用程序,在路上毫不费力地更改它(在大多数情况下),因此我们可以声明 Rails 应用程序是(几乎)数据库独立,因为它是 ORM(允许您避免数据库查询),您可以做很多其他事情。 (看看这个视频http://www.youtube.com/watch?v=p5EIrSM8dCA)
【讨论】:
【参考方案8】:只是想在 Keith Hanson 关于 1 + N 问题的聪明点中添加更多信息,他说:
DataMapper 是处理上述问题的好方法(它没有 1 + N 问题),但更好的方法是动用你的大脑并停止做这样的查询:D 当你需要原始性能时,大多数的 ORM 层将无法轻松处理极其自定义的查询,因此您不妨手写它们。
Doctrine 是 PHP 最流行的 ORM 之一。它通过提供一种称为 Doctrine Query Language (DQL) 的语言来解决 ORM 固有的 1 + N 复杂性问题。这允许您编写使用现有模型关系的类似 SQL 的语句。例如
$q = Doctrine_Query::Create() ->选择(*) ->从(模型A m) ->leftJoin(m.ModelB) ->执行()
【讨论】:
【参考方案9】:我从这个线程得到的印象是,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 语句。
【讨论】:
scopes 不是关于这个的吗?以上是关于Ruby on Rails 的可扩展性/性能? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何以可扩展的方式部署 [Ruby on Rails] 站点?
ruby Ruby on Rails指南:主动支持核心扩展 - http://guides.rubyonrails.org/active_support_core_extensions.html
何时在 Ruby on Rails 中使用 memoization