如何用Redlock实现分布式锁
轉(zhuǎn):https://blog.csdn.net/forezp/article/details/70305336
之前寫過一篇文章《如何在springcloud分布式系統(tǒng)中實(shí)現(xiàn)分布式鎖?》(https://blog.csdn.net/forezp/article/details/68957681),由于自己僅僅是閱讀了相關(guān)的書籍,和查閱了相關(guān)的資料,就認(rèn)為那樣的是可行的。那篇文章實(shí)現(xiàn)的大概思路是用setNx命令和setEx配合使用。 setNx是一個(gè)耗時(shí)操作,因?yàn)樗枰樵冞@個(gè)鍵是否存在,就算redis的百萬的qps,在高并發(fā)的場(chǎng)景下,這種操作也是有問題的。關(guān)于redis實(shí)現(xiàn)分布式鎖,redis官方推薦使用redlock。
一、redlock簡(jiǎn)介
在不同進(jìn)程需要互斥地訪問共享資源時(shí),分布式鎖是一種非常有用的技術(shù)手段。實(shí)現(xiàn)高效的分布式鎖有三個(gè)屬性需要考慮:
1、安全屬性:互斥,不管什么時(shí)候,只有一個(gè)客戶端持有鎖 2、效率屬性A:不會(huì)死鎖 3、效率屬性B:容錯(cuò),只要大多數(shù)redis節(jié)點(diǎn)能夠正常工作,客戶端端都能獲取和釋放鎖。Redlock是redis官方提出的實(shí)現(xiàn)分布式鎖管理器的算法。這個(gè)算法會(huì)比一般的普通方法更加安全可靠。關(guān)于這個(gè)算法的討論可以看下官方文檔(https://github.com/antirez/redis-doc/blob/master/topics/distlock.md)。
二、怎么用java使用 redlock
在pom文件引入redis和redisson依賴:
<!-- redis--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redisson--> <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.3.2</version> </dependency>AquiredLockWorker接口類,,主要是用于獲取鎖后需要處理的邏輯:
/*** Created by fangzhipeng on 2017/4/5.* 獲取鎖后需要處理的邏輯*/ public interface AquiredLockWorker<T> {T invokeAfterLockAquire() throws Exception; }DistributedLocker 獲取鎖管理類:
/*** Created by fangzhipeng on 2017/4/5.* 獲取鎖管理類*/ public interface DistributedLocker {/*** 獲取鎖* @param resourceName 鎖的名稱* @param worker 獲取鎖后的處理類* @param <T>* @return 處理完具體的業(yè)務(wù)邏輯要返回的數(shù)據(jù)* @throws UnableToAquireLockException* @throws Exception*/<T> T lock(String resourceName, AquiredLockWorker<T> worker) throws UnableToAquireLockException, Exception;<T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception;}UnableToAquireLockException ,不能獲取鎖的異常類:
/*** Created by fangzhipeng on 2017/4/5.* 異常類*/ public class UnableToAquireLockException extends RuntimeException {public UnableToAquireLockException() {}public UnableToAquireLockException(String message) {super(message);}public UnableToAquireLockException(String message, Throwable cause) {super(message, cause);} }RedissonConnector 連接類:
/*** Created by fangzhipeng on 2017/4/5.* 獲取RedissonClient連接類*/ @Component public class RedissonConnector {RedissonClient redisson;@PostConstructpublic void init(){redisson = Redisson.create();}public RedissonClient getClient(){return redisson;} }RedisLocker 類,實(shí)現(xiàn)了DistributedLocker:
import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit;/*** Created by fangzhipeng on 2017/4/5.*/ @Component public class RedisLocker implements DistributedLocker{private final static String LOCKER_PREFIX = "lock:";@AutowiredRedissonConnector redissonConnector;@Overridepublic <T> T lock(String resourceName, AquiredLockWorker<T> worker) throws InterruptedException, UnableToAquireLockException, Exception {return lock(resourceName, worker, 100);}@Overridepublic <T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception {RedissonClient redisson= redissonConnector.getClient();RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);// Wait for 100 seconds seconds and automatically unlock it after lockTime secondsboolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);if (success) {try {return worker.invokeAfterLockAquire();} finally {lock.unlock();}}throw new UnableToAquireLockException();} }測(cè)試類:
@AutowiredRedisLocker distributedLocker;@RequestMapping(value = "/redlock")public String testRedlock() throws Exception{CountDownLatch startSignal = new CountDownLatch(1);CountDownLatch doneSignal = new CountDownLatch(5);for (int i = 0; i < 5; ++i) { // create and start threadsnew Thread(new Worker(startSignal, doneSignal)).start();}startSignal.countDown(); // let all threads proceeddoneSignal.await();System.out.println("All processors done. Shutdown connection");return "redlock";}class Worker implements Runnable {private final CountDownLatch startSignal;private final CountDownLatch doneSignal;Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {this.startSignal = startSignal;this.doneSignal = doneSignal;}public void run() {try {startSignal.await();distributedLocker.lock("test",new AquiredLockWorker<Object>() {@Overridepublic Object invokeAfterLockAquire() {doTask();return null;}});}catch (Exception e){}}void doTask() {System.out.println(Thread.currentThread().getName() + " start");Random random = new Random();int _int = random.nextInt(200);System.out.println(Thread.currentThread().getName() + " sleep " + _int + "millis");try {Thread.sleep(_int);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " end");doneSignal.countDown();}}運(yùn)行測(cè)試類:
Thread-48 start Thread-48 sleep 99millis Thread-48 end Thread-49 start Thread-49 sleep 118millis Thread-49 end Thread-52 start Thread-52 sleep 141millis Thread-52 end Thread-50 start Thread-50 sleep 28millis Thread-50 end Thread-51 start Thread-51 sleep 145millis Thread-51 end從運(yùn)行結(jié)果上看,在異步任務(wù)的情況下,確實(shí)是獲取鎖之后才能運(yùn)行線程。不管怎么樣,這是redis官方推薦的一種方案,可靠性比較高。有什么問題歡迎留言。
三、參考資料
https://github.com/redisson/redisson
《Redis官方文檔》用Redis構(gòu)建分布式鎖 : http://ifeve.com/redis-lock/
A Look at the Java Distributed In-Memory Data Model (Powered by Redis) : https://dzone.com/articles/java-distributed-in-memory-data-model-powered-by-r
總結(jié)
以上是生活随笔為你收集整理的如何用Redlock实现分布式锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 史上最简单的 SpringCloud 教
- 下一篇: 大葱青椒西红柿炒肉的做法?