3

私は redis サーバーを持っており、次のことを行うアトミック (または疑似アトミック) メソッドを実装したいと考えています (注意: Redis サーバーへの複数のセッションを持つシステムがあります):

  1. いくつかのキーKが存在する場合、その値を取得します
  2. それ以外の場合は、関数F ( salt を生成する)によって生成されたランダムな値を使用してSETNX 関数を呼び出します。
  3. 現在のセッションによって生成されたばかりのキーKの値を redis に問い合わせます(または、別のセッションによって "同時に" - 現在のセッションが生成する少し前)。

(値が存在するかどうかを確認する前に) 関数Fで値を事前に生成し、キーが存在しない場合はそれを使用したくない理由は次のとおりです。

  1. 正当な理由もなくFを呼び出したくありません(集中的な CPU 動作を引き起こす可能性があります (
  2. 次の問題を回避したい : T1 : セッション 1 がランダムな値VAL1を生成した T2 : セッション 1 がキーKが存在するかどうかを尋ね、「False」を取得した T3 : セッション 2 がランダムな値VAL2を生成した T4 : セッション 2 がキーKが存在する かどうかを尋ねたT5 : セッション 2 は、値VAL2でSETNXを呼び出し、これからVAL2を使用しますT6 : セッション 1 は、値VAL1でSETNXを呼び出し、これからキーKの実際の値がVAL2であるVAL1を使用します

私が作成したpython疑似コードは次のとおりです。

    import redis
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    ''' gets the value of key K if exists (r.get(K) if r.exists(K)), 
    otherwise gets the value of key K if calling SETNX function returned TRUE 
    (else r.get(K) if r.setnx(K,F())), meaning this the sent value is really the value,
    otherwise, get the value of key K, that was generated by another session a         
    short moment ago (else r.get(K))
    The last one is redundant and I can write "**r.setnx(K,F()) or True**" to get the 
    latest value instead, but the syntax requires an "else" clause at the end '''
    r.get(K) if r.exists(K) else r.get(K) if r.setnx(K,F()) else r.get(K)

別の解決策はありますか?

4

1 に答える 1

5

はい、これにはWATCHを使用できます。redis-pyを使用した変更例を次に示します。

def atomic_get_set(some_key):
    with r.pipeline() as pipe:
        try:
            # put a WATCH on the key that holds our sequence value
            pipe.watch(some_key)
            # after WATCHing, the pipeline is put into immediate execution
            # mode until we tell it to start buffering commands again.
            # this allows us to get the current value of our sequence
            if pipe.exists(some_key):
                return pipe.get(some_key)
            # now we can put the pipeline back into buffered mode with MULTI
            pipe.multi()
            pipe.set(some_key, F())
            pipe.get(some_key)
            # and finally, execute the pipeline (the set and get commands)
            return pipe.execute()[-1]
            # if a WatchError wasn't raised during execution, everything
            # we just did happened atomically.
        except WatchError:
            # another client must have changed some_key between
            # the time we started WATCHing it and the pipeline's execution.
            # Let's just get the value they changed it to.
            return pipe.get(some_key)
于 2014-07-16T13:08:28.617 に答える