10

我正在开发的应用程序使用 JSON 对象或其集合响应大多数请求。我们正在使用Jbuilder来构建这些响应。呈现的数据量相当大(各种嵌套结构中的数千个对象 - 一旦格式化并完全展开,典型响应就有多达 10,000 行 JSON)。根据 NewRelic 的说法,这种渲染需要大量时间——大约是总请求时间的 1/3。

我正在寻找某种指南、一组技巧或其他资源,以帮助我确保从 JBuilder 中获得最佳性能。我也很好奇是否有 Jbuilder 与RABL或其他类似工具的性能比较。

编辑:我发现了一个抱怨 Jbuilder 性能的GitHub 问题,但任何人提出的唯一实际建议是“不要使用 Jbuilder”。好吧,实际上,他们使用了稍微强一些的语言,但是仍然没有关于Jbuilder为何如此缓慢的消息,如果有的话,可以做些什么来绕过它,或者对于相同任务的其他工具如何比较。

4

3 回答 3

12

jbuilder 构建一个包含您的数据的大哈希,然后ActiveSupport::JSON将其转换为 json。如下微基准测试所示,有更快的 json 发射器(确保您安装了 multijson 和 yajl-ruby gem)

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 引擎)花费了 21 毫秒。

JBuilder 被硬编码为使用 ActiveSupport::JSON,但是 MultiJSON(一个允许您在 json 库之间切换的 gem)是一个微不足道的插件,并且已经是 ActiveSupport 的依赖项 - 请参阅我的 jbuilder 的分支。我已经打开了一个拉取请求,但在那之前你可以尝试使用这个 fork(或创建你自己的 - 这是一个单行更改)

于 2012-06-14T16:22:45.130 回答
4

考虑切换到 Rabl 并添加一些缓存。鉴于嵌套结构中有数千个对象,生成的 JSON 的某些节点可以呈现为部分并缓存 - 性能提升可能是巨大的。

除此之外,Rabl 的性能略好于 JBuilder 的性能,但我发现 Rabl 语法有时令人困惑,一旦它实现了片段缓存,我就会切换到 JBuilder。

于 2012-06-20T11:26:17.190 回答
0

如前所述,JBuilder构建一个散列,然后将该散列序列化为 JSON。

与缓存相同,有主散列,缓存的散列合并到仍需要转换为 JSON 的主散列中。

我的解决方案是TurboStreamer。TurboStreamer 直接输出到 IO/Stream/String,因此跳过了 JBuilder 的序列化步骤(乍一看,这仍然适用于Rabl和 to_json ,具体取决于使用情况)。

对我们来说,这显着减少了渲染时间和 GC 时间(由于在 jbuilder 中构建哈希),并允许我们在获得结果时开始将 JSON 流式传输到客户端。缺点是 TurboStreamer 更加冗长和明确。

性能测试 A(不涉及缓存):

性能测试 B(主要是所有缓存):

于 2017-12-02T23:23:11.873 回答