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 中的事件相似的事件
- 根据用户的关键字重新计算每个类似事件
我正在想办法优化我的方法,因为它很快就会失控。普通用户每分钟将浏览大约 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
...这提供了我建议的那种去抖。
我们正在构建一个 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 中的事件相似的事件
- 根据用户的关键字重新计算每个类似事件
我正在想办法优化我的方法,因为它很快就会失控。普通用户每分钟将浏览大约 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
...这提供了我建议的那种去抖。