ホームページ データベース Redis Redis を使用して分散ロックを実装する方法

Redis を使用して分散ロックを実装する方法

Jul 05, 2019 pm 04:45 PM

Redis を使用して分散ロックを実装する方法

Redis を使用して分散ロックを実装する

redis 機能の紹介

1. String、List、Map などの豊富なデータ型をサポートします。 、セット、ZSet など。

2. RDB メソッドと AOF メソッドの両方でデータ永続性をサポート

3. クラスター動作モード、強力なパーティションフォールトトレランスをサポート

4. シングルスレッド、コマンドの順次処理

5. トランザクションのサポート

6. パブリケーションとサブスクリプションのサポート

Redis は、SETNX コマンドを使用して分散ロックを実装します:

SETNX キー値

キーが存在しない場合にのみ、キーの値を value に設定します。

指定されたキーがすでに存在する場合、SETNX は何もアクションを実行しません。

SETNX は「SET if Not eXists」(存在しない場合は SET) の略です。

利用可能なバージョン: >= 1.0.0 時間計算量: O(1) 戻り値:

設定が成功すると、1 を返します。

設定できませんでした。0 を返します。

redis> EXISTS job                # job 不存在
(integer) 0

redis> SETNX job "programmer"    # job 设置成功
(integer) 1

redis> SETNX job "code-farmer"   # 尝试覆盖 job ,失败
(integer) 0

redis> GET job                   # 没有被覆盖
"programmer"
ログイン後にコピー

まず、パブリック Redis アクセス ツール クラスをカプセル化する必要があります。このクラスは、RedisTemplate インスタンスと ValueOperations インスタンスを注入する必要があります。Redis によって実装される分散ロックは最も単純な String 型を使用するため、ValueOperations インスタンスが使用されます。さらに、setIfObsent (文字列キー、文字列値)、expire (文字列キー、長いタイムアウト、TimeUnit 単位)、および delete (文字列キー) という 3 つのメソッドをカプセル化する必要があります。これらは、SETNX、expire、および del コマンドに対応します。それぞれRedisの。 Redis アクセス ツール クラスの具体的な実装は次のとおりです。

@Component
public class RedisDao {

	@Autowired
	private RedisTemplate redisTemplate;
	
	@Resource(name="redisTemplate")
	private ValueOperations<Object, Object> valOpsObj;
	
	/**
	 * 如果key不存在,就存储一个key-value,相当于SETNX命令
	 * @param key      键
	 * @param value    值,可以为空
	 * @return
	 */
	public boolean setIfObsent (String key, String value) {
		return valOpsObj.setIfAbsent(key, value);
	}
	
	/**
	 * 为key设置失效时间
	 * @param key       键
	 * @param timeout   时间大小
	 * @param unit      时间单位
	 */
	public boolean expire (String key, long timeout, TimeUnit unit) {
		return redisTemplate.expire(key, timeout, unit);
	}
	
	/**
	 * 删除key
	 * @param key 键
	 */
	public void delete (String key) {
		redisTemplate.delete(key);
	}
}
ログイン後にコピー

Redis アクセス ツール クラスの実装が完了したら、次に考慮する必要があるのは、分散ロックの競合をシミュレートする方法です。 Redis 自体は分散クラスターをサポートしているため、マルチスレッド処理のビジネス シナリオをシミュレートするだけで済みます。スレッド プールはここでシミュレーションに使用されます。テスト クラスの具体的な実装は次のとおりです:

@RestController
@RequestMapping("test")
public class TestController {

	private static final Logger LOG = LoggerFactory.getLogger(TestController.class);  //日志对象
	@Autowired
	private RedisDao redisDao;
	//定义的分布式锁key
	private static final String LOCK_KEY = "MyTestLock";
	
