通過添加一些gems來(lái)提升Rails應(yīng)用的性能
使用Rails一段時(shí)間之后,你可能就會(huì)開始吹毛求疵的想要提高它性能。這是一系列文章中第一次考慮如何提高(即使微不足道的)Rails的性能。
我將會(huì)關(guān)注在一些gem的提速上面,在某些情況下,可能是一小部分的Rails,如html轉(zhuǎn)義,String.blank?和JSON工具類。
基準(zhǔn)原則
原則,對(duì)于僅僅在控制臺(tái)wrk運(yùn)行幾次來(lái)講,是一個(gè)與其過強(qiáng)的詞語(yǔ),但是我這里不是來(lái)尋找“圣杯”的,而是提供一些初始的想法。
我將從舊的apache ab切換到wrk。
wrk是現(xiàn)代的 HTTP 基準(zhǔn)工具,當(dāng)在一個(gè)單一的多核 CPU 上運(yùn)行時(shí),能夠產(chǎn)生巨大的負(fù)載。
- wrk -t10 -c10 -d10s http://localhost:3000
 
這條指令運(yùn)行基準(zhǔn)問題10s,使用10個(gè)線程,并且保持打開50個(gè)HTTP鏈接,也就是說(shuō),這樣就足夠了。記得將這些基準(zhǔn)測(cè)試在你實(shí)際的應(yīng)用中跑一下,看一下實(shí)際上的性能提高有多少。
escape_utils gem
通過可愛的escape_utils gem可以加快HTML的轉(zhuǎn)義。為了使其能夠在Rails中使用,需要添加一個(gè)初始值設(shè)定來(lái)解決:
- 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
 
對(duì)該邏輯進(jìn)行測(cè)試的用例:
- 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
 
使用標(biāo)準(zhǔn)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?方法太慢?不用多說(shuō),試一下fast_blank gem!
僅需要在你的Gemfile中添加gem 'fast_blank',這應(yīng)該就可以非常漂亮的提高像這篇文章中提到的String.black?方法的速度。為了測(cè)試,我僅添加下倆代碼:
fast_blank是一個(gè)簡(jiǎn)單的擴(kuò)展,提供了一個(gè)支持String.blank?功能的快速實(shí)現(xiàn)。
- 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
 
#p#
使用標(biāo)準(zhǔn)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
 
這個(gè)測(cè)試用例非常簡(jiǎn)單,僅僅將所有的article序列化為JSON格式:
- class SidechannelsController < ApplicationController
 - def oj
 - render json: Article.all
 - end
 - end
 
使用標(biāo)準(zhǔn)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
好吧,這其實(shí)不是一個(gè)真正的gem,如果你想深入探究它,可以看我的這篇文章。在初始測(cè)試時(shí),jemalloc并沒有產(chǎn)生太多性能的提升,至少對(duì)我使用的測(cè)試用例是這樣的。
提示:某些情況下,可能會(huì)默認(rèn)包含在Ruby中。
更新:請(qǐng)一定嘗試一下kzk的jemalloc gem:
- gem install jemalloc
 - je -v rails s
 
深入探究你的Rails應(yīng)用
不要擔(dān)心,去用一下Sam Saffron的帶有非常棒的FlameGraphs的MiniProfiler吧!
結(jié)語(yǔ)
鑒于你的應(yīng)用要做什么,你可能想為你的Gemfile添加上述的一些gem。通常我會(huì)把他們都添加上,當(dāng)然是出于一個(gè)好的估量(你可能會(huì)想檢查你的RAM利用率,然后在添加之前,進(jìn)行一個(gè)完整的測(cè)試)。
oj gem基于JSON API,對(duì)Rails來(lái)說(shuō)是非常不錯(cuò)的,使用oj gem,你可以刪除視圖并僅使用代言人或者你選擇的模式進(jìn)行序列化。















 
 
 



 
 
 
 