将Rails应用程序中不明时间减少,并将速度提升了10倍的故事
你好。我是@srockstyle。
Ruby On Rails真是方便啊。作为一个框架,一直以来都有很多“像Rails一样方便!”的框架不断涌现。
这次是关于如何提升使用Rails开发的应用程序速度的故事。尽管如此,由于这是在大约2015年进行的工作,所以在现代环境中可能不适用。
这篇文章的结论最终是“现金好”。关于最近的现金趋势话题,我会另外写一篇。
事情的起源 (shì de qǐ
那时的我独自一人编写应用程序。
在作业接近尾声,解决了几乎所有的错误之后,我注意到了一个特定的现象。

顺便说一下,这是一个远程服务器。数据库连接部分使用了缓存,所以速度还可以,云端也进行了一些设置,一切都还不错,但是还是有点慢。视图是9毫秒,活动记录是17毫秒,但整体花费了1570毫秒。
在Chrome上测量结果显示全部内容加载需要2.23秒。
其他网站。
我只是隨意挑選了一些看起來很重的網站,發現某個大型電子商務網站的響應時間為160毫秒,某個大型電子商務購物中心的響應時間為88毫秒。相比之下,我手機上的應用程序全部返回的時間卻需要2秒。太慢了。
探索1500毫秒的神秘本质
首先,我怀疑服务器的中间件。配置是nginx + Passenger V5(当时V5是最新的!)
由于设置没有问题,所以我现在查看了一下应该积累了缓存的memcache。
<35 GET ********(伏せてます)
<35 Read binary protocol data:
>35 Writing bin response:
这条日志表明缓存未生效。换句话说,原本应该被缓存的地方未被正确缓存。
Active Record 0.0ms之路
由于我从未发出写入查询,所以我试图将读取查询设置为零。由于财务原因,该应用程序无法创建副本。现在看来,这也是个原因。将写入用数据库和读取用数据库分开是基本的做法。
由於金錢問題無法解決,我先試著解決閱讀的問題吧。這是一個徹底的省錢方法。
缓存存储采用了memcached加Dalli。那时这是一种流行趋势。
- Dalli / github
在编写Active Record时,将修正处理步骤。
Rails.cache.fetch("key"){
Model.where(flg: true).order("created_at DESC")
}
这是个错误的例子。
这是一个将ActiveRecord在执行SQL之前插入内容的行为。
于是我这样做了。
ret = Rails.cache.read(key)
if ret.nil?
ret = Model.where(flg: true).order("created_at DESC").to_a
Rails.cache.write(key,ret)
end
太冗长了。
一般而言,在fetch的AR后面添加to_a就可以了。
暫時,通過將其修改為這個方法來調用多個ActiveRecord將被緩存。原來必須將其正確轉換為數組。
寻找、通过查找
虽然这样说,但Rails的ActiveRecord不止有一个功能。还有find和find_by等。
这些问题已经得到了解决。
ret = Model.find(id).attributes.symbolize_keys
将属性设置为符号之后,您可以在哈希中进行访问。由于attribute时只能通过hash [ “”]访问,所以我有意地将其转换为符号。
如果有人知道好的方法,请告诉我……
通过缓存这个对象,find的问题就解决了。
关系
使用Rails时,会有以下类似的需求。
user = User.find(1)
pages = user.pages
如果在上面进行attributes并缓存,那么它只是一个简单的哈希,因此这没有意义关于关系。(Translated to Chinese)
在这里,我们使用缓存并将其加载到数组中来解决这个问题。
ret = Rails.cache.read(key)
if ret.nil?
model = Model.where(flg: true).order("created_at DESC").to_a
ret = model.pages.to_a
Rails.cache.write(key,ret)
end
这里也是经过犹豫后决定成这个形式的,如果有什么好的方法,请告诉我。
通过这三项措施,Active Record现在可以在0.0毫秒内返回结果。
提高观看端的渲染速度
那么接下来就是视图方面了。在视图的渲染中往往会耗费300毫秒以上的时间,因此我希望尽量避免在这方面使用Rails的延迟处理。
我在这里使用了片段缓存。
关于片段缓存系统,以下提供了详细信息。
- Rails のフラグメントキャッシュで使われるキーについて
我参考了这个网站进行设置。因为有很多地方都是重复使用了部分模板,所以我将它们嵌入进去了。使用方法是这样的。
- cache obj do
## haml
haml很好,因为不需要后面绑定。通过将对象放入obj中来在循环中更改键。
经过全面的执行,我们可以看到相当大的改善。
结果

首页响应速度减少至156毫秒!太棒了!
即使在Chrome开发者工具中观察,也仍然保持在大约300毫秒左右。
因為我覺得可能可以做得更快,所以我目前正在不斷嘗試和錯誤。如果有人知道什麼好方法的話,請一定留下評論,我將非常高興!
卡住了
写代码的方法 (xiě mǎ de
由于当时没有人对代码进行审查,我一个人写了上面的代码,所以无法确定它是否正确。
如果要做类似的事情,我认为还有更好的方法。
批量修改视图文件
应该会有更好的方法来处理这个问题,因为现在所有的代码都已经被改成了hash[:key]或者hash[“key”]的形式。
关系缓存
由于类似Rails特有的obj.store.name的写法失效了,让我感到很困扰。我尝试使用了一些能够顺利解决问题的Gem,但是变得非常复杂,所以我选择放弃了。
如果之后进行了调查,我会随时补充的。
整理
最开始我们怀疑是中间件调整或网络问题,但是根据日志显示的毫秒数最终发现这是应用程序返回时的日志,所以需要在应用程序端进行修正。
如果这个文件能对某人有所帮助,那就非常幸运了。