2012-06-11 25 views
10

Ứng dụng tôi đang xử lý đáp ứng hầu hết các yêu cầu với các đối tượng JSON hoặc các bộ sưu tập của chúng. Chúng tôi đang sử dụng Jbuilder để xây dựng các phản hồi đó. Lượng dữ liệu được hiển thị khá lớn (vài nghìn đối tượng trong các cấu trúc lồng nhau khác nhau - một khi được định dạng và mở rộng hoàn toàn, có tới 10.000 dòng JSON cho một phản hồi điển hình). Việc render này chiếm một lượng thời gian đáng kể - khoảng 1/3 tổng thời gian yêu cầu, theo NewRelic.Cải thiện hiệu suất kết xuất với Jbuilder và Rails 3

Tôi đang tìm một số loại hướng dẫn, bộ mẹo hoặc tài nguyên khác sẽ giúp tôi đảm bảo rằng tôi nhận được hiệu suất tốt nhất có thể từ JBuilder. Tôi cũng tò mò nếu có so sánh hiệu suất có sẵn cho Jbuilder so với RABL hoặc các công cụ tương tự khác.

Chỉnh sửa: Tôi đã tìm thấy một GitHub Issue phàn nàn về hiệu suất Jbuilder, nhưng đề xuất thực tế duy nhất của bất kỳ ai được thực hiện là 'không sử dụng Jbuilder'. Vâng, trên thực tế, họ đã sử dụng ngôn ngữ hơi mạnh hơn, nhưng vẫn không có từ nào trên lý do tại sao Jbuilder quá chậm, cái gì, nếu có, có thể được thực hiện để thực hiện hoặc sử dụng các công cụ khác cho cùng một công việc so sánh.

Trả lời

12

jbuilder xây dựng một băm lớn chứa dữ liệu của bạn và sau đó sử dụng ActiveSupport::JSON để biến nó thành json. Có phát thải json nhanh hơn như các chương trình sau đây vi điểm chuẩn (chắc chắn rằng bạn có đá quý multijson và yajl-ruby cài đặt)

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 

Trên máy tính của tôi này tạo

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

tức là để mã hóa các đối tượng mẫu 1000 lần hỗ trợ hoạt động mất một mái tóc hơn 1 giây, MultiJson (sử dụng động cơ yajl) mất 21ms.

JBuilder được mã hóa cứng để sử dụng ActiveSupport :: JSON, nhưng MultiJSON (đá quý cho phép bạn chuyển đổi giữa các thư viện json) là một sự sụt giảm nhỏ và đã là phụ thuộc của ActiveSupport - xem fork of jbuilder. Tôi đã mở một yêu cầu kéo, nhưng cho đến lúc đó bạn có thể thử sử dụng nĩa này (hoặc tạo của riêng bạn - đó là một thay đổi một dòng)

+0

Chuyển sang MultiJson dường như cắt giảm khoảng 60ms trong 400ms để chúng tôi chi tiêu hiển thị cho một yêu cầu điển hình. Không phải là sự thay đổi lớn mà tôi đã hy vọng, nhưng đối với một sự thay đổi một dòng, không tệ chút nào. Cảm ơn. – MrTheWalrus

+0

Có. Điều này. Là. Tuyệt quá. – maletor

+0

@Frederick: Tôi thấy một dòng thay đổi từ liên kết: - https://github.com/fcheung/jbuilder/commit/a58b355f68bc39b1fddf8b178f3844c5d4f65501 sáp nhập với đường ray chính, vì vậy tôi đoán chúng tôi không cần thực hiện bất kỳ thay đổi nào. Bạn có thể vui lòng xác nhận nếu suy luận của tôi là chính xác. – boddhisattva

4

Xem xét chuyển sang Rabl và thêm một số caching. Do bạn có hàng ngàn đối tượng trong cấu trúc lồng nhau, một số nút của kết quả JSON của bạn có thể được hiển thị dưới dạng partials và được lưu trong bộ nhớ cache - hiệu suất đạt được có thể rất lớn. Ngoài hiệu suất Rabl này là tốt hơn một chút so với hiệu suất của JBuilder, nhưng tôi thấy cú pháp Rabl đôi khi khó hiểu và tôi sẽ chuyển sang JBuilder khi nó đã thực hiện bộ nhớ đệm mảnh.

0

Như đã nêu trước khi JBuilder tạo một băm, sau đó tuần tự hóa băm đó thành JSON.

Tương tự với bộ nhớ đệm, có băm chính và băm được lưu trong bộ nhớ cache được hợp nhất vào băm chính mà vẫn cần được chuyển đổi thành JSON.

Giải pháp của tôi là TurboStreamer. TurboStreamer kết quả đầu ra trực tiếp đến một IO/Stream/String do đó bỏ qua bước serialization mà JBuilder (và ở cái nhìn đầu tiên này vẫn áp dụng cho Rabl, và to_json tùy thuộc vào cách sử dụng).

Đối với chúng tôi điều này đã giảm đáng kể thời gian hiển thị & lần GC (do xây dựng băm trong trình tạo hình) và cho phép chúng tôi bắt đầu truyền JSON ra cho khách hàng khi chúng tôi nhận được kết quả của mình. Nhược điểm là TurboStreamer là một chút chi tiết và rõ ràng.

Hiệu suất thử nghiệm A (không có bộ nhớ đệm có liên quan):

Hiệu suất thử nghiệm B (chủ yếu là tất cả các bộ nhớ đệm):

Các vấn đề liên quan