redisによる分散トランザクション・ロックの実現により、高同時環境での在庫削減を解決
7060 ワード
問題の説明:
ある電子商取引プラットフォームでは、新製品の携帯電話を発売し、1人当たり2台の購入を制限し、10 Wの同時販売が予想されている.
ソリューション1
データベース・ロック・メカニズムを使用して、レコードをロックし、操作します.
SELECT * from goods where ID =1 for update;
UPDATE goods set stock = stock - 1;
排他ロックを使用してパラレルをシリアル・オペレーションに変換しますが、このスキームのパフォーマンスとユーザー・エクスペリエンスは低下します.
ソリューション2
redisを利用して分散ロックを実現し、
setnxコマンド(keyが存在しない場合はvalueが1を返し、keyが存在する場合は0を返す)を使用してロックを取得します.ビジネスロジックでは、このようなスキームで操作できます.
Jedis client = jedisPool.getResource();
while(client.setnx("lock",String.valueOf(System.currentTimeMillis())) == 0){
Thread.sleep(10000);
}
//coding here
client.del("lock")
シナリオ2段階
デッドロックの問題、すなわち既成Aがロックを取得した後、ダウンタイムになり、ロックが解放されなくなったことを考慮して、getコマンドでロックのタイムスタンプを取得し、タイムアウト判断を行い、解放することができます.
Long TIMEOUT_SECOUND = 120000L;
Jedis client = jedisPool.getResource();
while(client.setnx("lock",String.valueOf(System.currentTimeMillis())) == 0){
Long lockTime = Long.valueOf(client.get("lock"));
if (lockTime!=null && System.currentTimeMillis() > lockTime+TIMEOUT_SECOUND) {
client.del("lock");
}
Thread.sleep(10000);
}
...........................
...........................
client.del("lock")
方案二強化
スキーム2のアルゴリズムでは,非タイムアウトの場合,ロックがロックされたスレッドのみで解放されることを確保するためにvalueのタイムスタンプにスレッド特徴コードを綴ることができる.
Long TIMEOUT_SECOUND = 120000L;
String featureCode = "machine01";
Jedis client = jedisPool.getResource();
while(client.setnx("lock",featureCode+":"+String.valueOf(System.currentTimeMillis())) == 0){
Long lockTime = Long.valueOf(client.get("lock").substring(9));
if (lockTime!=null && System.currentTimeMillis() > lockTime+TIMEOUT_SECOUND) {
client.del("lock");
}
Thread.sleep(10000);
}
...........................
...........................
if (featureCode.equals(client.get("lock").substring(0, 8))) {
client.del("lock");
}