在多线程 Rails 环境中使用 Redis 的最佳方式是什么?(彪马/Sidekiq) [英] What is the best way to use Redis in a Multi-threaded Rails environment? (Puma / Sidekiq)

查看:72
本文介绍了在多线程 Rails 环境中使用 Redis 的最佳方式是什么?(彪马/Sidekiq)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using Redis in my application, both for Sidekiq queues, and for model caching.

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

What is the best way to have a Redis connection available to my models, considering that the models that will be hitting Redis will be called both from my Web application (ran via Puma), and from background jobs inside Sidekiq?

我目前正在我的初始化程序中执行此操作:

I'm currently doing this in my initializers:

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

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

And then simply use Redis.current.get / Redis.current.set (and similar) throughout the code...

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

This should be thread-safe, as far as I understand, since the Redis Client only runs one command at a time, using a Monitor.

现在,Sidekiq 有自己的 Redis 连接池,推荐这样做

Now, Sidekiq has its own connection pool to Redis, and recommends doing

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

据我所知,这比仅使用 Redis.current 的方法要好,因为当它们命中 Redis 时,多个线程上没有多个工作线程在单个连接上相互等待.

As I understand it, this would be better than the approach of just using Redis.current because you don't have multiple workers on multiple threads waiting on each other on a single connection when they hit Redis.

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

However, how can I make this connection that I get from Sidekiq.redis available to my models? (without having to pass it around as a parameter in every method call)

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

I can't set Redis.current inside that block, since it's global, and I'm back to everyone using the same connection (plus switching between them randomly, which might even be non-thread-safe)

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

Should I store the connection that I get from Sidekiq.Redis into a Thread-local variable, and use that thread-local variable everywhere?

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

In that case, what do I do in the "Puma" context? How do I set the thread-local variable?

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

Any thoughts on this are greatly appreciated.

谢谢!

推荐答案

您为应用程序代码使用单独的全局连接池.在你的 redis.rb 初始值设定项中放入这样的内容:

You use a separate global connection pool for your application code. Put something like this in your redis.rb initializer:

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

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

Now in your application code anywhere, you can do this:

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

您最多可以与 puma/sidekiq 工作人员共享 10 个连接.这将带来更好的性能,因为正如您正确地注意到的那样,您不会让所有线程争夺单个 Redis 连接.

You'll have up to 10 connections to share amongst your puma/sidekiq workers. This will lead to better performance since, as you correctly note, you won't have all the threads fighting over a single Redis connection.

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

All of this is documented here: https://github.com/mperham/sidekiq/wiki/Advanced-Options#connection-pooling

这篇关于在多线程 Rails 环境中使用 Redis 的最佳方式是什么?(彪马/Sidekiq)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