gpt4 book ai didi

ruby-on-rails - 使用缓存优化 Rails 中的时间线

转载 作者:IT王子 更新时间:2023-10-29 06:05:51 25 4
gpt4 key购买 nike

我希望获得有关正确使用缓存以加速 Rails 中的时间线查询的建议。这是背景:

我正在开发一个带有 Rails 后端的 iPhone 应用程序。这是一个社交应用程序,与其他社交应用程序一样,它的主要 View 是消息的时间线(即新闻源)。这与 Twitter 非常相似,其中时间轴由用户及其关注者的消息组成。检索时间线的 API 请求中的主要查询如下:

@messages = Message.where("user_id in (?) OR user_id = ?", current_user.followed_users.map(&:id), current_user)

现在这个查询变得非常低效,尤其是在规模上,所以我正在研究缓存。这是我打算做的两件事:

1) 使用 Redis 将时间线缓存为消息 ID 列表

使此查询如此昂贵的部分原因在于确定要即时显示哪些消息。我的计划是继续为每个用户创建一个 Redis 消息 ID 列表。假设我在收到 Timeline API 请求时正确构建了它,我可以调用 Redis 来获取要显示的消息 ID 的预处理有序列表。例如,我可能会得到这样的结果:“[21, 18, 15, 14, 8, 5]”

2) 使用 Memcached 缓存单个消息对象

虽然我相信第一点会有很大帮助,但从数据库中检索单个消息对象仍然存在潜在问题。消息对象可能会变得很大。通过它们,我返回相关对象,如评论、点赞、用户等。理想情况下,我也会缓存这些单独的消息对象。这就是我感到困惑的地方。

如果没有缓存,我会像这样简单地进行查询调用来检索消息对象:

@messages = Message.where("id in (?)", ids_from_redis)

然后我会返回时间线:

respond_with(:messages => @messages.as_json) # includes related likes, comments, user, etc.

现在,鉴于我希望利用 Memcache 检索单个消息对象,似乎我需要一次检索一条消息。使用伪代码我在想这样的事情:

ids_from_redis.each do |m|
message = Rails.cache.fetch("message_#{m}") do
Message.find(m).as_json
end
@messages << message
end

这是我的两个具体问题(抱歉构建时间过长):

1) 这种方法通常有意义吗(redis 用于列表,memcached 用于对象)?

2) 具体来说,在下面的伪代码中,这是唯一的方法吗?一条一条地抓取消息感觉效率很低,但考虑到我打算进行对象级缓存,我不确定还能怎么做。

感谢任何反馈,因为这是我第一次尝试这样的事情。

最佳答案

从表面上看,这似乎是合理的。 Redis 非常适合存储列表等,可以持久化等,memcached 检索单个消息的速度非常快,即使您像那样顺序调用它也是如此。

这里的问题是每次发布消息时您都需要清除/补充 redis 缓存。在这种情况下只清除缓存似乎有点浪费,因为您已经麻烦地识别邮件的每个收件人。

因此,在不希望回答错误问题的情况下,您是否考虑过在发布每条消息时将消息的可见性“呈现”到数据库(或 Redis,就此而言)?像这样:

class Message
belongs_to :sender
has_many :visibilities

before_create :render_visibility
sender.followers.each do |follower|
visibilities.build(:user => follower)
end
def
end

然后您可以非常简单地呈现消息列表:

class User
has_many :visibilities
has_many :messages, :through => :visibilities
end

# in your timeline view:
<%= current_user.messages.each { |message| render message } %>

然后我会像这样添加单独的消息:

# In your message partial, caching individual rendered messages:
<%= cache(message) do %>
<!-- render your message here -->
<% end %>

然后我还会像这样添加整个时间线的缓存:

# In your timeline view
<%= cache("timeline-for-#{current_user}-#{current_user.messages.last.cache_key}") do %>
<%= current_user.messages.each { |message| render message } %>
<% end %>

应该实现的(我没有测试过)是整个时间轴 HTML 将被缓存,直到发布新消息。发生这种情况时,时间线将重新呈现,但所有单独的消息都将来自缓存而不是再次呈现(除了任何其他人未查看的任何新消息可能异常(exception)!)

请注意,这假设消息呈现对于每个用户都是相同的。如果不是,您还需要缓存每个用户的消息,这会有点遗憾,所以如果可以,请尽量不要这样做!

FWIW,我相信这就是 Twitter 所做的模糊(我的意思是模糊)。不过,他们有一种“大数据”方法,推文被分解并插入到大型机器集群的关注者时间线中。我在这里描述的内容将难以在拥有大量追随者的写入密集型环境中扩展,尽管您可以通过使用 resque 或类似工具来稍微改善这一点。

附言我对这里的代码有点懒惰——你应该考虑重构它来移动,例如将时间轴缓存 key 生成到助手和/或人员模型中。

关于ruby-on-rails - 使用缓存优化 Rails 中的时间线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14206376/

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