我有一个模型,我使用 Carrierwave 让用户上传他们的头像。我有一个版本的头像,裁剪成一个叫做“裁剪”的正方形。
class User
mount_uploader :avatar, AvatarUploader
end
class AvatarUploader < ImageUploader
version :cropped do
process :crop
end
end
在我的一个页面中,我列出了几千个用户,每个用户都有他们的头像,为这些图像生成 URL 的调用需要很长时间。
问题似乎在于,仅通过访问已安装上传程序的模型属性,Carrierwave 似乎正在访问磁盘以读取文件、检查文件是否存在或其他内容。换句话说,调用:
user.avatar
user.avatar.cropped
user.avatar.present?
user.avatar.anything_really
所有这些都击中了硬盘。
在我发现的最糟糕的情况下,对于我们的一个拥有大量数据的客户端,页面在我的开发机器上呈现 10 秒,在服务器上呈现 30 秒。此页面呈现意味着对“user.avatar.cropped”的大约 1200 次调用。差异似乎是由于 SSD 与 HDD (或者可能是由于 VM 的开销,不确定)。不过,OS 磁盘缓存确实起作用了,因为在服务器中第二次渲染同一页面需要 10 秒,大概是因为磁盘命中被缓存了。
如果我“手动”生成 URL,而不是使用 CarrierWave,它会在所有机器中恢复到 10 秒,所以肯定是 Carrierwave 导致了速度变慢。
似乎不需要点击 HDD 来生成路径。有没有办法避免这种情况,或者解决这个问题?
(注意:无论如何,我知道 10 秒对于一个页面来说太糟糕了,我们正在做一些事情来解决这个问题,但是在整个站点范围内,我们有很多页面显示了大量的头像,并且由于这些硬盘驱动器,我们的速度变慢了点击,所以我们想改进它们,而不必手动生成 URL,因为 Carrierwave 提供的抽象很棒)
更新(由于下面的评论):我们没有使用 eager_load。Cache_classes 在开发中关闭,在生产中打开。(同样,dev 很快,prod 很慢,但我认为这与 cache_classes 无关)