rubyの排他制御ライブラリ(redis-semaphoreの紹介)

June 30, 2014 by Yudai Suzuki

最近仕事でよく知らなかった排他制御について調べたり勉強する機会があって、セマフォを実現するのによさげなライブラリがあったので書く。

dv/redis-semaphore

この辺分かってる人だったらライブラリ名でどんなものだか想像できると思うけど、カウンティングセマフォの資源の操作をredisで行うライブラリである。

使い方

基本的にセマフォのインスタンスを作って排他制御を行いたい処理をブロックで囲むだけでOK。
READMEのコピペで申し訳ない。

# :semaphore_nameはredisにkeyを作成する際のnamespaceになる
s = Redis::Semaphore.new(:semaphore_name, connection: "localhost")
s.lock do
  # 排他制御したい処理
end

資源の数を指定する場合はインスタンスを作成する際に:resourcesを指定する

s = Redis::Semaphore.new(:semaphore_name, resources: 5, connection: "localhost")
s.lock do
  # 排他制御したい処理
end

ブロックじゃなくてインスタンスメソッドでも制御できる。その場合は#unlockを忘れないように注意する。

s = Redis::Semaphore.new(:semaphore_name, resources: 5, connection: "localhost")
s.lock
# 排他制御したい処理
s.unlock

内部で何をやってるのか見てみると、GRABBEDEXISTSAVAILABLEというkey-valueを登録している。

127.0.0.1:6379> keys *
1) "SEMAPHORE:semaphore_name:GRABBED"
2) "SEMAPHORE:semaphore_name:EXISTS"
3) "SEMAPHORE:semaphore_name:AVAILABLE"

127.0.0.1:6379> type SEMAPHORE:semaphore_name:GRABBED
hash
127.0.0.1:6379> type SEMAPHORE:semaphore_name:EXISTS
string
127.0.0.1:6379> type SEMAPHORE:semaphore_name:AVAILABLE
list

AVAILABLEは資源の数がlist型で登録され、例えばresources: 2でinitializeした場合"0""1"が登録される。

127.0.0.1:6379> lindex SEMAPHORE:semaphore_name:AVAILABLE 0
"0"
127.0.0.1:6379> lindex SEMAPHORE:semaphore_name:AVAILABLE 1
"1"

GRABBED#lockしたタイミングで資源をhash型で登録し、AVAILABLEからblpopした値をkey、valにタイムスタンプを登録してる。 ちなみに、#lockの際に引数で数値を入れるとblpopする際のタイムアウトの数値になる。

127.0.0.1:6379> hkeys SEMAPHORE:semaphore_name:GRABBED
1) "0"
127.0.0.1:6379> hget SEMAPHORE:semaphore_name:GRABBED "0"
"1404128562.538218"

EXISTSはとりあえず登録してる感じかな?ちょっとよくわかんないです。
API_VERSIONという定数を登録してる。

127.0.0.1:6379> get SEMAPHORE:semaphore_name:EXISTS
"1"

で、#unlockが呼ばれたタイミングでGRABBEDhdelし、AVAILABLElpushしている。
redisのデータ型をうまく使った実装になっている。

https://github.com/dv/redis-semaphore/blob/master/lib/redis/semaphore.rb#L87-L94

    def signal(token = 1)
      token ||= generate_unique_token

      @redis.multi do
        @redis.hdel grabbed_key, token
        @redis.lpush available_key, token
      end
    end

雑な紹介でした。

© 2017 | Onigra | Powerd by Hucore theme & Hugo