通過添加一些 gems 來提升 Rails 應用的性能

jopen 10年前發布 | 20K 次閱讀 Rails Ruby開發

使用Rails一段時間之后,你可能就會開始吹毛求疵的想要提高它性能。這是一系列文章中第一次考慮如何提高(即使微不足道的)Rails的性能。

我將會關注在一些gem的提速上面,在某些情況下,可能是一小部分的Rails,如html轉義,String.blank?和JSON工具類。

基準原則

原則,對于僅僅在控制臺wrk運行幾次來講,是一個與其過強的詞語,但是我這里不是來尋找“圣杯”的,而是提供一些初始的想法。

我將從舊的apache ab切換到wrk

wrk是現代的 HTTP 基準工具,當在一個單一的多核 CPU 上運行時,能夠產生巨大的負載。

wrk -t10 -c10 -d10s http://localhost:3000

這條指令運行基準問題10s,使用10個線程,并且保持打開50個HTTP鏈接,也就是說,這樣就足夠了。記得將這些基準測試在你實際的應用中跑一下,看一下實際上的性能提高有多少。

escape_utils gem

通過可愛的escape_utils gem可以加快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</pre>

使用標準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_blank gem!

僅需要在你的Gemfile中添加gem 'fast_blank',這應該就可以非常漂亮的提高像這篇文章中提到的String.black?方法的速度。為了測試,我僅添加下倆代碼:

fast_blank是一個簡單的擴展,提供了一個支持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</pre>

使用標準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

這個測試用例非常簡單,僅僅將所有的article序列化為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,如果你想深入探究它,可以看我的這篇文章。在初始測試時,jemalloc并沒有產生太多性能的提升,至少對我使用的測試用例是這樣的。

提示:某些情況下,可能會默認包含在Ruby中。

更新:請一定嘗試一下kzk的jemalloc gem

gem install jemalloc

je -v rails s</pre>

深入探究你的Rails應用

不要擔心,去用一下Sam Saffron的帶有非常棒的FlameGraphsMiniProfiler吧!

結語

鑒于你的應用要做什么,你可能想為你的Gemfile添加上述的一些gem。通常我會把他們都添加上,當然是出于一個好的估量(你可能會想檢查你的RAM利用率,然后在添加之前,進行一個完整的測試)。

oj gem基于JSON API,對Rails來說是非常不錯的,使用oj gem,你可以刪除視圖并僅使用代言人或者你選擇的模式進行序列化。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!