在多线程 Rails 环境中使用 Redis 的最佳方式是啥? (彪马/Sidekiq)

Posted

技术标签:

【中文标题】在多线程 Rails 环境中使用 Redis 的最佳方式是啥? (彪马/Sidekiq)【英文标题】:What is the best way to use Redis in a Multi-threaded Rails environment? (Puma / Sidekiq)在多线程 Rails 环境中使用 Redis 的最佳方式是什么? (彪马/Sidekiq) 【发布时间】:2015-03-22 17:31:42 【问题描述】:

我在我的应用程序中使用 Redis,用于 Sidekiq 队列和模型缓存。

考虑到将要访问 Redis 的模型将被我的 Web 应用程序(通过 Puma 运行)和 Sidekiq 内的后台作业调用,那么让我的模型可以使用 Redis 连接的最佳方式是什么?

我目前正在我的初始化程序中这样做:

Redis.current = Redis.new(host: 'localhost', port: 6379)

然后在整个代码中简单地使用Redis.current.get / Redis.current.set(和类似的)......

据我了解,这应该是线程安全的,因为 Redis 客户端一次只运行一个命令,使用监视器。

现在,Sidekiq 有自己的 Redis 连接池,建议这样做

Sidekiq.redis do |conn|
   conn.get
   conn.set
end

据我了解,这比仅使用 Redis.current 的方法要好,因为您不会让多个线程上的多个工作人员在单个连接上等待 Redis。

但是,如何使我从 Sidekiq.redis 获得的这种连接可用于我的模型? (无需在每个方法调用中将其作为参数传递)

我无法在该块内设置 Redis.current,因为它是全局的,而且我回到使用相同连接的每个人(加上在它们之间随机切换,这甚至可能是非线程安全的)

我是否应该将从 Sidekiq.Redis 获得的连接存储到线程局部变量中,并在任何地方使用该线程局部变量?

在这种情况下,在“Puma”上下文中我该怎么做?如何设置线程局部变量?

非常感谢您对此的任何想法。

谢谢!

【问题讨论】:

【参考方案1】:

您为应用程序代码使用单独的全局连接池。在你的 redis.rb 初始化器中加入这样的东西:

require 'connection_pool'
REDIS = ConnectionPool.new(size: 10)  Redis.new 

现在在您的应用程序代码的任何地方,您都可以这样做:

REDIS.with do |conn|
  # some redis operations
end

您最多可以在 puma/sidekiq 工作人员之间共享 10 个连接。这将带来更好的性能,因为正如您正确指出的那样,您不会让所有线程争夺单个 Redis 连接。

所有这些都记录在这里:https://github.com/mperham/sidekiq/wiki/Advanced-Options#connection-pooling

【讨论】:

现在,在这种情况下,我的代码将拥有自己的连接池(在您的示例中,10 个连接),Sidekiq 将拥有自己的连接池,它将用于“工人工作”,我不会在我的代码中的任何地方使用“Sidekiq.redis”。这是正确的吗? 这与 Puma、Redis 和 Sidekiq 完美结合。我的前端订阅了我的一个控制器中的事件流,现在性能要好得多。就像@DanielMagliola 所说,我从不在我的代码中使用 Sidekiq.redis,你指的是应用范围内可用的 REDIS 变量。 @MikePerham 那么我们是否也使用REDIS 初始化sidekiq? ` Sidekiq.configure_server 做 |config| config.redis = REDIS 结束 Sidekiq.configure_client 做 |config| config.redis = REDIS 结束 ` Sidekiq wiki 描述了如何初始化 Redis。你可以直接给它一个连接池,但这是一个高级选项,只有在你知道自己在做什么的情况下才应该使用。 @MikePerham 如果我们必须让 Redis 池已经可用于其他初始化程序,您是否建议在 application.rb 中的 config.before_initialize 中定义 REDIS 常量?

以上是关于在多线程 Rails 环境中使用 Redis 的最佳方式是啥? (彪马/Sidekiq)的主要内容,如果未能解决你的问题,请参考以下文章

Java实现Redis分布式锁

Redis分布式锁服务(转)

面试官:怎么实现Redis分布式锁?

如何使用 Java 在多线程环境中测试某些东西 [重复]

在多线程环境中使用 PyCurl 时程序消耗的内存不断增长

可以在多线程环境中使用单个 QueueConnection 吗?