2017-12-20 4 views
0

私たちのプロジェクトでは、redisのincrコマンドを使ってストレージを制限したいと考えています。たとえば、特定の商品Aについては、プロモーション中に10個のみを販売したいと考えています。そこで、incrコマンドを使用して0から10までのストレージ値を追加することを計画しました。理論的には、このシナリオではこの計画は問題ありません。redis incrコマンドは特定の番号に制限されますか?

開始する前に、incrコマンドのパフォーマンステストを行いました。その結果、incrを使用して商品保管庫の制限を行うことは実現できない可能性がありました。以下

テストコード:

static int count = 0; 

public void performanceToken() throws RedisAccessException { 

    long result = redisUtil.incrRedisEx("myrrrxxxrrrediskey6"); 

    if (result <= 10) { 
     count ++; 
    } 

    Struts2Utils.renderJson(result +"|"+count); 
    return; 
} 

incrRedisExはINCRコマンドのラッパーだったと我々は我々のJavaプロジェクトで、私たちのRedisを駆動するドライバとしてjedisを使用しました。

次に、私たちはtomcatを開始し、私たちは上記のインターフェースをブラウザから直接呼び出すことができました。結果は良かったし、ミスも誤りもなかった。

そして、私たちはパフォーマンステストツールjmeterに切り替えました。このツールは、ユーザーからインターフェースを呼び出すという大きなプレッシャーをシミュレートすることができました。私たちは1秒間にインターフェイスを呼び出すための1500リクエストを作成しました。結果は以下の通りです。しかし:まず

、コードは[OK]を働いたと私たちは、商品ストレージがしばらくして10 enter image description here enter image description here

に限定されていた、我々はそのカウント数を見ることができることがわかります制限を破った、それgrowssss! enter image description here

redis incrが偉大なユーザーの要求に基づいてストレージに制限を加えることができない理由がわかりません。誰でも私にそれにライトをつけることができますか?

redis incrのメカニズムに基づいて、incrコマンドを実行した後に新しい値を返します。もしそうなら、数字の増加を止めることができないのは本当に奇妙なことです。

私は、おそらく同時に、incr操作を行うためにredisに送信する2つの操作がありますが、incrコマンドを実行して直接戻ってきます。もう1つは非常に遅くincrを返します。他の要求がすでにincrコマンドを実行していて、良い記憶容量が10に増えているため、増加する数は2ではなく11です。しかし、この説明は正しくはありません。なぜなら、redisは単一スレッドモデルであるからです。

-------- EDIT ----------------

私はスレッドセーフな問題を避けるために、自分のコードを変更:

long result = redisUtil.incrRedisEx("axgggggggggg"); 

    if (result <= 10) { 
     logger.error("==generate==order==result==" + result); 
    } 

    Struts2Utils.renderJson(result); 
    return; 

ログが10回以上書き込まれることがわかりました。

+0

performanceToken'は、複数のスレッド環境で実行 'していますか? –

+0

@for_stackこれはstrutsのアクションです。私はそれをユーザーに公開します。 – CharlieShi

+0

'performanceToken'はスレッドセーフではありません。ユーザーまたはテストコードがこのメソッドを複数のスレッドで呼び出すと、 'count'は10より大きい場合があります。 –

答えて

3

あなたは基本的にシングルスレッドであるように、Redisの自身の中の増分を行うにはほとんどのLuaスクリプトを使用することができます。

127.0.0.1:6379> set CappedInt 7 
OK 
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get 
(integer) 8 
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get 
(integer) 9 
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get 
(integer) 10 
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get 
(integer) 10 

のではなく、スクリプトを入力し、あなたはまた、Luaのを置くことができますファイルにコードは、このようなIncWithCap.luaと呼ば:

local cap=10 
if(redis.call(ARGV[1],KEYS[1])+0 < cap) then 
    return redis.call('INCR',KEYS[1]) 
end 
return cap 

その後、あなたとのRedisにロードすることができます。

redis-cli SCRIPT LOAD "$(cat IncWithCap.lua)" 

サンプル出力

"6e6ad88c9a2b7dfdade9c5763467aaab2358d4e1" 

次にあなたが実行/それを呼び出すことができます。

127.0.0.1:6379> evalsha 6e6ad88c9a2b7dfdade9c5763467aaab2358d4e1 1 CappedInt get 
+0

thx、チームメンバーとのコンバージョンを達成し、問題を把握しました。はい、あなたが言ったように、redis + luaが最良の解決策になるはずです。 – CharlieShi

+0

優秀 - プロジェクトに幸運を祈る。ところで、これが私が書いた最初のルアです。それを表現するより良い方法があるかもしれません。 –

+0

問題ありません。私たちの会社の他のプロジェクトはredis + luaを使用していました。私はそれらから情報を得ることができます。 – CharlieShi

関連する問題