【问题标题】:Redis, Sidekiq and Heroku AppsRedis、Sidekiq 和 Heroku 应用程序
【发布时间】:2021-03-01 21:18:08
【问题描述】:

我有两个 Rails 应用程序需要共享一些状态。每个应用程序都需要在其执行生命周期内运行后台作业。我将 Heroku Redis 添加到每个应用程序和 Sidekiq。所以当我运行后台作业时,一切都很好。

我没有共享状态,直到我将一个应用程序的 REDIS_URL 指向另一个应用程序的 REDIS_URL,然后两个应用程序都使用相同的共享 Redis 实例,我假设,因此我有一些共享状态。

现在两个 Sidekiq 实例共享同一个 Redis,一个 App 正在查看其他 Apps 的作业并在呕吐,因为它不知道其他 Apps 的作业。

什么是共享状态和保持作业分开的更清晰的方法?我想我只需要购买一个可以用作与作业分开的共享状态的缓存吗?

Heroku 应用 1. 拥有 Redis 实例。有 Sidekiq。运行作业 AaaBbbJob Heroku App 2. 从 App1 指向 Redis 实例。有 Sidekiq

我注意到 App 2 的日志显示作业 AaaBbbJob 尝试运行并失败,因为未找到 AaaBbbJob。

在 App 1 的日志中,Job AaaBbbJob 运行良好...

所以我的困惑在于试图向自己保证这一切都很好。当 App 1 通过 Sidekiq 通过作业进入 Redis 时,无论出于何种原因,App 2 在 Redis 中也看到了该作业,并尝试运行它。

所以我的问题是,由于现在将 Jobs 放入 Redis 是在两个应用程序之间共享的,它们都尝试并运行他们看到的任何作业?

【问题讨论】:

  • 你如何表示你的应用状态? Sidekiq 在不同的机器/实例中运行你的 slug。您应该将任何必需的参数传递给您的工作,而它是模型实例或应用程序范围的数据。 Sidekiq 不知道动态创建的网络服务器常量或类变量是什么。 (如果您有实际代码要添加到您的问题中会更容易)

标签: ruby-on-rails heroku redis sidekiq


【解决方案1】:

这里有两个问题:

  • 2 个不同的应用使用 Sidekiq 并共享同一个 Redis 实例
  • 需要在两个应用之间交换数据

对于第一个问题,您的 2 个应用程序可能有不同的 Sidekiq 作业,但由于相同的 Redis 实例,每个后台应用程序(运行各自的应用程序 slug)都会选择所有 Sidekiq 作业,并且只了解他们知道的作业。

Sidekiq 就是这样完成的,你真的帮不上忙。该功能允许使用 Sidekiq 为同一个应用程序运行多个测功机。

您可以做的是将两种类型的 Sidekiq 作业分开的方法是为每个应用程序分配一个 redis 数据库:What's the Point of Multiple Redis Databases?

Redis 可以将数据分离到 16 个不同的数据库中。

例如,我的一个应用程序中的 Redis 配置是:

config/redis.yml

development:
  url: redis://localhost:6379/
  db: 2  

production:
  url: <%= ENV["REDIS_URL"] %>
  db: 2

test: 
  url: redis://localhost:6379/
  db: 2 

在另一个应用程序中,我使用的是 1 号数据库。然后没有冲突。

匹配的 Sidekiq 初始化器看起来像这样:

conf = Rails.application.config_for(:redis)
confid = conf.merge({id: "Sidekiq-server-PID-#{::Process.pid}"})
confservid = conf.merge({id: "Sidekiq-server"})

if Rails.env.production?

  Sidekiq.configure_client do |config|    
    config.redis = conf    
  end

  Sidekiq.configure_server do |config|    
    config.redis = conf    
  end

end


if Rails.env.development?
  Sidekiq.configure_client do |config|         
    config.redis = confid    
  end

  Sidekiq.configure_server do |config|    
    config.redis = confservid        
  end

end

如您所见,我在解释的基础上命名了所有 redis 客户端(正在开发中)。了解 Redis 客户端的使用情况非常有用。

关于您的第二个问题:共享“应用程序状态”我认为这是关于共享全局值,例如常量或类变量。

也许可以通过 Redis 共享这些数据,但这绝对是丑陋的。您将 2 个应用程序变成了一个整体。 即使您设法正确地做到了,当您希望每个应用程序拥有自己的 Redis 实例时,您也必须重写所有内容。

做到这一点的唯一方法是通过一个控制器作为一个 API 来响应请求并将数据传递给其他应用程序。

【讨论】:

  • 感谢您所做的一切。实际上,应用程序之间共享的状态非常干净和安全。一个应用程序,例如 App1,生成一个 JSON 数据结构 {“foomanchu”:“greatbeard”},在 App2 中我有时需要使用这个键“foomanuchu”。所以据我所知没有丑陋的,只是需要在应用程序之间共享一些 JSON!
  • 只需通过在任一应用程序中 ping 一条路由,将其作为 API 执行即可。这绝对是最干净的方式。
【解决方案2】:

每个应用都需要一个用于其他 Redis 实例的Redis 连接池。然后 App A 可以使用这些连接将数据或作业发送到 App B 或将作业推送到其 sidekiq。使用多个 Redis 称为分片。

https://github.com/mperham/sidekiq/wiki/Sharding

【讨论】:

  • 所以在我的 Rails 应用程序 A 中,我在 Heroku 购买了一个来自 Heroku 的 Super Redis。我在 Redis 中设置了一个命名空间,我得到的 REDIS_URL 为“AppA”。现在 Sidekiq 也应该指向命名空间“AppA”,神奇地我的 ActiveJobs 将在正确的 Redis DB 中执行,没有串扰,一切都很好。至于 AppB,它有一个 REDIS_URL 指向 AppA Redis,而这里的 Rail Initialization 中,命名空间称为 AppB,而 AppB 中的 Sidekiq 则指向这个命名空间 'AppB',以便作业在 Redis 中执行,而不会污染什么在 AppA 中进行。
  • 现在只要在 Redis 中有一个键,这两个应用程序都可以看到,我想这意味着两个应用程序都必须在 Redis 中看到相同的数据库,所以哇...所有突然我又遇到麻烦了。我想我可能会退后一步。在其 Redis 上运行 AppA,在其 Redis 上运行 AppB,对于共享状态,找出另一个解决方案
  • 您需要在 AppA 中有一个单独的 Redis 池,配置为使用 AppB 的命名空间,反之亦然。或者,您可以在两个应用程序中都有一个没有命名空间的池,这是两者的共享空间。
猜你喜欢
  • 2013-03-14
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 2015-06-17
  • 2017-04-26
  • 2019-06-03
相关资源
最近更新 更多