LoginSignup
17
15

More than 5 years have passed since last update.

Redis Sentinel 環境で redis-namespace, sidekiqを動かす

Last updated at Posted at 2013-08-13

この記事は最終更新から1年以上経過しています。 気をつけてね。

Redis Sentinelで構成されたRedisのクラスタ環境はそこそこに複雑です、クライアントはRedisがSentinel環境であることを意識して専用のドライバを使うほうがよいでしょう。

Rubyでよく使うRedisのライブラリ、redis-namespaceSidekiqをRedis Sentinel 環境の環境で使ってみました。


修正情報:sidekiq対応がモンキーパッチでしたが、Sidekiq開発者のPerham氏から直々にツッコミを頂いたので記事を修正。

This is how you should configure Redis Sentinel. Please don't monkeypatch. https://t.co/gKf98gnivd


redis-sentinelというGemがあるので、それを利用することにします。

redis-namespace with redis-sentinel

まずredis-sentinelのサンプルで使い方を確認します。Redis::Clientをオープンしてsentinel関係の設定がうまいことやってくれるようになっていました。テスト環境起動用のコンフィグもついていたのですぐに試せます。

example/test.rb
require 'redis'
require 'redis-sentinel'

redis = Redis.new(:master_name => "example-test",
                  :sentinels => [
                    {:host => "localhost", :port => 26379},
                    {:host => "localhost", :port => 26380}
                  ])
redis.set "foo", "bar"

while true
  begin
    puts redis.get "foo"
  rescue => e
    puts "failed?", e
  end
  sleep 1
end

このサンプルからredis-namespaceを使うようにしたのがこちら。
普段の使い方と通りにRedis Sentinelの環境に適応させることができました。

example/test_name.rb
require 'redis'
require 'redis-namespace'
require 'redis-sentinel'

redis_s = Redis.new(:master_name => "example-test",
                  :sentinels => [
                    {:host => "localhost", :port => 26379},
                    {:host => "localhost", :port => 26380}
                  ])

redis = Redis::Namespace.new(:myspace, :redis => redis_s)
redis.set "foo", "bar"

while true
  begin
    puts redis.get "foo"
  rescue => e
    puts "failed?", e
  end
  sleep 1
end

redis-namespaceに関しては特に考慮なしでよさそうですね。

Sidekiq with redis-sentinel

次はSidekiqです、まずは付属のサンプル。
sinatraのWEBインターフェースからキューして、ワーカに処理させています。

sidekiq/examples/sinkiq.rb
# Make sure you have Sinatra installed, then start sidekiq with
# ./bin/sidekiq -r ./examples/sinkiq.rb
# Simply run Sinatra with
# ruby examples/sinkiq.rb
# and then browse to http://localhost:4567
#
require 'sinatra'
require 'sidekiq'
require 'redis'

$redis = Redis.new

class SinatraWorker
  include Sidekiq::Worker

  def perform(msg="lulz you forgot a msg!")
    $redis.lpush("sinkiq-example-messages", msg)
  end
end

get '/' do
  stats = Sidekiq::Stats.new
  @failed = stats.failed
  @processed = stats.processed
  @messages = $redis.lrange('sinkiq-example-messages', 0, -1)
  erb :index
end

post '/msg' do
  SinatraWorker.perform_async params[:msg]
  redirect to('/')
end

__END__

@@ layout
<html>
  <head>
    <title>Sinatra + Sidekiq</title>
    <body>
      <%= yield %>
    </body>
</html>

@@ index
  <h1>Sinatra + Sidekiq Example</h1>
  <h2>Failed: <%= @failed %></h2>
  <h2>Processed: <%= @processed %></h2>

  <form method="post" action="/msg">
    <input type="text" name="msg">
    <input type="submit" value="Add Message">
  </form>

  <a href="/">Refresh page</a>

  <h3>Messages</h3>
  <% @messages.each do |msg| %>
    <p><%= msg %></p>
  <% end %>

起動コマンド

一応このサンプルの起動コマンドはヘッダに書いてあるとおりこんな感じです。

  • sinatra_web: (bundle exec) ruby ./sidekiq/examples/sinkiq.rb
  • sidekiq_worker: (bundle exec) sidekiq -r ./sidekiq/examples/sinkiq.rb -v

