怎样写ruby on rails 视频程序

网站已改版,请使用新地址访问:
ruby--shop 用 写的一个小程序, on rails,在《Web开发敏捷之道:应用 进行 Other systems 其他 238万源代码下载-
&文件名称: ruby--shop& & [
& & & & &&]
&&所属分类:
&&开发工具: Others
&&文件大小: 6387 KB
&&上传时间:
&&下载次数: 0
&&提 供 者:
&详细说明:用ruby写的一个小程序,ruby on rails,在《Web开发敏捷之道:应用Rails进行敏捷Web开发》上的例子上进行了一些改进,实现里一个简单的bookshop购书网站。-ruby on rails
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&depot\.gitignore&&.....\.svn\entries&&.....\....\format&&.....\....\pristine\00\00f03cbef319e217d330eaa78ed4f9a.svn-base&&.....\....\........\.2\0ba335b82f79d9ba31d8ed43b4db3e.svn-base&&.....\....\........\..\c8ec0157f3eacca10c151.svn-base&&.....\....\........\.3\df574bfeabe340be6720c.svn-base&&.....\....\........\.6\0685640fcca12d2bdcd513a066242.svn-base&&.....\....\........\.8\089b8b064e6d09ee39ca.svn-base&&.....\....\........\..\08c4d504e3d3d08b4e861e5c1f1d5a.svn-base&&.....\....\........\..\08fc711ac02ee28efd3d0b1cba16c1a.svn-base&&.....\....\........\.9\09a3ce9f5a894c5c.svn-base&&.....\....\........\.a\0adaeb0f4bbb61be1c.svn-base&&.....\....\........\..\0a68faeefdfda0e8e6f1.svn-base&&.....\....\........\.b\0bfac57ebbae308afbfb66ebbe9bf.svn-base&&.....\....\........\.c\0c6e15da25fd63833ccc3bf883a00f2f2b0038c4.svn-base&&.....\....\........\.d\0d9fa91fddd9f87a4bea06.svn-base&&.....\....\........\.e\0e308ae19b0d84d2f2ae.svn-base&&.....\....\........\..\0e430ca0a7e352addbf09.svn-base&&.....\....\........\..\0ec113f82dcd00d50c68.svn-base&&.....\....\........\..\0ed926fd005da5302d46dbf84d02e08f07a0d36c.svn-base&&.....\....\........\.f\0f00cefb53f52e28db.svn-base&&.....\....\........\10\10acaaf7f457fc59ccedab814f3cf9.svn-base&&.....\....\........\.1\a1abddac.svn-base&&.....\....\........\.2\128a97ebbafa20dd13c9d9b9d053641.svn-base&&.....\....\........\..\128bf160e745f9c29e670c7c016d.svn-base&&.....\....\........\..\12d7dda19fc76d267c9913614efc9db237c3574c.svn-base&&.....\....\........\..\12ff987f3a7a4b3d302abafac35221a.svn-base&&.....\....\........\.3\135dff6c93de5c2cf4ec.svn-base&&.....\....\........\.6\163cd4fbceec59e3f512d28cd9c2fb.svn-base&&.....\....\........\..\6d87aa1b1bfbd357f40cce457f3280.svn-base&&.....\....\........\..\167a17e0e4bcbc69fae1beda5bb272bf29be65da.svn-base&&.....\....\........\..\167cac37f0c1ba426ee0b03cf8ac32.svn-base&&.....\....\........\.7\17de2ef18dd2a4b6e9ba8d1b3e7b7.svn-base&&.....\....\........\.8\e921eaf5c9e311279ccedf.svn-base&&.....\....\........\..\b9dcb6b10aac9779addde.svn-base&&.....\....\........\..\f3e8c1e86e32fcfbc9f5.svn-base&&.....\....\........\..\d4d2fdbf55fbbc11dd2d42202aa84.svn-base&&.....\....\........\.a\1a7a356f831ec3cde0ad74e599199.svn-base&&.....\....\........\..\1a71b645b3f95f6a696a03f2e13b7b3fb55db6d4.svn-base&&.....\....\........\..\1aacccb9e33cad48de0.svn-base&&.....\....\........\..\1aafa6df04e142c74209fdeab131e0.svn-base&&.....\....\........\..\1ab25f6ae6dbac6e2d68eaa3a2cb.svn-base&&.....\....\........\..\1ac16f8c39b7fdf85.svn-base&&.....\....\........\.b\1b36cd0a6e4ac641c.svn-base&&.....\....\........\.c\1c868da4693aec2653aabea61fdc805e1f88bff9.svn-base&&.....\....\........\..\1ce14847dcfc6c9e66a1e2d7da4ff7d.svn-base&&.....\....\........\..\1cf2bdfcc29ece4c7f6998.svn-base&&.....\....\........\.e\1e56ee6caa3179aea8303db31f7a.svn-base&&.....\....\........\..\1e60c7c09c21ff27c9d.svn-base&&.....\....\........\..\1eafbd9c8f53f85d70cdc3de8742e7.svn-base&&.....\....\........\.f\1f5ffcdbc82cafccb27c3cf9b014d11ef3f9d6e6.svn-base&&.....\....\........\20\2b2d68e0a1ba5e175df64802e1df.svn-base&&.....\....\........\..\2080adb3e8e72f65c7bb0bb3c1ad56bd5f15d416.svn-base&&.....\....\........\.1\21f5b7f9a285c6b51c42d666a5165a.svn-base&&.....\....\........\.3\232b426b538c22c4d0d1a31f896cd4.svn-base&&.....\....\........\..\23d18e131f64ee5effc5b3.svn-base&&.....\....\........\..\23ee9edaed9d673e37b4.svn-base&&.....\....\........\.4\24d859ddacec32fb313ff7c45ce0279.svn-base&&.....\....\........\.6\260f880eabf4ee029ee.svn-base&&.....\....\........\.8\ebd4b2c6f869eb884e4.svn-base&&.....\....\........\..\28ef9e363c40c75e8ac65c0f76aac387f6e1f025.svn-base&&.....\....\........\.9\a4ffb78dae79b5b42ff4a9e406e0bf.svn-base&&.....\....\........\..\29f1c99aa03a2cbdb6e06c2df32c1.svn-base&&.....\....\........\..\29f841fd56c9eb032c978261bbc40f.svn-base&&.....\....\........\.a\2a81a0a68702c7efab5ea85165d1b.svn-base&&.....\....\........\.c\2c8f7da27ccf977cdbbfc1f18b7c2e.svn-base&&.....\....\........\..\2c9dfa93e90c239ae89ee8a2abce3d.svn-base&&.....\....\........\.d\2d65c841cdd3eafdce2.svn-base&&.....\....\........\.e\2e7ddcbc012e48e29ab8.svn-base&&.....\....\........\..\2ea7d6cfbaf85e04675.svn-base&&.....\....\........\..\2edc284eafe1722cbd457aab5ba615.svn-base&&.....\....\........\..\2efd72a394fefdb28a5f8.svn-base&&.....\....\........\.f\2fd825b079db6e451e0c611d1dd171a.svn-base&&.....\....\........\32\323d5c3f8a671d6fca3dedce15a6b8b.svn-base&&.....\....\........\.3\33ebeb2ea993f32abe525f04a787feaa.svn-base&&.....\....\........\.4\341bdaefc1aa2de4f3b3.svn-base&&.....\....\........\..\34bc358be18f8fdfbac73bc0fd0f0a.svn-base&&.....\....\........\.5\350ac9e47d403a87a97b38cf70ced.svn-base&&.....\....\........\..\35b23af5ade699ba18cf64c.svn-base&&.....\....\........\.6\ce8a14d00d3a62beb3.svn-base&&.....\....\........\..\36fd1a4c6f.svn-base&&.....\....\........\.8\383a7c47e7c294cdfac162b9449071.svn-base&&.....\....\........\..\389a040d972a1226edb2b890e129.svn-base&&.....\....\........\.9\885a6c5d93a0dd636c3ddfda9d103.svn-base&&.....\....\........\..\39772b21aac6fb0fea774b467a12bf.svn-base&&.....\....\........\..\39f68d4a2df221958.svn-base&&.....\....\........\.a\3ad1dc2ec94d9042aec9a2cd1ac40.svn-base&&.....\....\........\.b\3b5eb283b83e04d0d37ad8e0fd67.svn-base&&.....\....\........\..\3bb02f658b701dcaf0b.svn-base&&.....\....\........\..\3bbeb8f00fee9b587014.svn-base&&.....\....\........\.e\3e5c811e5c899c5e8be72f68fa9ca9a.svn-base&&.....\....\........\..\3ea4e17fa740e6cc90.svn-base&&.....\....\........\.f\3f32bbdd5cec9b44f.svn-base&&.....\....\........\..\3f8fedee833a18b172418bcad4b47d4.svn-base&&.....\....\........\40\40b611ace444ea40ee792a932ae4b2074deeb2ff.svn-base&&.....\....\........\.4\44c28ca6f3eeb4ee74969d6fadb0dabf91aead67.svn-base&&.....\....\........\.7\472aecb7643cfe335d29cc17be17554.svn-base&&.....\....\........\.8\992966eca8a9e44dc5.svn-base&&.....\....\........\..\f27eafd98e9c2de7cadaa279b45e3.svn-base
&输入关键字,在本站238万海量源码库中尽情搜索:如何提高 Ruby On Rails 的性能? - 文章 - 伯乐在线
& 如何提高 Ruby On Rails 的性能?
大家总是说 Rails 好慢啊,这差不多已经成为 Ruby and Rails 社区里的一个老生常谈的问题了。然而实际上这个说法并不正确。只要正确使用 Rails,把你的应用运行速度提升 10 倍并不困难。那么如何优化你的应用呢,我们来了解下面的内容。
1.1 优化一个 Rails app 的步骤
导致你的 Rails 应用变慢无非以下两个原因:
在不应该将 Ruby and Rails 作为首选的地方使用 Ruby and Rails。(用 Ruby and Rails 做了不擅长做的工作)
过度的消耗内存导致需要利用大量的时间进行垃圾回收。
Rails 是个令人愉快的框架,而且 Ruby 也是一个简洁而优雅的语言。但是如果它被滥用,那会相当的影响性能。有很多工作并不适合用 Ruby and Rails,你最好使用其它的工具,比如,数据库在大数据处理上优势明显,R 语言特别适合做统计学相关的工作。
内存问题是导致诸多 Ruby 应用变慢的首要原因。Rails 性能优化的 80-20 法则是这样的:80% 的提速是源自于对内存的优化,剩下的 20% 属于其它因素。为什么内存消耗如此重要呢?因为你分配的内存越多,Ruby GC(Ruby 的垃圾回收机制)需要做的工作也就越多。Rails 就已经占用了很大的内存了,而且平均每个应用刚刚启动后都要占用将近 100M 的内存。如果你不注意内存的控制,你的程序内存增长超过 1G 是很有可能的。需要回收这么多的内存,难怪程序执行的大部分时间都被 GC 占用了。
2 我们如何使一个 Rails 应用运行更快?
有三种方法可以让你的应用更快:扩容、缓存和代码优化。
扩容在如今很容易实现。基本上就是为你做这个的,而 Hirefire 则让这一过程更加的自动化。你可以在了解到更多有关自动扩容的内容。其它的托管环境提供了类似的解决方案。总之,可以的话你用它就是了。但是请牢记扩容并不是一颗改善性能的银弹。如果你的应用只需在 5 分钟内响应一个请求,扩容就没有什么用。还有就是用 Heroku + Hirefire 几乎很容易导致你的银行账户透支。我已经见识过 Hirefire 把我一个应用的扩容至 36 个实体,让我为此支付了 $3100。我立马就手动吧实例减容到了 2 个, 并且对代码进行了优化.
Rails 缓存也很容易实施。Rails 4 中的块缓存非常不错。 是有关缓存知识的优秀资料。另外还有一篇
也值得一读。如今设置 Memcached 也简单。不过同扩容相比,缓存并不能成为性能问题的终极解决方案。如果你的代码无法理想的运行,那么你将发现自己会把越来越多的资源耗费在缓存上,直到缓存再也不能带来速度的提升。
让你的 Rails 应用更快的唯一可靠的方式就是代码优化。在 Rails 的场景中这就是内存优化。而理所当然的是,如果你接受了我的建议,并且避免把 Rails 用于它的设计能力范围之外,你就会有更少的代码要优化。
2.1 避免内存密集型Rails特性
Rails 一些特性花费很多内存导致额外的垃圾收集。列表如下。
2.1.1 序列化程序
序列化程序是从数据库读取的字符串表现为 Ruby 数据类型的实用方法。
class Smth & ActiveRecord::Base
serialize :data, JSON
Smth.find(...).data
Smth.find(...).data = { ... }
But convenience comes with 3x memory overhead. If you store 100M in data column, expect to allocate 300M just to read it from the database.
class Smth & ActiveRecord::Base&&serialize :data, JSONendSmth.find(...).dataSmth.find(...).data = { ... }But convenience comes with 3x memory overhead. If you store 100M in data column, expect to allocate 300M just to read it from the database.
它要消耗更多的内存去有效的序列化,你自己看:
class Smth & ActiveRecord::Base
JSON.parse(read_attribute(:data))
def data=(value)
write_attribute(:data, value.to_json)
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
class Smth & ActiveRecord::Base&&def data&&&&JSON.parse(read_attribute(:data))&&end&&def data=(value)&&&&write_attribute(:data, value.to_json)&&endend
这将只要 2 倍的内存开销。有些人,包括我自己,看到 Rails 的 JSON 序列化程序内存泄漏,大约每个请求 10% 的数据量。我不明白这背后的原因。我也不知道是否有一个可复制的情况。如果你有经验,或者知道怎么减少内存,请告诉我。
2.1.2 活动记录
很容易与 ActiveRecord 操纵数据。但是 ActiveRecord 本质是包装了你的数据。如果你有 1g 的表数据,ActiveRecord 表示将要花费 2g,在某些情况下更多。是的,90% 的情况,你获得了额外的便利。但是有的时候你并不需要,比如,批量更新可以减少 ActiveRecord 开销。下面的代码,即不会实例化任何模型,也不会运行验证和回调。
Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
后面的场景它只是执行 SQL 更新语句。
update books
set author = 'David'
where title LIKE '%Rails%'
Another example is iteration over a large dataset. Sometimes you need only the data. No typecasting, no updates. This snippet just runs the query and avoids ActiveRecord altogether:
result = ActiveRecord::Base.execute 'select * from books'
result.each do |row|
# do something with row.values_at('col1', 'col2')
update books&&set author = 'David'&&where title LIKE '%Rails%'Another example is iteration over a large dataset. Sometimes you need only the data. No typecasting, no updates. This snippet just runs the query and avoids ActiveRecord altogether:result = ActiveRecord::Base.execute 'select * from books'result.each do |row|&&# do something with row.values_at('col1', 'col2')end
2.1.3 字符串回调
Rails 回调像之前/之后的保存,之前/之后的动作,以及大量的使用。但是你写的这种方式可能影响你的性能。这里有 3 种方式你可以写,比如:在保存之前回调:
before_save :update_status
before_save do |model|
model.update_status
before_save "self.update_status"
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba
&p&&&&&before_save :update_statusbefore_save do |model|&&model.update_statusendbefore_save "self.update_status"&/p&
前两种方式能够很好的运行,但是第三种不可以。为什么呢?因为执行 Rails 回调需要存储执行上下文(变量,常量,全局实例等等)就是在回调的时候。如果你的应用很大,你最终在内存里复制了大量的数据。因为回调在任何时候都可以执行,内存在你程序结束之前不可以回收。
有象征,回调在每个请求为我节省了 0.6 秒。
2.2 写更少的 Ruby
这是我最喜欢的一步。我的大学计算机科学类教授喜欢说,最好的代码是不存在的。有时候做好手头的任务需要其它的工具。最常用的是数据库。为什么呢?因为 Ruby 不善于处理大数据集。非常非常的糟糕。记住,Ruby 占用非常大的内存。所以举个例子,处理 1G 的数据你可能需要 3G 的或者更多的内存。它将要花费几十秒的时间去垃圾回收这 3G。好的数据库可以一秒处理这些数据。让我来举一些例子。
2.2.1 属性预加载
有时候反规范化模型的属性从另外一个数据库获取。比如,想象我们正在构建一个 TODO 列表,包括任务。每个任务可以有一个或者几个标签标记。规范化数据模型是这样的:
Tasks_Tags
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba
Tasks id nameTags id nameTasks_Tags tag_id task_id
加载任务以及它们的 Rails 标签,你会这样做:
tasks = Task.find(:all, :include =& :tags)
& 0.058 sec
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
tasks = Task.find(:all, :include =& :tags)&&&&& 0.058 sec
这段代码有问题,它为每个标签创建了对象,花费很多内存。可选择的解决方案,将标签在数据库预加载。
tasks = Task.select &&-END
select tags.name from tags inner join tasks_tags on (tags.id = tasks_tags.tag_id)
where tasks_tags.task_id=tasks.id
) as tag_names
tasks = Task.select &&-END&&&&&&*,&&&&&&array(&&&&&&&&select tags.name from tags inner join tasks_tags on (tags.id = tasks_tags.tag_id)&&&&&&&&where tasks_tags.task_id=tasks.id&&&&&&) as tag_names&&&&END
这只需要内存存储额外一列,有一个数组标签。难怪快 3 倍。
2.2.2 数据集合
我所说的数据集合任何代码去总结或者分析数据。这些操作可以简单的总结,或者一些更复杂的。以小组排名为例。假设我们有一个员工,部门,工资的数据集,我们要计算员工的工资在一个部门的排名。
SELECT * FROM
| empno | salary
-----------+-------+-------
personnel |
personnel |
12345678910
SELECT * FROM empsalary;&&depname&&| empno | salary-----------+-------+------- develop&& |&&&& 6 |&& 6000 develop&& |&&&& 7 |&& 4500 develop&& |&&&& 5 |&& 4200 personnel |&&&& 2 |&& 3900 personnel |&&&& 4 |&& 3500 sales&&&& |&&&& 1 |&& 5000 sales&&&& |&&&& 3 |&& 4800
你可以用 Ruby 计算排名:
salaries = Empsalary.all
salaries.sort_by! { |s| [s.depname, s.salary] }
key, counter = nil, nil
salaries.each do |s|
if s.depname != key
key, counter = s.depname, 0
counter += 1
s.rank = counter
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
salaries = Empsalary.allsalaries.sort_by! { |s| [s.depname, s.salary] }key, counter = nil, nilsalaries.each do |s| if s.depname != key&&key, counter = s.depname, 0 end counter += 1 s.rank = counterend
Empsalary 表里 100K 的数据程序在 4.02 秒内完成。替代 Postgres 查询,使用 window 函数做同样的工作在 1.1 秒内超过 4 倍。
SELECT depname, empno, salary, rank()
OVER (PARTITION BY depname ORDER BY salary DESC)
| empno | salary | rank
-----------+-------+--------+------
personnel |
personnel |
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
SELECT depname, empno, salary, rank()OVER (PARTITION BY depname ORDER BY salary DESC)FROM empsalary;&&depname&&| empno | salary | rank -----------+-------+--------+------ develop&& |&&&& 6 |&& 6000 |&&&&1 develop&& |&&&& 7 |&& 4500 |&&&&2 develop&& |&&&& 5 |&& 4200 |&&&&3 personnel |&&&& 2 |&& 3900 |&&&&1 personnel |&&&& 4 |&& 3500 |&&&&2 sales&&&& |&&&& 1 |&& 5000 |&&&&1 sales&&&& |&&&& 3 |&& 4800 |&&&&2
4 倍加速已经令人印象深刻,有时候你得到更多,到 20 倍。从我自己经验举个例子。我有一个三维 OLAP 多维数据集与 600k 数据行。我的程序做了切片和聚合。在 Ruby 中,它花费了 1G 的内存大约 90 秒完成。等价的 SQL 查询在 5 内完成。
2.3 优化 Unicorn
如果你正在使用Unicorn,那么以下的优化技巧将会适用。Unicorn 是 Rails 框架中最快的 web 服务器。但是你仍然可以让它更运行得快一点。
2.3.1 预载入 App 应用
Unicorn 可以在创建新的 worker 进程前,预载入 Rails 应用。这样有两个好处。第一,主线程可以通过写入时复制的友好GC机制(Ruby 2.0以上),共享内存的数据。操作系统会透明的复制这些数据,以防被worker修改。第二,预载入减少了worker进程启动的时间。Rails worker进程重启是很常见的(稍后将进一步阐述),所以worker重启的速度越快,我们就可以得到更好的性能。
若需要开启应用的预载入,只需要在unicorn的配置文件中添加一行:
preload_app true
<div class="crayon-num" data-line="crayon-598fba
preload_app true
2.3.2 在 Request 请求间的 GC
请谨记,GC 的处理时间最大会占到应用时间的50%。这个还不是唯一的问题。GC 通常是不可预知的,并且会在你不想它运行的时候触发运行。那么,你该怎么处理?
首先我们会想到,如果完全禁用 GC 会怎么样?这个似乎是个很糟糕的想法。你的应用很可能很快就占满 1G 的内存,而你还未能及时发现。如果你服务器还同时运行着几个 worker,那么你的应用将很快会出现内存不足,即使你的应用是在自托管的服务器。更不用说只有 512M 内存限制的 Heroku。
其实我们有更好的办法。那么如果我们无法回避GC,我们可以尝试让GC运行的时间点尽量的确定,并且在闲时运行。例如,在两个request之间,运行GC。这个很容易通过配置Unicorn实现。
对于Ruby 2.1以前的版本,有一个unicorn模块叫做OobGC:
require 'unicorn/oob_gc'
use(Unicorn::OobGC, 1)
# "1" 表示"强制GC在1个request后运行"
require 'unicorn/oob_gc'&&&&use(Unicorn::OobGC, 1)&& # "1" 表示"强制GC在1个request后运行"
对于Ruby 2.1及以后的版本,最好使用gctools(/tmm1/gctools):
require 'gctools/oobgc'
use(GC::OOB::UnicornMiddleware)
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
require 'gctools/oobgc'use(GC::OOB::UnicornMiddleware)
但在request之间运行GC也有一些注意事项。最重要的是,这种优化技术是可感知的。也就是说,用户会明显感觉到性能的提升。但是服务器需要做更多的工作。不同于在需要时才运行GC,这种技术需要服务器频繁的运行GC. 所以,你要确定你的服务器有足够的资源来运行GC,并且在其他worker正在运行GC的过程中,有足够的worker来处理用户的请求。
2.4 有限的增长
我已经给你展示了一些应用会占用1G内存的例子。如果你的内存是足够的,那么占用这么一大块内存并不是个大问题。但是Ruby可能不会把这块内存返还给操作系统。接下来让我来阐述一下为什么。
Ruby通过两个堆来分配内存。所有Ruby的对象在存储在Ruby自己的堆当中。每个对象占用40字节(64位操作系统中)。当对象需要更多内存的时候,它就会在操作系统的堆中分配内存。当对象被垃圾回收并释放后,被占用的操作系统中的堆的内存将会返还给操作系统,但是Ruby自有的堆当中占用的内存只会简单的标记为free可用,并不会返还给操作系统。
这意味着,Ruby的堆只会增加不会减少。想象一下,如果你从数据库读取了1百万行记录,每行10个列。那么你需要至少分配1千万个对象来存储这些数据。通常Ruby worker在启动后占用100M内存。为了适应这么多数据,worker需要额外增加400M的内存(1千万个对象,每个对象占用40个字节)。即使这些对象最后被收回,这个worker仍然使用着500M的内存。
这里需要声明, Ruby GC可以减少这个堆的大小。但是我在实战中还没发现有这个功能。因为在生产环境中,触发堆减少的条件很少会出现。
如果你的worker只能增长,最明显的解决办法就是每当它的内存占用太多的时候,就重启该worker。某些托管的服务会这么做,例如Heroku。让我们来看看其他方法来实现这个功能。
2.4.1 内部内存控制
Trust in God, but lock your car 相信上帝,但别忘了锁车。(寓意:大部分外国人都有宗教信仰,相信上帝是万能的,但是日常生活中,谁能指望上帝能帮助自己呢。信仰是信仰,但是有困难的时候 还是要靠自己。)。有两个途径可以让你的应用实现自我内存限制。我管他们做,Kind(友好)和hard(强制).
Kind 友好内存限制是在每个请求后强制内存大小。如果worker占用的内存过大,那么该worker就会结束,并且unicorn会创建一个新的worker。这就是为什么我管它做“kind”。它不会导致你的应用中断。
获取进程的内存大小,使用 RSS 度量在 Linux 和 MacOS 或者
在 windows 上。我来展示下在 Unicorn 配置文件里怎么实现这个限制:
class Unicorn::HttpServer
KIND_MEMORY_LIMIT_RSS = 150 #MB
alias process_client_orig process_client
undef_method :process_client
def process_client(client)
process_client_orig(client)
rss = `ps -o rss= -p #{Process.pid}`.chomp.to_i / 1024
exit if rss & KIND_MEMORY_LIMIT_RSS
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba
class Unicorn::HttpServer KIND_MEMORY_LIMIT_RSS = 150 #MB alias process_client_orig process_client undef_method :process_client def process_client(client)&&process_client_orig(client)&&rss = `ps -o rss= -p #{Process.pid}`.chomp.to_i / 1024&&exit if rss & KIND_MEMORY_LIMIT_RSS endend
硬盘内存限制是通过询问操作系统去杀你的工作进程,如果它增长很多。在 Unix 上你可以叫 setrlimit 去设置 RSSx 限制。据我所知,这种只在 Linux 上有效。MacOS 实现被打破了。我会感激任何新的信息。
这个片段来自 Unicorn 硬盘限制的配置文件:
after_fork do |server, worker|
worker.set_memory_limits
class Unicorn::Worker
HARD_MEMORY_LIMIT_RSS = 600 #MB
def set_memory_limits
Process.setrlimit(Process::RLIMIT_AS, HARD_MEMORY_LIMIT * 1024 * 1024)
<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba<div class="crayon-num crayon-striped-num" data-line="crayon-598fba<div class="crayon-num" data-line="crayon-598fba
after_fork do |server, worker|&&worker.set_memory_limitsendclass Unicorn::Worker&&HARD_MEMORY_LIMIT_RSS = 600 #MB&&def set_memory_limits&&&&Process.setrlimit(Process::RLIMIT_AS, HARD_MEMORY_LIMIT * 1024 * 1024)&&endend
2.4.2 外部内存控制
自动控制没有从偶尔的 OMM(内存不足)拯救你。通常你应该设置一些外部工具。在 Heroku 上,没有必要因为它们有自己的监控。但是如果你是自托管,使用 ,是一个很好的主意,或者其它的监视解决方案。
2.5 优化 Ruby GC
在某些情况下,你可以调整 Ruby GC 来改善其性能。我想说,这些 GC 调优变得越来越不重要,Ruby 2.1 的默认设置,后来已经对大多数人有利。
GC 好的调优你需要知道它是怎么工作的。这是一个独立的主题,不属于这编文章。要了解更多,彻底读读 Sam Saffron 的
这篇文章。在我即将到来的 Ruby 性能的一书,我挖到更深的 Ruby GC 细节。订阅这个,当我完成这本书的 beta 版本会给你发送一份邮件。
我的建议是最好不要改变 GC 的设置,除非你明确知道你想要做什么,而且有足够的理论知识知道如何提高性能。对于使用 Ruby 2.1 或之后的版本的用户,这点尤为重要。
我知道只有一种场合 GC 优化确实能带来性能的提升。那就是,当你要一次过载入大量的数据。你可以通过改变如下的环境变量来达到减少GC运行的频率:RUBY_GC_HEAP_GROWTH_FACTOR,RUBY_GC_MALLOC_LIMIT,RUBY_GC_MALLOC_LIMIT_MAX,RUBY_GC_OLDMALLOC_LIMIT,和 RUBY_GC_OLDMALLOC_LIMIT。
请注意,这些变量只适用于 Ruby 2.1 及之后的版本。对于 2.1 之前的版本,可能缺少某一个变量,或者变量不是使用这个名字。
RUBY_GC_HEAP_GROWTH_FACTOR 默认值 1.8,它用于当 Ruby 的堆没有足够的空间来分配内存的时候,每次应该增加多少。当你需要使用大量的对象的时候,你希望堆的内存空间增长的快一点。在这种场合,你需要增加该因子的大小。
内存限制是用于定义当你需要向操作系统的堆申请空间的时候,GC 被触发的频率。Ruby 2.1 及之后的版本,默认的限额为:
New generation malloc limit RUBY_GC_MALLOC_LIMIT 16M
Maximum new generation malloc limit RUBY_GC_MALLOC_LIMIT_MAX 32M
Old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT 16M
Maximum old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT_MAX 128M
New generation malloc limit RUBY_GC_MALLOC_LIMIT 16MMaximum new generation malloc limit RUBY_GC_MALLOC_LIMIT_MAX 32MOld generation malloc limit RUBY_GC_OLDMALLOC_LIMIT 16MMaximum old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT_MAX 128M
让我简要的说明一下这些值的意义。通过设置以上的值,每次新对象分配 16M 到 32M 之间,并且旧对象每占用 16M 到 128M 之间的时候 (&#8220;旧对象&#8221; 的意思是,该对象至少被垃圾回收调用过一次), Ruby 将运行 GC。Ruby 会根据你的内存模式,动态的调整当前的限额值。
所以,当你只有少数几个对象,却占用了大量的内存(例如读取一个很大的文件到字符串对象中),你可以增加该限额,以减少 GC 被触发的频率。请记住,要同时增加 4 个限额值,而且最好是该默认值的倍数。
我的建议是可能和其他人的建议不一样。对我可能合适,但对于你却未必。这些文章将介绍,哪些对
适用,而哪些对
2.6 Profile
有时候,这些建议未必就是通用。你需要弄清楚你的问题。这时候,你就要使用 profiler。 是每个 Ruby 用户都会使用的工具。
想知道更多关于 profiling 的知识, 请阅读
和我的关于在 Rails 中 。还有一些也许有点过时的关于 memory profiling 的建议.
2.7 编写性能测试用例
最后,提高 Rails 性能的技巧中,虽然不是最重要的,就是确认应用的性能不会因你修改了代码而导致性能再次下降。Rails 3.x 有一个附带了一个
的功能。对于 Rails 4, 你可以通过
使用相同的框架。
3 总结感言
对于一篇文章中,对于如何提高 Ruby 和 Rails 的性能,要面面俱到,确实不可能。所以,在这之后,我会通过写一本书来总结我的经验。如果你觉得我的建议有用,请 ,当我准备好了该书的预览版之后,将会第一时间通知你。现在,让我们一起来动手,让 Rails 应用跑得更快一些吧!
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
&#8211; 好的话题、有启发的回复、值得信赖的圈子
&#8211; 分享和发现有价值的内容与观点
&#8211; 为IT单身男女服务的征婚传播平台
&#8211; 优秀的工具资源导航
&#8211; 翻译传播优秀的外文文章
&#8211; 国内外的精选文章
&#8211; UI,网页,交互和用户体验
&#8211; 专注iOS技术分享
&#8211; 专注Android技术分享
&#8211; JavaScript, HTML5, CSS
&#8211; 专注Java技术分享
&#8211; 专注Python技术分享
& 2017 伯乐在线}

我要回帖

更多关于 ruby on rails 指南 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信