gpt4 book ai didi

ruby-on-rails - 如何加快我的 Rails App JSON 渲染速度?

转载 作者:数据小太阳 更新时间:2023-10-29 08:44:27 25 4
gpt4 key购买 nike

我的 Rails 4.2.4 应用程序有一个 JSON API。一个 Action 被非常非常频繁地调用,所以我想让它尽可能快(我的目标是每个请求大约 150 毫秒)。

Controller 方法如下所示:

def update
t_update = 0
t_render = 0
total = Benchmark.measure do
success = false
t_update = Benchmark.measure do
success = @character.update_attributes(char_params)
end
t_render = Benchmark.measure do
if success
respond_to do |format|
format.html { redirect_to @character }
format.json { render json: char_to_json(@character) }
end
else
respond_to do |format|
format.html { redirect_to @character }
format.json { render json: char_to_json(@character), status: 500 }
end
end
end
end
logger.warn("##### Update: #{(t_update.real*1000).to_i}ms")
logger.warn("##### Render: #{(t_render.real*1000).to_i}ms")
logger.warn("##### Update + Render: #{(total.real*1000).to_i}ms")
end

我添加了一些基准测量来了解时间花在了哪里。我得到这样的输出:

App 6144 stdout: ##### Update: 195ms
App 6144 stdout: ##### Render: 265ms
App 6144 stdout: ##### Update + Render: 461ms

这是在生产服务器上,当然是在 Rails 生产模式下。显然太慢了。由于渲染需要更多的时间,我想先优化它。

  • 最初,我使用 jbuilder View 呈现我的 JSON。这花了大约 400 毫秒。
  • 我将 JSON 渲染器切换为 Oj,将我带到了大约 300 毫秒
  • 我完全放弃了 jbuilder。现在我从我的模型中生成一个哈希并将其直接传递给 Oj(如此处推荐的那样:http://brainspec.com/blog/2012/09/28/lightning-json-in-rails/)

char_to_json 看起来像这样:

def char_to_json(char)
hash = nil
json = nil
t_hash = Benchmark.measure do
hash = char.as_json
end
t_render = Benchmark.measure do
json = Oj.dump(hash, mode: :object, indent: 0)
end
logger.warn("#### Hashing: #{(t_hash.real*1000).to_i}ms")
logger.warn("#### Rendering: #{(t_render.real*1000).to_i}ms")
json
end

这里的基准显示:

App 6144 stdout: ####  Hashing: 263ms
App 6144 stdout: #### Rendering: 0ms

所以所有的时间都花在创建哈希上了!不可否认,它是一个相当大和复杂的对象图,但它基本上只是从我的模型对象创建一个哈希,所有内容都已经初始化(ActiveRecord 整个请求大约需要 20 毫秒):

def as_json
grouped_items = items.group_by {|i| i.container }

json = {
'id' => id,
'name' => name,
'status' => status,
'creating' => creating?,
'title' => title,
'level' => level,
'level_count' => level_count,
'rules_compliant' => rules_compliant?,
'health' => health,
'max_health' => max_health,
'stamina' => stamina,
'mana' => mana,
'mana_mult_buff' => mana_mult_buff,
'wounds' => wounds,
'armor_buff' => decimal_number(armor_buff),
'damage_incoming' => decimal_number(damage_incoming),

'rolled_damage_left' => rolled_damage_left,
'rolled_damage_right' => rolled_damage_right,
'initiative_roll' => initiative_roll,

'offensive_buff' => offensive_buff,
'defensive_buff' => defensive_buff,
'evasion_buff' => evasion_buff,
'speed_buff' => speed_buff,

'notes' => notes,

'race' => race.as_json,
'birthsign' => birthsign.as_json,
'specialization' => specialization.as_json,
'fav_attribute1' => fav_attribute1.as_json(mode: :fav),
'fav_attribute2' => fav_attribute2.as_json(mode: :fav),

'attributes' => character_attributes.map {|attr| attr.as_json },
'skills' => skills.map {|skill| skill.as_json },
'resistances' => resistances.map {|resi| resi.as_json },

'containers' => Item.containers.map do |container|
{
'key' => container[0],
'name' => I18n.t("activerecord.attributes.item.container.#{container[0]}"),
'weight' => decimal_number(send("#{container[0]}_weight")),
'max_weight' => respond_to?("max_#{container[0]}_weight") ?
decimal_number(send("max_#{container[0]}_weight")) :
nil,
'items' => (grouped_items[container[0]] || []).
sort {|a,b| a.index <=> b.index}.
map {|item| item.as_json }
}
end,

'slots' => slots.map {|slot| slot.as_json },
'spells' => spells.map {|spell| spell.as_json self }
}
formulas.each do |formula|
json[formula.property.abbr] = decimal_number(formula.points)
end
json
end

我该如何进一步调查?这里的时间能花在哪里?或者在 ruby​​ 中创建一个大的嵌套哈希只是很慢?我不想相信!

感谢您的任何建议!

最佳答案

预加载

检查 N+1 数据库命中。在你的 as_json 中使用了一些关联(比如 race, skills, resistances),当你阅读 @character 时,可能不是所有在第一个查询中选择的关联 实例。附加信息 http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

考虑缓存

  • 'race' => race.as_json - 我想你没有那么多比赛,而且它们不会经常更新。您可以将 races json 放入 Rails.cache 中,例如

    'race' => Rails.cache.fetch("json_race_#{race.id}", expires_in: 1.day) do
    race.as_json
    end

    如果您更改种族,请不要忘记使缓存失效 :)

  • 'containers' => Item.containers.map ... - 看起来这部分代码对于任何角色都是相同的。也可以缓存。

关于ruby-on-rails - 如何加快我的 Rails App JSON 渲染速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34549248/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com