sinatraはlocalhost:4567で起動するので、メッセージをキューしてワーカの出力を見るといいです。

Sentinelを使う

SidekiqをSentinel経由にする方法は Advanced Options | sidekiq wiki にありました。
Redisのインスタンスを自由に設定するやり方を参考に前述のサンプルを変更してみます。

sinkiq_sentinel_with_stat.rb
require 'sinatra'
require 'sidekiq'
require 'redis'
require 'redis-sentinel'

redis_conn = proc {
  Redis.new(:master_name => "example-test",
                  :sentinels => [
                    {:host => "localhost", :port => 26379},
                    {:host => "localhost", :port => 26380}
                  ])
}

Sidekiq.configure_server do |config|
  config.redis = ConnectionPool.new(size: 10, &redis_conn)
end

Sidekiq.configure_client do |config|
  config.redis = ConnectionPool.new(size: 5, &redis_conn)
end

class SinatraWorker
  include Sidekiq::Worker

  def perform(msg="lulz you forgot a msg!")
    $redis.lpush("sinkiq-example-messages", msg)
  end
end

get '/' do
  stats = Sidekiq::Stats.new
  @failed = stats.failed
  @processed = stats.processed
  @messages = $redis.lrange('sinkiq-example-messages', 0, -1)
  erb :index
end

post '/msg' do
  SinatraWorker.perform_async params[:msg]
  redirect to('/')
end

__END__

@@ layout
<html>
<head>
<title>Sinatra + Sidekiq</title>
<body>
<%= yield %>
</body>
</html>

@@ index
<h1>Sinatra + Sidekiq Example</h1>
<h2>Failed: <%= @failed %></h2>
<h2>Processed: <%= @processed %></h2>

<form method="post" action="/msg">
<input type="text" name="msg">
<input type="submit" value="Add Message">
</form>

<a href="/">Refresh page</a>

<h3>Messages</h3>
<% @messages.each do |msg| %>
<p><%= msg %></p>
<% end %>

※初版ではここはモンキーパッチでした、ちゃんとスマートに設定できたようです。

サンプルログ

上記サンプルを使って、sidekiq_workerを (bundle exec) sidekiq -r ./sinkiq_sentinel.rb -vで起動すればStat APIがデータストアにRedis Sentinel環境を使いだします。

ワーカはそれぞれID(@hash)を持っているようなので複数起動しても問題無さ気でした。

マスタ切替時のログはこの様に出力されます。

sidekiq
TID-oxgwckouo INFO: Running in ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.3.0]

TID-oxgwcg8yk ERROR: Error fetching message: Error connecting to Redis on 127.0.0.1:16380 (ECONNREFUSED)

# -- 接続切れた

TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/.rvm/gems/ruby-2.0.0-p247@redis-sentinel/gems/redis-3.0.4/lib/redis/client.rb:276:in `rescue in
TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/.rvm/gems/ruby-2.0.0-p247@redis-sentinel/gems/redis-3.0.4/lib/redis/client.rb:271:in `establish
TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/.rvm/gems/ruby-2.0.0-p247@redis-sentinel/gems/redis-3.0.4/lib/redis/client.rb:69:in `connect'
TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/github/others/redis-sentinel/lib/redis-sentinel/client.rb:25:in `block in connect_with_sentinel
TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/github/others/redis-sentinel/lib/redis-sentinel/client.rb:42:in `call'
TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/github/others/redis-sentinel/lib/redis-sentinel/client.rb:42:in `auto_retry_with_timeout'

# -- redis-sentinel gemによるマスタ再発見まわり

TID-oxgwcg8yk ERROR: /Users/sawanoboriyu/github/others/redis-sentinel/lib/redis-sentinel/client.rb:23:in `connect_with_sentinel'
TID-oxgwevm7g ERROR: The master: example-test is currently not available.
TID-oxgwevm7g ERROR: /Users/sawanoboriyu/github/others/redis-sentinel/lib/redis-sentinel/client.rb:75:in `discover_master'

# -- 復旧

TID-oxgwcg8yk INFO: Redis is online, 16.16007900238037 sec downtime

良い感じに切り替わりましたね。

17
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15