Rails、Heroku 和 Resque:长 运行 后台作业优化

Rails, Heroku, and Resque: Long Running Background Job Optimization

我们正在构建一个 tinder 风格的应用程序,允许用户进行 "like" 或 "dislike" 事件。每个事件都有大约 100 个与之关联的关键字。当用户 "likes" 或 "dislikes" 和事件发生时,我们将该事件的关键字与用户相关联。用户可以快速获取上千个关键词。

我们通过 table 将用户和事件与关键字(event_keywords 和 user_keywords)相关联。 through table 有一个额外的列 relevance_score,它是一个浮点数(例如,关键字可以是 0.1,如果它非常相关,或者 0.9,如果它非常相关)。

我们的目标是根据用户的关键字向他们展示最相关的事件。所以 Events 有很多 event_rankings 属于一个用户。从理论上讲,我们希望对每个用户的所有事件进行不同的排名。

以下是模型:

User.rb:

  has_many :user_keywords, :dependent => :destroy
  has_many :keywords, :through => :user_keywords
  has_many :event_rankings, :dependent => :destroy
  has_many :events, :through => :event_rankings

Event.rb

  has_many :event_keywords, :dependent => :destroy
  has_many :keywords, :through => :event_keywords
  has_many :event_rankings, :dependent => :destroy
  has_many :users, :through => :event_rankings

UserKeyword.rb:

  belongs_to :user
  belongs_to :keyword

EventKeyword.rb:

  belongs_to :keyword
  belongs_to :event

EventRanking.rb:

  belongs_to :user
  belongs_to :event

Keyword.rb:

  has_many :event_keywords, :dependent => :destroy
  has_many :events, :through => :event_keywords
  has_many :user_keywords, :dependent => :destroy
  has_many :users, :through => :user_keywords

我们有一种方法可以根据关键字计算事件与特定用户的相关程度。这种方法运行得非常快,因为它只是数学。

User.rb:

def calculate_event_relevance(event_id)
  ## Step 1: Find which of the event keywords the user has 
  ## Step 2: Compare those keywords and do math to calculate a score 
  ## Step 3: Update the event_ranking for this user
end

每次用户 "likes" 或 "dislikes" 一个事件,都会创建一个后台作业:

RecalculateRelevantEvents.rb:

def self.perform(event_id)
  ## Step 1: Find any events that that share keywords with Event.find(event_id)
  ## Step 2: calculate_event_relevance(event) for each event from above step
end

下面是过程总结:

  1. 用户喜欢或不喜欢一个事件
  2. 已创建后台作业,查找与步骤 1 中的事件相似的事件
  3. 根据用户的关键字重新计算每个类似事件

我正在想办法优化我的方法,因为它很快就会失控。普通用户每分钟将浏览大约 20 个事件。一个事件最多可以有 1000 个类似的事件。每个事件都有大约 100 个关键字。

因此,在我的方法中,每次滑动,我需要循环 1000 个事件,然后在每个事件中循环 100 个关键字。每个用户每分钟发生 20 次。

我该如何处理?

每次滑动都要计算吗?您可以 debounce 它,并且每 5 分钟不超过一次为用户重新计算吗?

此数据不需要每秒更新 20 次才有用,事实上,每秒更新一次可能比有用的频率高得多。

通过 5 分钟的去抖,您可以在同一时期从每个用户 6,000 (20 * 60 * 5) 次重新计算减少到 1 次 - 相当大的节省。

如果可以的话,我还建议您使用 sidekiq,通过它的多线程处理,您将大大提高同时作业的数量 - 我是它的忠实粉丝。

一旦你使用了它们,你可以尝试 gem 像: https://github.com/hummingbird-me/sidekiq-debounce

...这提供了我建议的那种去抖。