2012-06-11 40 views
10

我正在處理的應用程序響應大多數使用JSON對象或其集合的請求。我們使用Jbuilder來構建這些響應。呈現的數據量相當大(在各種嵌套結構中有數千個對象 - 一旦格式化並完全展開,對於典型響應,就有多達10,000行JSON行)。根據NewRelic的說法,這種渲染需要花費大量的時間 - 約佔總請求時間的1/3。使用Jbuilder和Rails提高渲染性能3

我正在尋找某種指南,一套提示或其他資源,這些資源可以幫助我確保從JBuilder中獲得最佳性能。我也很好奇,如果有可用於Jbuilder與RABL或其他類似工具的性能比較。

編輯:我發現一個GitHub Issue,抱怨Jbuilder的性能,但唯一真正的建議是任何人的'不使用Jbuilder'。實際上,他們使用的語言略強一些,但仍然沒有任何關於的信息。爲什麼 Jbuilder的速度太慢了,如果有的話,可以做些什麼來避開它,或者爲了同一個任務如何比較其他工具。

回答

12

jbuilder建立一個包含您的數據的大散列,然後使用ActiveSupport::JSON將它變成json。有更快的JSON體如下面的微基準測試顯示(確保你安裝了multijson和yajl-紅寶石寶石)

require 'benchmark' 
require 'active_support' 
require 'multi_json' 
sample = {menu: { 
    header: "SVG Viewer", 
    items: [ 
     {id: "Open"}, 
     {id: "OpenNew", label: "Open New"}, 
     nil, 
     {id: "ZoomIn", label: "Zoom In"}, 
     {id: "ZoomOut", label: "Zoom Out"}, 
     {id: "OriginalView", label: "Original View"}, 
     nil, 
     {id: "Quality"}, 
     {id: "Pause"}, 
     {id: "Mute"}, 
     nil, 
     {id: "Find", label: "Find..."}, 
     {id: "FindAgain", label: "Find Again"}, 
     {id: "Copy"}, 
     {id: "CopyAgain", label: "Copy Again"}, 
     {id: "CopySVG", label: "Copy SVG"}, 
     {id: "ViewSVG", label: "View SVG"}, 
     {id: "ViewSource", label: "View Source"}, 
     {id: "SaveAs", label: "Save As"}, 
     nil, 
     {id: "Help"}, 
     {id: "About", label: "About Adobe CVG Viewer..."} 
    ] 
}} 


MultiJson.engine = :yajl 
Benchmark.bmbm(5) do |x| 
    x.report 'activesupport' do 
    1000.times {ActiveSupport::JSON.encode(sample)} 
    end 
    x.report 'yajl' do 
    1000.times {MultiJson.encode(sample)} 
    end 
end 

在我的機器,這產生

    user  system  total  real 
activesupport 1.050000 0.010000 1.060000 ( 1.068426) 
yajl   0.020000 0.000000 0.020000 ( 0.021169) 

即編碼樣本對象1000次主動支持發了1秒多,MultiJson(使用yajl引擎)耗時21ms。

JBuilder被硬編碼爲使用ActiveSupport :: JSON,但是MultiJSON(允許您在json庫之間切換的gem)很簡單,並且已經是ActiveSupport的依賴關係 - 請參閱我的fork of jbuilder。我已經打開了拉取請求,但在此之前您可以嘗試使用此叉(或創建您自己的 - 這是一個換行)

+0

切換到MultiJson似乎削減了約400ms左右60ms,我們花了一個典型的請求進行渲染。不是我所希望的巨大變化,而是一個改變,一點也不差。謝謝。 – MrTheWalrus

+0

是的。這個。是。大。 – maletor

+0

@Frederick:我看到鏈接中的一行改變: - https://github.com/fcheung/jbuilder/commit/a58b355f68bc39b1fddf8b178f3844c5d4f65501與rails master合併,所以我猜測我們不需要做任何改變。你能否確認我的推論是否正確。 – boddhisattva

4

考慮切換到Rabl並添加一些caching。由於嵌套結構中有成千上萬的對象,因此生成的JSON的某些節點可以呈現爲部分和緩存 - 性能增益可能很大。

除此之外Rabl的性能稍好於JBuilder的性能,但我發現Rabl語法有時會令人困惑,而且一旦實現了碎片緩存,我就會切換到JBuilder。

0

如前所述,JBuilder構建一個散列,然後將該散列序列化爲JSON。

與緩存一樣,存在主散列,並且緩存的散列會合併到主散列中,但仍需要將其轉換爲JSON。

我的解決方案是TurboStreamer。 TurboStreamer直接輸出到IO/Stream/String,因此跳過了JBuilder的序列化步驟(乍一看這依然適用於Rabl和to_json,具體取決於使用情況)。

對於我們來說,這大大減少了渲染時間& GC時間(由於在jbuilder中構建哈希),並允許我們在獲得結果時開始向客戶端流式傳輸JSON。缺點是TurboStreamer稍微冗長一些。

性能測試A(無緩存參與):

性能測試B(大多都緩存):