$redis 全局变量与 ruby on rails
Posted
技术标签:
【中文标题】$redis 全局变量与 ruby on rails【英文标题】:$redis global variable with ruby on rails 【发布时间】:2014-01-31 06:48:11 【问题描述】:我使用 redis 作为读取缓存。我创建了一个初始化器
config/initializer/redis.rb
$redis = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
我在我的 unicorn.rb 中使用这个全局变量来创建一个新的连接,无论何时创建一个新的 worker。
before_fork do |server, worker|
# clear redis connection
$redis.quit unless $redis.blank?
end
# Give each child process its own Redis connection
after_fork do |server, worker|
$redis = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
end
每当我需要访问我的 redis 服务器时,我也会使用这个全局变量。但是我不习惯使用这个全局变量。有没有比使用全局变量更好的选择?
【问题讨论】:
***.com/a/16474679/19079 比以下任何答案都回答得更好。 【参考方案1】:有Redis.current
,您可以使用它来存储您的唯一Redis
实例。
因此,您可以按如下方式分配您的实例,而不是使用$redis
:
Redis.current = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
Redis.current
是 introduced to redis-rb in 2010 作为获取 redis 连接的标准方式,所以我很惊讶没有其他答案提到它。
更新:从 4.6.0 版开始Redis.current
has been deprecated。作者指出,典型的多线程应用程序会在共享 redis 客户端周围发现很多锁定。他们建议定义一个自己的地方来获取redis客户端,但也建议使用连接池。
因此,公认的答案是实现与Redis.current
相当的目标的最简单解决方案,但在多线程环境中可能表现不佳。
【讨论】:
令人讨厌的是,这是我一直在寻找的答案,但因为它低于公认的答案,所以我浪费时间不这样做。 恕我直言,这应该是公认的答案。 现在已弃用。惊喜。多么有趣。 我提交了一个问题,要求提供“官方”建议:github.com/redis/redis-rb/issues/1064 @courtsimas 感谢您注意到这一点。我已经在相应的提交中询问并相应地更新了答案。【参考方案2】:进一步扩展 mestachs 建议,在初始化程序中命名模块,如下所示
config/initializers/redis.rb
module ReadCache
class << self
def redis
@redis ||= Redis.new(:url => (ENV["REDIS_URL"] || 'redis://127.0.0.1:6379'))
end
end
end
然后在 unicorn.rb 中
before_fork do |server, worker|
...
if defined?(ReadCache.redis)
ReadCache.redis.quit
end
...
end
after_fork do |server, worker|
...
if defined?(ReadCache.redis)
ReadCache.redis.client.reconnect
end
...
end
【讨论】:
那么,如果我同时有上千个独特的请求,我还需要上千个连接到 redis 服务器,对吧? @Kira 你能解释一下吗。我认为它不需要数千个连接。如果我理解正确,这个模块将是整个应用程序通用的。 这篇文章devcenter.heroku.com/articles/… 有助于了解连接池天气或不使用 Heroku。稍微了解一下,您可以让他们调整您的 sidekiq 并发性,请参阅:github.com/mperham/sidekiq/wiki/…。 @blootto 读得很好,谢谢。虽然,您的示例代码没有使用 ActiveRecord(如果我错了,请纠正我),所以它没有使用池化技术,但我们仍然有每个客户端/工作人员的 redis 连接。 使用Redis.current
,如下@NobodysNightmare 所述。【参考方案3】:
如果你还没有使用另一个 Rails.cache,我建议你只使用 redis 的机制。
gem redis-store 让这变得非常简单 (https://github.com/redis-store/redis-store)
这样你就可以做到Rails.cache.reconnect
,一切都很好
https://github.com/redis-store/redis-store/issues/21#issuecomment-948569
它还允许您使用很棒的 Rails.cache API,它有一些简洁的功能:http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html
【讨论】:
【参考方案4】:一个更命名空间选项来替换你的全局变量,你可以在一个模块中创建一个方法
模块缓存 def self.redis ...在这里初始化/记忆/重新连接... 结尾 结尾然后你调用它:
Caching.redis
【讨论】:
【参考方案5】:试试这个:-
您可以使用constant
代替global variable
.like in
config/initializer/redis.rb
REDIS = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
在 unicorn.rb 中
before_fork do |server, worker|
# clear redis connection
REDIS.quit if defined?(REDIS)
end
#给每个子进程自己的Redis连接
after_fork do |server, worker|
REDIS ||= Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
end
【讨论】:
听起来很有趣,这个常量的作用是什么?我的意思是,它不是全局变量,但它的行为类似于全局变量。【参考方案6】:根据this Heroku,您不需要将$redis
添加到您的独角兽:
将 Redis Cloud 与 Unicorn 服务器一起使用时,无需进行特殊设置。在 Unicorn 上运行 Rails 应用程序的用户应遵循Configuring Redis from Rails 部分中的说明,用户...
这是 Rails 4 之前的所有“Configuring Redis from Rails 部分”(除了 Gemfile 和其他一些之前 Rails 3 的东西):
# config/initalizers/redis.rb
if ENV["REDISCLOUD_URL"]
uri = URI.parse(ENV["REDISCLOUD_URL"])
$redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end
它并没有真正解释为什么“不需要特殊设置”。
【讨论】:
我知道您确实需要做一些特别的事情。我已经使用 unicorn 在生产 heroku 服务器上连接了 512 个 redis 云实例。以上是关于$redis 全局变量与 ruby on rails的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Windows 操作系统的 Ruby on Rails 应用程序中使用 Redis?
如何将 Juggernaut 聊天服务器(由 ruby on rails 提供支持)与 iPhone/Android 应用程序集成以进行实时聊天?