redis-mutexで排他制御

例えばサーバが2台あったとして同じ時間に全く同じ内容のcronスクリプトが実行されるとする、その処理がDBのバッチ処理など大きなコストを必要とするなら両方のサーバで実行されるのは無駄でしかないし場合によってはデータの不整合なども発生するかもしれない。そんな時はredis-mutexを使って排他制御を行うことができる。

なにはともあれredisをインストール ※Macの場合のインストール方法です

$ brew install redis

redis-mutexというgemをインストール。

$ gem install redis-mutex
Successfully installed redis-mutex-2.1.1

排他制御を行いたい部分をRedis::Mutex.with_lockブロックで囲むだけでOK、簡単ですね。

#!/usr/bin/env ruby

require 'redis-mutex'

def main
  Redis::Classy.db = Redis.new(host:"localhost", port: "6379")

  Redis::Mutex.with_lock(:your_lock_name, block: 0) do
    sleep 5
    puts "Do exclusively!"
  end
rescue
  puts 'failed to acquire lock!'
end

if __FILE__ == $0
  main()
end

このスクリプトをコンソールを2つ開いてそれぞれ実行すると最初に実行したほうだけwith_lockブロックで囲んだコードが実行されます。

# 1番目に実行
$ ./redis-mutex-example.rb
Do exclusively!

# 2番目に実行
$ ./redis-mutex-example.rb
failed to acquire lock!

実装にはredisのSETNXとSETEXを使っていると思われる。redisはrebuld.fmでredis-mutexの作者の江島さんが言ってたようにサーバの垣根をも超えたスーパーグローバル変数みたいな感じの使い方ができるし、リアルタイムランキングの実装にも向いてるし、RDBMSではちょっとやりにくい部分をうまく補ってくれるツールな感じ。AWSのElasticacheでもサポートされて今後どんどん伸びていきそうなKVSですね。