Ruby on Rails 可扩展性/性能?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/503684/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby on Rails scalability/performance?
提问by ryeguy
I have used PHP for awhile now and have used it well with CodeIgniter, which is a great framework. I am starting on a new personal project and last time I was considering what to use (PHP vs ROR) I used PHP because of the scalability problems I heard ROR had, especially after reading what the Twitter devs had to say about it. Is scalability still an issue in ROR or has there been improvements to it?
我已经使用 PHP 一段时间了,并且很好地与 CodeIgniter 一起使用,这是一个很棒的框架。我正在开始一个新的个人项目,上次我考虑使用什么(PHP 与 ROR)时,我使用了 PHP,因为我听说 ROR 存在可扩展性问题,尤其是在阅读了 Twitter 开发人员对此的评论之后。可扩展性是否仍然是 ROR 中的一个问题,或者是否有改进?
I would like to learn a new language, and ROR seems interesting. PHP gets the job done but as everyone knows its syntax and organization are fugly and it feels like one big hack.
我想学习一门新语言,ROR 似乎很有趣。PHP 完成了这项工作,但众所周知,它的语法和组织很糟糕,感觉就像是一次大黑客。
回答by Keith Hanson
To expand on Ryan Doherty's answer a bit...
稍微扩展一下 Ryan Doherty 的回答......
I work in a statically typed language for my day job (.NET/C#), as well as Ruby as a side thing. Prior to my current day job, I was the lead programmer for a ruby development firm doing work for the New York Times Syndication service. Before that, I worked in PHP as well (though long, long ago).
我在日常工作中使用静态类型语言 (.NET/C#),同时使用 Ruby 作为副业。在我现在的日常工作之前,我是一家 ruby 开发公司的首席程序员,为纽约时报辛迪加服务工作。在此之前,我也在 PHP 中工作过(虽然很久很久以前)。
I say that simply to say this: I've experienced rails (and more generally ruby) performance problems first hand, as well as a few other alternatives. As Ryan says, you aren't going to have it automatically scale for you. It takes work and immense amounts of patience to find your bottlenecks.
我这么说只是为了说:我亲身经历过 Rails(更普遍的是 ruby)性能问题,以及其他一些替代方案。正如瑞安所说,你不会让它自动为你扩展。找到瓶颈需要工作和巨大的耐心。
A large majority of the performance issues we saw from others and even ourselves were dealing with slow performing queries in our ORM layer. We went from Rails/ActiveRecord to Rails/DataMapper and finally to Merb/DM, each iteration getting more speed simply because of the underlying frameworks.
我们从其他人那里看到的大部分性能问题,甚至我们自己都在处理 ORM 层中执行缓慢的查询。我们从 Rails/ActiveRecord 到 Rails/DataMapper,最后到 Merb/DM,每次迭代都因为底层框架而获得更快的速度。
Caching does amazing wonders for performance. Unfortunately, we couldn't cache our data. Our cache would effectively be invalidated every five minutes at most. Nearly every single bit of our site was dynamic. So if/when you can't do that, perhaps you can learn from our experience.
缓存为性能创造了惊人的奇迹。不幸的是,我们无法缓存我们的数据。我们的缓存最多每五分钟就会失效一次。我们网站的几乎每一点都是动态的。因此,如果/当您不能这样做时,也许您可以从我们的经验中学习。
We had to end up seriously fine tuning our database indexes, making sure our queries weren't doing very stupid things, making sure we weren't executing more queries than was absolutely necessary, etc. When I say "very stupid things", I mean the 1 + N query problem...
我们最终不得不认真地微调我们的数据库索引,确保我们的查询没有做非常愚蠢的事情,确保我们没有执行超过绝对必要的查询,等等。当我说“非常愚蠢的事情”时,我意思是 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 is an excellent way to handle the above problem (there are no 1 + N problems with it), but an even better way is to use your brain and stop doing queries like that :D When you need raw performance, most of the ORM layers won't easily handle extremely custom queries, so you might as well hand write them.
DataMapper 是处理上述问题的极好方法(它没有 1 + N 问题),但更好的方法是动脑筋并停止执行这样的查询 :D 当您需要原始性能时,大多数 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 itsown 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!).
我们也做了常识性的事情。我们为不断增长的数据库购买了一个强大的服务器,并将其移到了自己的专用盒子上。我们还必须不断进行大量的处理和数据导入。我们也将我们的处理转移到了自己的盒子上。我们还停止为我们的数据导入实用程序加载整个该死的堆栈。我们只加载了我们绝对需要的东西(从而减少了内存开销!)。
If you can't tell already... generally, when it comes to ruby/rails/merb, you have to scale out, throwing hardware at the problem. But in the end, hardware is cheap; though that's no excuse for shoddy code! :D
如果您还不能确定……一般来说,当涉及到 ruby/rails/merb 时,您必须向外扩展,将硬件放在问题上。但归根结底,硬件便宜;虽然这不是劣质代码的借口!:D
And even with these difficulties, I personally would never start projects in another framework if I can help it. I'm in love with the language, and continually learn more about it every day. That's something that I don't get from C#, though C# is faster.
即使有这些困难,如果我能帮上忙,我个人也永远不会在另一个框架中开始项目。我爱上了这门语言,并且每天都在不断地了解它。这是我无法从 C# 中获得的东西,尽管 C# 更快。
I also enjoy the open source tools, the low cost to start working in the language, the low cost to just get something out there and try to see if it's marketable, all the while working in a language that often times can be elegant and beautiful...
我也喜欢开源工具,开始使用该语言的低成本,将一些东西放在那里并尝试看看它是否有市场的低成本,同时使用一种通常可以优雅和美丽的语言工作...
In the end, it's all about what you want to live, breathe, eat, and sleep in day in and day out when it comes to choosing your framework. If you like Microsoft's way of thinking, go .NET. If you want open source but still want structure, try Java. If you want to have a dynamic language and still have a bit more structure than ruby, try python. And if you want elegance, try Ruby (I kid, I kid... there are many other elegant languages that fit the bill. Not trying to start a flame war :D)
最后,在选择框架时,这完全取决于您日复一日地想要生活、呼吸、饮食和睡眠。如果您喜欢 Microsoft 的思维方式,请选择 .NET。如果您想要开源但仍然想要结构,请尝试 Java。如果你想拥有一门动态语言并且仍然比 ruby 有更多的结构,请尝试 python。如果你想要优雅,试试 Ruby(我开玩笑,我开玩笑……还有许多其他优雅的语言符合要求。不要试图开始一场火焰War:D)
Hell, try them all! I tend to agree with the answers above that worrying about optimizations early isn't the reason you should or shouldn't pick a framework, but I disagree that this is their only answer.
见鬼,都试试!我倾向于同意上面的答案,即早期担心优化并不是您应该或不应该选择框架的原因,但我不同意这是他们唯一的答案。
So in short, yes there are difficulties you have to overcome, but the elegance of the language, imho, far outweighs those shortcomings.
所以简而言之,是的,您必须克服一些困难,但是语言的优雅,恕我直言,远远超过了这些缺点。
Sorry for the novel, but I've been there and back with performance issues. It canbe overcome. So don't let that scare you off.
很抱歉这本小说,但我一直在那里,因为性能问题而回来。它可以被克服。所以不要让它吓到你。
回答by Ryan Doherty
RoR is being used with lots of huge websites, but as with anylanguage or framework, it takes a good architecture (db scaling, caching, tuning, etc) to scale to large numbers of users.
RoR 被用于许多大型网站,但与任何语言或框架一样,它需要良好的架构(数据库扩展、缓存、调整等)才能扩展到大量用户。
There's been a few minor changes to RoR to make it easier to scale, but don't expect it to scale magically for you. Every website has different scaling issues, so you'll have to put in some work to make it scale.
对 RoR 进行了一些小的更改以使其更易于扩展,但不要指望它会为您神奇地扩展。每个网站都有不同的扩展问题,因此您必须进行一些工作以使其扩展。
回答by RichH
Develop in the technology that is going to give your project the best chance of success - quick to develop in, easy debugging, easy deployment, good tools, you know it inside out (unless the point is to learn a new language), etc.
使用能够为您的项目带来最大成功机会的技术进行开发 - 快速开发、易于调试、易于部署、良好的工具、您完全了解它(除非重点是学习一门新语言)等。
If you get tens of million of uniques a month you can always hire in a couple of people and rewrite in a different technology if you need to as ...
如果您每月获得数千万个唯一身份,您可以随时雇用几个人,并在需要时使用不同的技术重写...
... you'll be rake-ing in the cache(sorry - couldn't resist!!)
......你会在缓存中耙 -ing (对不起 - 无法抗拒!!)
回答by 0x4a6f4672
First of all, it would perhaps make more sense to compare Rails to Symfony, CodeIgniter or CakePHP, since Ruby on Rails is a complete web application framework. Compared to PHP or PHP frameworks, Rails applications offer the advantages that they are small, clean, and readable. PHP is perfect for small, personal pages (originally it stood for "Personal Home Page"), while Rails is a full MVC framwork which can be used to build large sites.
首先,将 Rails 与 Symfony、CodeIgniter 或 CakePHP 进行比较可能更有意义,因为 Ruby on Rails 是一个完整的 Web 应用程序框架。与 PHP 或 PHP 框架相比,Rails 应用程序具有体积小、干净且可读的优点。PHP 非常适合小型的个人页面(最初它代表“个人主页”),而 Rails 是一个完整的 MVC 框架,可用于构建大型站点。
Ruby on Rails has nota larger scalability issue than comparable PHP frameworks. Both Rails and PHP will scale well if you have only a moderate number of users (10,000-100,000) which operate on a similar number of objects. For a few thousand users a classic monolithic architecture will be sufficient. With a bit of M&M (Memcached and MySQL) you can also handle millions of objects. The M&M architecture uses a MySQL server to handle writes and Memcached to handle high read loads. The traditional storage pattern, a single SQL server using normalized relational tables (or at best a SQL Master/Multiple Read Slave setup), no longer works for very large sites.
Ruby on Rails没有比可比的 PHP 框架更大的可扩展性问题。如果您只有中等数量的用户(10,000-100,000)对相似数量的对象进行操作,那么 Rails 和 PHP 都可以很好地扩展。对于几千用户来说,经典的单体架构就足够了。借助一点 M&M(Memcached 和 MySQL),您还可以处理数百万个对象。M&M 架构使用 MySQL 服务器来处理写入,使用 Memcached 来处理高读取负载。传统的存储模式,使用规范化关系表的单个 SQL 服务器(或者最好是 SQL 主/多读从设置),不再适用于非常大的站点。
If you have billions of users like Google, Twitter and Facebook, then probably a distributed architecture will be better. If you really want to scale your application without limit, use some kind of cheap commodity hardware as a foundation, divide your application into a set of services, keep each component or service scalable itself (design every component as a scalable service), and adapt the architecture to your application. Then you will need suitable scalable datastores like NoSQL databases and distributed hash tables (DHTs), you will need sophisticated map-reduce algorithms to work with them, you will have to deal with SOA, external services, and messaging. Neither PHP nor Rails offer a magic bullet here.
如果您拥有像 Google、Twitter 和 Facebook 这样的数十亿用户,那么分布式架构可能会更好。如果你真的想无限扩展你的应用程序,使用某种廉价的商品硬件作为基础,将你的应用程序划分为一组服务,保持每个组件或服务本身的可扩展性(将每个组件设计为可扩展的服务),并适应应用程序的架构。然后,您将需要合适的可扩展数据存储,如 NoSQL 数据库和分布式哈希表 (DHT),您将需要复杂的 map-reduce 算法来使用它们,您将不得不处理 SOA、外部服务和消息传递。PHP 和 Rails 都没有在这里提供灵丹妙药。
回答by phresus
What is breaks down to with RoR is that unless you're in Alexa's top 100, you will not have any scalability problems. You'll have more issues with stability on shared hosting unless you can squeeze Phusion, Passenger, or Mongrel out.
RoR 的问题在于,除非您进入 Alexa 的前 100 名,否则您不会遇到任何可扩展性问题。除非您可以挤出 Phusion、Passenger 或 Mongrel,否则您将在共享主机上遇到更多稳定性问题。
回答by Mike Woodhouse
Take a little while to look at the problems the Twitter people had to deal with, then ask yourself if your app is going to need to scale to that level.
花点时间看看 Twitter 用户必须处理的问题,然后问问自己您的应用是否需要扩展到那个级别。
Then build it in Rails anyway, because you know it makes sense. If you get to Twitter-level volumes then you'll be in the happy position of considering performance optimisaton options. At least you'll be applying them in a nice language!
无论如何,然后在 Rails 中构建它,因为你知道它是有道理的。如果您达到 Twitter 级别的数量,那么您将处于考虑性能优化选项的快乐位置。至少你会用一种很好的语言来应用它们!
回答by Aree Cohen
Just wanted to add some more info to Keith Hanson's smart point about 1 + N problem where he states:
只是想为 Keith Hanson 关于 1 + N 问题的聪明点添加更多信息,他指出:
DataMapper is an excellent way to handle the above problem (there are no 1 + N problems with it), but an even better way is to use your brain and stop doing queries like that :D When you need raw performance, most of the ORM layers won't easily handle extremely custom queries, so you might as well hand write them.
DataMapper 是处理上述问题的极好方法(它没有 1 + N 问题),但更好的方法是动脑筋并停止执行这样的查询 :D 当您需要原始性能时,大多数 ORM图层不会轻易处理极其自定义的查询,因此您不妨手写它们。
Doctrine is one of the most popular ORM's for PHP. It addresses this 1 + N complexity problem intrinsic to ORMs by providing a language called Doctrine Query Language (DQL). This allows you to write SQL like statements that use your existing model relationships. e.g
Doctrine 是最流行的 PHP ORM 之一。它通过提供一种称为 Doctrine Query Language (DQL) 的语言来解决 ORM 固有的 1 + N 复杂性问题。这允许您编写使用现有模型关系的类似 SQL 的语句。例如
$q = Doctrine_Query::Create() ->select(*) ->from(ModelA m) ->leftJoin(m.ModelB) ->execute()
$q = Doctrine_Query::Create() ->select(*) ->from(ModelA m) ->leftJoin(m.ModelB) ->execute()
回答by Joe
You can't compare PHP and ROR, PHP is a scripting language as Ruby, and Rails is a framework as CakePHP.
Stated that, I strongly suggest you Rails, because you will have an application strictly organized in MVC pattern, and this is a MUSTfor your scalability requirement. (Using PHP you had to take care about the project organization on your own).
But for what about scalability, Rails it's not just MVC: For instance, you can start to develop your application with a database, changing it on road without any effort (in the most part of cases), so we can state that a Rails application is (almost) database indipendentbecause it's ORM (that allow you to avoid database query), you can do a lot of other stuff.
(take a look to this video http://www.youtube.com/watch?v=p5EIrSM8dCA)
您无法比较 PHP 和 ROR,PHP 是一种脚本语言,如 Ruby,Rails 是一种框架,如 CakePHP。
声明,我强烈建议你使用 Rails,因为你将有一个严格按照 MVC 模式组织的应用程序,这对于你的可扩展性要求是必须的。(使用 PHP 您必须自己负责项目组织)。
但是对于可扩展性,Rails 不仅仅是 MVC:例如,您可以开始使用数据库开发您的应用程序,在路上毫不费力地更改它(在大多数情况下),因此我们可以声明 Rails 应用程序是(几乎)数据库独立的,因为它是 ORM(允许你避免数据库查询),你可以做很多其他的事情。
(看看这个视频http://www.youtube.com/watch?v=p5EIrSM8dCA)
回答by Jeff
I'm getting the impression from this thread that the scalability issues of ROR come down primarily to the mess that ORMs are in with regard to loading child objects - ie the '1+N' problem mentioned above. In the above example that Ryan gave with dogs and owners:
我从这个线程中得到的印象是,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
You could actually write a single sql statement to get all that data, and you could also 'stitch' that data up into the Dog.Owner.Siblings.Pets object heirarchy of your custom-written objects. But could someone write an ORM that did that automatically, so that the above example would incur a single round-trip to the DB and a single SQL Statement, instead of potentially hundreds? Totally. Just join those tables into one dataset, then do some logic to stitch it up. It's a bit tricky to make that logic generic so it can handle any set of objects but not the end of the world. In the end, tables and objects only relate to each other in one of three categories (1:1, 1:many, many:many). It's just that no one ever built that ORM.
您实际上可以编写一个 sql 语句来获取所有数据,并且您还可以将这些数据“缝合”到您自定义编写的对象的 Dog.Owner.Siblings.Pets 对象层次结构中。但是有人可以编写一个自动执行此操作的 ORM,以便上面的示例将导致一次到 DB 的往返和一条 SQL 语句,而不是可能数百个?完全。只需将这些表加入一个数据集,然后做一些逻辑来拼接它。使该逻辑通用有点棘手,因此它可以处理任何对象集,但不能处理世界末日。最后,表和对象仅在三个类别之一(1:1、1:many、many:many)中相互关联。只是没有人构建过那个 ORM。
You need a syntax that tells the system upfront what children you want to load for this particularquery. You can sort of do this with the 'eager' loading of LinqToSql (C#), which is not a part of ROR, but even though that results in one round trip to the DB, it's still hundreds of separate SQL statements the way it has currently been set up. It's really more about the history of ORMs. They just got started down the wrong path with that and never really recovered in my opnion. 'Lazy loading' is the default behavior of most ORMs, ie incurring another round trip for every mention of a child object, which is crazy. Then with 'eager' loading - loading the children upfront, that is set up statically in everything I am aware outside of LinqToSql - ie which children always load with certain objects - as if you would always need the same children loaded when you loaded a collection of Dogs.
您需要一种语法来预先告诉系统您要为此特定加载哪些子项询问。您可以通过 LinqToSql (C#) 的“热切”加载来完成此操作,这不是 ROR 的一部分,但即使这会导致一次到数据库的往返,它仍然是数百个单独的 SQL 语句目前已经成立。这实际上更多是关于 ORM 的历史。他们刚刚开始走上错误的道路,在我看来从未真正恢复过来。“延迟加载”是大多数 ORM 的默认行为,即每次提及子对象都会导致另一次往返,这很疯狂。然后使用“急切”加载 - 预先加载子项,这是在 LinqToSql 之外我知道的所有内容中静态设置的 - 即哪些子项总是加载某些对象 - 就好像在加载集合时总是需要加载相同的子项的狗。
You need some kind of strongly-typed syntax saying that this time I want to load these children and grandchilren. Ie, something like:
你需要某种强类型语法,说这次我要加载这些孩子和孙子。即,类似于:
Dog.Owners.Include()
Dog.Owners.Siblings.Include()
Dog.Owners.Siblings.Pets.Include()
then you could issue this command:
那么你可以发出这个命令:
Dog.find(:all).each do |dog|
The ORM system would know what tables it needs to join, then stitch up the resulting data into the OM heirarchy. It's true that you can throw hardware at the current problem, which I'm generally in favor of, but it's no reason the ORM (ie Hibernate, Entity Framework, Ruby ActiveRecord) shouldn't just be better written. Hardware really doesn't bail you out of an 8 round-trip, 100-SQL statement query that should have been one round trip and one SQL statement.
ORM 系统会知道它需要加入哪些表,然后将结果数据拼接到 OM 层次结构中。确实,您可以将硬件用于当前的问题,我通常是赞成的,但是 ORM(即 Hibernate、Entity Framework、Ruby ActiveRecord)没有理由不应该只是更好地编写。硬件确实不会让您摆脱 8 次往返、100 条 SQL 语句查询,而本应为一次往返和一条 SQL 语句。