	@RequestMapping(value={"testRedisLock"}, method=RequestMethod.GET)
	public void testRedisLock () {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		for (int i = 0; i < 5; i++) {
			executorService.submit(new Runnable() {
				@Override
				public void run() {
				    //获取分布式锁
					boolean flag = redisDao.setIfObsent(LOCK_KEY, "lock");
					if (flag) {
						LOG.info(Thread.currentThread().getName() + ":获取Redis分布式锁成功");
						//获取锁成功后设置失效时间
						redisDao.expire(LOCK_KEY, 2, TimeUnit.SECONDS);
						try {
							LOG.info(Thread.currentThread().getName() + ":处理业务开始");
							Thread.sleep(1000); //睡眠1000ms模拟处理业务
							LOG.info(Thread.currentThread().getName() + ":处理业务结束");
							//处理业务完成后删除锁
							redisDao.delete(LOCK_KEY);
						} catch (InterruptedException e) {
							LOG.error("处理业务异常:", e);
						}
					} else {
						LOG.info(Thread.currentThread().getName() + ":获取Redis分布式锁失败");
					}
				}
			});
		}
	}
}
ログイン後にコピー

上記のコードを通じて、次の疑問が生じる可能性があります:

スレッドが分散ロック、ロックを再取得してみませんか?

スレッドは分散ロックを正常に取得した後、ロックの有効期限を設定します。有効期限はどのように決定されますか?

スレッドのビジネス処理が完了した後、なぜロックを削除する必要があるのでしょうか?

これらの質問について話し合うことができます。

まず、キーがすでに存在する場合、Redis の SETNX コマンドは操作を実行しないため、SETNX によって実装される分散ロックはリエントラント ロックではありません。もちろん、コードを通じて、または分散ロックが取得されるまで n 回再試行することもできます。ただし、これは公正な競争を保証するものではなく、スレッドはロックを待機しているためにブロックされます。したがって、Redis によって実装された分散ロックは、共有リソースが 1 回書き込まれ、複数回読み取られるシナリオにより適しています。

2 番目に、分散ロックには有効期限を設定する必要があり、その有効期限は (データの整合性を確保するため) ビジネス処理に必要な時間より長くする必要があります。そのため、テスト段階では、通常の業務処理にかかる時間をできるだけ正確に予測し、業務処理プロセスにおける何らかの原因によるデッドロックを防ぐために有効期限を設定する必要があります。

第三に、業務処理が完了したら、ロックを削除する必要があります。

上記の分散ロックの設定とロックの有効期限の設定は 2 つの手順で完了しますが、より合理的な方法は、分散ロックの設定とロックの有効期限の設定を 1 回の操作で行うことです。両方とも成功するか、両方とも失敗するかのどちらかです。実装コードは次のとおりです:

/**
* Redis访问工具类
*/
@Component
public class RedisDao {

	private static Logger logger = LoggerFactory.getLogger(RedisDao.class);
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	
	/**
	 * 设置分布式锁    
	 * @param key     键
	 * @param value   值
	 * @param timeout 失效时间
	 * @return
	 */
	public boolean setDistributeLock (String key, String value, long timeout) {
		RedisConnection connection = null;
		boolean flag = false;
		try {
			//获取一个连接
			connection = stringRedisTemplate.getConnectionFactory().getConnection();
			//设置分布式锁的同时为锁设置失效时间
			connection.set(key.getBytes(), value.getBytes(), Expiration.seconds(timeout), RedisStringCommands.SetOption.SET_IF_ABSENT);
			flag = true;
		} catch (Exception e) {
			logger.error("set automic lock error:", e);
		} finally {
			//使用后关闭连接
			connection.close();
		}
		return flag;
	}
	
	/**
	 * 查询key的失效时间
	 * @param key       键
	 * @param timeUnit  时间单位
	 * @return
	 */
	public long ttl (String key, TimeUnit timeUnit) {
		return stringRedisTemplate.getExpire(key, timeUnit);
	}
}

