ホームページ  >  記事  >  データベース  >  Redis における共通分散ロックの原則と実装 (概要共有)

Redis における共通分散ロックの原則と実装 (概要共有)

WBOY
WBOY転載
2022-08-25 11:53:502428ブラウズ

推奨学習: Redis ビデオ チュートリアル

Java のロックには、主に同期ロックと JUC パッケージのロックが含まれます。これらはすべて単一の JVM インスタンス上のロックに関するものであり、分散環境では無効です。では、分散ロックを実装するにはどうすればよいでしょうか?

一般的な分散ロックの実装は次のとおりです:

データベースに基づく

悲観的ロック

悲観的ロック (悲観的ロック) は、その名前が示すように、非常に悲観的なロックであり、データを取得するたびにロックされます。このようにして、悲観的ロックが解放されるまでデータを取得しようとする他のユーザーはブロックされます。悲観的ロック内の共有リソースは一度に 1 つのスレッドによってのみ使用され、他のスレッドはブロックされます。使用後、リソースはただし、効率の点で、ロック機構の処理は追加のオーバーヘッドを生成し、デッドロックが発生しやすくなります。

実装原則

ペシミスティック同時実行制御は、実際には「最初にロックを取得してからアクセスする」という保守的な戦略であり、データ処理のセキュリティを保証します。

具体的な実装

##たとえば、悲観的ロックを通じて在庫控除を実現する擬似コードは次のとおりです。

// 对于库存记录进行行锁

SELECT *FROM sys_goods s WHERE s.Id='1' FOR UPDATE;

//执行库存扣减
update sys_stock s set s.stockQty=s.stockQty-#{number} where s.goodId=1 and s.stockQty>0;

//提交事务,自动释放悲观锁。

楽観的ロック

はじめに

オプティミスティック ロックは、データ バージョン番号 (バージョン) メカニズムに基づいて実装されます。データベース テーブルに「バージョン」フィールドを追加します。データを読み取るときに、このバージョン番号が読み出されます。更新プロセス中にバージョン番号が比較されます。それらが一致していれば、操作は正常に実行され、バージョン番号が表示されます。 1. バージョン番号が一致しない場合、アップデートは失敗します。

実装原理

悲観的ロックと比較すると、楽観的ロックの実装はデータベースのロック機構を使用しません。楽観的ロックの原理は CAS 機構を使用して実装されます。CAS (比較-

    1,
  • 比較: 値 A を読み取り、それを B に更新する前に、次のことを確認します。元の値は A のままです (他のスレッドによって変更されていません)
  • 2.
  • Settings: 変更が送信されない場合は、A を B に更新して終了します。変化が起こっても何もしません。
具体的な実装

たとえば、在庫控除を実装するためのオプティミスティック ロックの疑似コードは次のとおりです。

// 查询库存记录,获取版本号
SELECT stockQty,version FROM sys_goods s WHERE s.Id='1'

//执行库存扣减,防止出现超卖
update sys_stock s set 
  s.stockQty=s.stockQty-#{number},
  s.version=version+1
  where s.goodId=1 and s.stockQty>0 and version=#{version};

Redis は分散型を実装します。 lock

Redis 分散ロックの実装については以前の記事で説明しています。次の記事を参照してください。

Spring Boot は Redis 分散ロックの原理を実装します

Spring Boot統合 分散ロックを実装する Redisson の詳細なケース

Zooker の分散ロックの実装

Zookper は、主に Zookeeper ノードの一時的かつ秩序立った性質を適用することによって、分散ロックを実装します。

ロック プロセス

クライアント 1 が要求すると、Zookeeper クライアントは永続ノードの Locks ノードを作成します。クライアント 1 がロックを取得したい場合は、locks ノード/の下に一時的なノードを作成します。 node_000000 で、ロックの下に一時的に順序付けされた子ノードがすべて見つかった場合、最小のノードである場合、ロックの取得に成功します。

クライアント 2 がロックを取得しようとすると、ロック下の一時ノードもチェックして、自身のノード/node_000001 が最小かどうかを判断します。最小の場合、ロックの取得に失敗します。クライアント 2 は、最上位のノード node_000000 に監視イベントを登録し、node_000000 の存在を監視します。ロックの取得は失敗しますが、node_000001 は待機状態になります。

ロックを解放するプロセス

Zookeeper クライアント サービスが完了するか、クライアントが失敗すると、一時ノードが削除され、ロックが解除されます。解放されました。タスクが完了すると、クライアント 1 は、node_000000 を削除する命令も明示的に呼び出します。

たとえば、上の図では、クライアント 1 が切断され、一時ノード node_000000 が削除されています。このとき、ウォッチャーを通じて、node_000001 が自身を最小の一時ノードとして認識します。監視しているため、ロックが成功します。

异常场景分析

客户端1创建临时节点后,会与Zookeeper服务器维护一个Session,这个Session会依赖客户端 定时心跳来维持连接。由于网路异常原因,Zookeeper长时间收不到客户端1的心跳,就认为这个Session过期了,也会把这个临时节点删除,此时客户端2创建临时节点能够获取锁成功。当客户端网络恢复正常后,它仍然认为持有锁,此时就会造成锁冲突。

具体实现

Zookeeper实现分布式锁,可以采用Curator实现分布式锁,关于SpringBoot如何集成Curator,大家可以参考如下文章:

Java Spring Boot 集成Zookeeper

Zookpeer实现分布式锁实现库存扣减

 @RequestMapping("/lockStock")
    public void lockStock()
    {
       zooKeeperUtil.lock("/Locks", 1000, TimeUnit.SECONDS, ()->{
           //业务逻辑
       });
    }

小结:

关于分布式锁的实现的对比,详情请查看下图:

推荐学习:Redis视频教程

以上がRedis における共通分散ロックの原則と実装 (概要共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjb51.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。