使用Rails一段时间后,你会开始对如何改进它吹毛求疵。这是关于如何提高Rails性能(哪怕是一点点)的系列文章中的第一篇。
我将重点介绍一些宝石,这些宝石在某些情况下可以大大加快Rails的小部分速度,比如html转义、String#blank? 和JSON工具。
基准测试方法
方法论是一个很强烈的词,因为它只是在控制台中运行了几次wrk ,但我在这里不是在寻找圣杯,只是想得到一个原始的想法。
我从老的apache ab转到wrk 。
wrk是一个现代的HTTP基准测试工具,
在单个多核CPU上运行时
能够产生巨大的
负载。
wrk -t10 -c10 -d10s http://localhost:3000
这个基准运行10秒,使用10个线程,并保持50个HTTP连接开放,也就是说,这应该足够了。只要记得在你的实际应用上进行基准测试,就能看到真正的改进。
escape_utils gem
通过可爱的escape_utilsgem,可以更快地实现所有的html转义。为了在Rails中使用它,我们需要添加一个初始化器来修补东西。
begin
require 'escape_utils/html/rack' # to patch Rack::Utils
require 'escape_utils/html/erb' # to patch ERB::Util
require 'escape_utils/html/cgi' # to patch CGI
require 'escape_utils/html/haml' # to patch Haml::Helpers
rescue LoadError
Rails.logger.info 'Escape_utils is not in the gemfile'
end
测试它的逻辑:
def escape_utils
@escape_me = <<-HTML
<body class="application articles_show">
<!-- Responsive navigation
==================================================== -->
<div class="container">
<nav id="nav">
<ul>
<li><a href="/"><i class="ss-standard ss-home"></i>home</a></li>
<li><a href="/home/about"><i class="ss-standard ss-info"></i>about</a></li>
<li><a href="/contact"><i class="ss-standard ss-ellipsischat"></i>contact</a></li>
<li><a href="/home/projects"><i class="ss-standard ss-fork"></i>projects</a></li>
<li><a href="/tags"><i class="ss-standard ss-tag"></i>tags</a></li>
<li><a href="/articles?query=code"><i class="ss-standard ss-search"></i>search</a></li>
</ul>
</nav>
<a href="#" class="ss-standard ss-list" id="nav-toggle" aria-hidden="true"></a>
HTML
render inline: "Hello world <%= @escape_me %>"
end
使用标准Rails:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 35.40ms 3.55ms 64.70ms 91.98%
Req/Sec 142.19 11.68 164.00 83.12%
2837 requests in 10.00s, 4.92MB read
Requests/sec: 283.61
Transfer/sec: 503.34KB
使用 escape_utils gem:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 34.06ms 3.89ms 63.92ms 89.10%
Req/Sec 148.65 13.36 180.00 75.94%
2960 requests in 10.00s, 5.46MB read
Requests/sec: 295.98
Transfer/sec: 558.72KB
fast_blank gem
如果你觉得blank方法太慢,那就不要再说了,试试fast_blankgem!
只需在你的Gemfile中添加gem 'fast_blank' ,它就能很好地加速本文所述的String#blank? 方法 。为了测试,我只是添加了这段代码。
fast_blank是一个简单的扩展,它提供了一个快速实现active support的string#blank?
def fast_blank_test
n = 1000
strings = [
"",
"\r\n\r\n ",
"this is a test",
" this is a longer test",
" this is a longer test
this is a longer test
this is a longer test
this is a longer test
this is a longer test"
]
Benchmark.bmbm do |x|
strings.each do |s|
x.report("Fast Blank #{s.length} :") do
n.times { s.blank? }
end
end
end
render nothing: true
end
使用标准的Rails:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.40s 207.72ms 1.58s 92.68%
Req/Sec 3.10 2.11 6.00 53.66%
69 requests in 10.01s, 33.08KB read
Requests/sec: 6.90
Transfer/sec: 3.31KB
使用fast_blank gem:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.33s 179.56ms 1.41s 93.33%
Req/Sec 3.07 0.80 4.00 40.00%
72 requests in 10.00s, 34.52KB read
Requests/sec: 7.20
Transfer/sec: 3.45KB
oj gem
# oj gem
gem 'oj'
gem 'oj_mimic_json' # we need this for Rails 4.1.x
测试逻辑很简单,只要将所有文章序列化为JSON即可:
class SidechannelsController < ApplicationController
def oj
render json: Article.all
end
end
使用标准的Rails序列化器:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 108.37ms 5.12ms 134.90ms 83.33%
Req/Sec 45.76 3.60 55.00 57.69%
922 requests in 10.00s, 57.41MB read
Requests/sec: 92.17
Transfer/sec: 5.74MB
使用oj gem:
Running 10s test @ http://localhost:3000/sidechannels/bench
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 78.06ms 4.43ms 92.83ms 81.31%
Req/Sec 63.64 5.33 71.00 64.49%
1277 requests in 10.00s, 79.83MB read
Requests/sec: 127.65
Transfer/sec: 7.98MB
使用jemalloc
好吧,这并不是一个真正的gem,如果你想深入了解它,那么请查看我的gist 。在最初的测试中,它不会产生太多的性能提升,至少对我的使用情况是这样。
注意:它将在某个时候被默认包含在Ruby中
更新:请尝试kzk的jemallocgem
gem install jemalloc
je -v rails s
挖掘你的Rails应用
不要害怕,使用MiniProfiler与Sam Saffron的超强FlameGraphs。
结论
根据你的应用所做的事情,你可能想在你的Gemfile中添加其中的一些宝石,我通常会把它们全部添加进去,以备不时之需(不过在这样做之前,你可能想检查你的内存使用情况,并有一个完整的测试套件)。
ojgem对于基于Rails的JSON API来说是非常好的,你可以放弃视图,只需使用表示器或你选择的模式进行序列化。