/**
* 单元测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo1ApplicationTests {

	private static final Logger LOG = LoggerFactory.getLogger(Demo1ApplicationTests.class);
		
	@Autowired
	private RedisDao redisDao;
	
	@Test
	public void testDistributeLock () {
		String key = "MyDistributeLock";
		//设置分布式锁,失效时间20s
		boolean result = redisDao.setDistributeLock(key, "1", 20);
		if (result) {
			LOG.info("设置分布式锁成功");
			long ttl = redisDao.ttl(key, TimeUnit.SECONDS);
			LOG.info("{}距离失效还有{}s", key, ttl);
		}
	}
}
ログイン後にコピー

単体テスト クラスを実行すると、結果は次のようになります:

2019-05-15 13:07:10.827 - 设置分布式锁成功
2019-05-15 13:07:10.838 - MyDistributeLock距离失效还有19s
ログイン後にコピー

Redis 関連の知識の詳細については、Redis の使用方法のチュートリアルを参照してください## # カラム!

以上がRedis を使用して分散ロックを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Redisクラスターでシャードキーを選択するにはどうすればよいですか? Redisクラスターでシャードキーを選択するにはどうすればよいですか? Mar 17, 2025 pm 06:55 PM

この記事では、Redisクラスターでシャードキーを選択し、パフォーマンス、スケーラビリティ、データ分布への影響を強調しています。重要な問題には、データ分布の確保、アクセスパターンの調整、一般的な間違いの回避lが含まれます。

Redisで認証と承認を実装するにはどうすればよいですか? Redisで認証と承認を実装するにはどうすればよいですか? Mar 17, 2025 pm 06:57 PM

この記事では、Redisでの認証と承認の実装について説明し、ACLSを使用し、Redisを保護するためのベストプラクティスの有効化に焦点を当てています。また、Redisセキュリティを強化するためのユーザー許可とツールの管理をカバーしています。

ジョブキューとバックグラウンド処理にRedisを使用するにはどうすればよいですか? ジョブキューとバックグラウンド処理にRedisを使用するにはどうすればよいですか? Mar 17, 2025 pm 06:51 PM

この記事では、ジョブキューとバックグラウンド処理にRedisを使用し、セットアップ、ジョブの定義、実行の詳細を使用しています。アトミックオペレーションやジョブの優先順位付けなどのベストプラクティスをカバーし、Redisが処理効率を高める方法を説明します。

Redisでキャッシュ無効化戦略を実装するにはどうすればよいですか? Redisでキャッシュ無効化戦略を実装するにはどうすればよいですか? Mar 17, 2025 pm 06:46 PM

この記事では、時間ベースの有効期限、イベント駆動型の方法、バージョン化など、Redisでキャッシュの無効化を実装および管理するための戦略について説明します。また、キャッシュの有効期限と監視とオートマットのツールのベストプラクティスもカバーしています

Redisクラスターのパフォーマンスを監視するにはどうすればよいですか? Redisクラスターのパフォーマンスを監視するにはどうすればよいですか? Mar 17, 2025 pm 06:56 PM

記事では、Redis CLI、Redis Insight、DatadogやPrometheusなどのサードパーティソリューションなどのツールを使用して、Redisクラスターのパフォーマンスと健康を監視しています。

Pub/SubメッセージングにRedisを使用するにはどうすればよいですか? Pub/SubメッセージングにRedisを使用するにはどうすればよいですか? Mar 17, 2025 pm 06:48 PM

この記事では、Pub/サブメッセージング、セットアップ、ベストプラクティスのカバー、メッセージの信頼性の確保、監視のパフォーマンスにRedisを使用する方法について説明します。

Webアプリケーションのセッション管理にRedisを使用するにはどうすればよいですか? Webアプリケーションのセッション管理にRedisを使用するにはどうすればよいですか? Mar 17, 2025 pm 06:47 PM

この記事では、Webアプリケーションでのセッション管理にRedisを使用すること、セットアップの詳細、スケーラビリティやパフォーマンスなどの利点、セキュリティ対策について説明します。

共通の脆弱性に対してRedisを保護するにはどうすればよいですか? 共通の脆弱性に対してRedisを保護するにはどうすればよいですか? Mar 17, 2025 pm 06:57 PM

記事では、強力なパスワード、ネットワークバインディング、コマンドの無効化、認証、暗号化、更新、監視に焦点を当てた脆弱性に対するRedisの保護について説明します。

See all articles