分析redis实现分布式锁的思路
文章目录
- 1、基于redis实现分布式锁:利用key的唯一性
- 1.1、独占排他
- 1.2、死锁问题
- 1.2.1、redis客户端程序获取了锁之后,服务器立马宕机,就会导致死锁。
- 1.2.2、不可重入:可重入
- 1.3、原子性:加锁和过期之间:set k v nx ex 3
- 1.4、防误删:给锁添加 uuid 唯一标识
- 1.5、可重入锁:
- 2、代码实现一个基本分布式锁
- 2.1、AlbumInfoApiController --》testLock()
- 2.2、AlbumInfoServiceImpl --》testLock()
- 3、分布式锁程序存在的问题及测试
- 3.1、AlbumInfoServiceImpl --》testLock()
1、基于redis实现分布式锁:利用key的唯一性
1.1、独占排他
1.2、死锁问题
1.2.1、redis客户端程序获取了锁之后,服务器立马宕机,就会导致死锁。
解决方案:给锁添加过期时间,时间到了自动释放锁。
1.2.2、不可重入:可重入
1.3、原子性:加锁和过期之间:set k v nx ex 3
判断和删除之间:lua 脚本。
1.4、防误删:给锁添加 uuid 唯一标识
先判断是否是自己的锁,如果是才能删除。
1.5、可重入锁:
锁操作:加锁、解锁、自旋
2、代码实现一个基本分布式锁
2.1、AlbumInfoApiController --》testLock()
@Tag(name = "专辑管理")
@RestController
@RequestMapping("api/album/albumInfo")
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoApiController {@GetMapping("test/lock")public Result testLock() {this.albumInfoService.testLock();return Result.ok("测试分布式锁案例");}}
2.2、AlbumInfoServiceImpl --》testLock()
@Overridepublic void testLock(){// 加锁Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", "111");if (!lock) {try {// 获取锁失败,进行自旋Thread.sleep(50);this.testLock();} catch (InterruptedException e) {throw new RuntimeException(e);}}// 获取锁成功,执行业务Object numObj = this.redisTemplate.opsForValue().get("num");if (numObj == null) {this.redisTemplate.opsForValue().set("num", 1);return;}Integer num = Integer.parseInt(numObj.toString());this.redisTemplate.opsForValue().set("num", ++num);// 解锁this.redisTemplate.delete("lock");}
启动多个运行实例:
redis中的值重新改为0。
[root@localhost ~]# ab -n 5000 -c 100 http://192.168.74.1:8500/api/album/albumInfo/test/lock
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.74.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requestsServer Software:
Server Hostname: 192.168.74.1
Server Port: 8500Document Path: /api/album/albumInfo/test/lock
Document Length: 76 bytesConcurrency Level: 100
Time taken for tests: 16.625 seconds
Complete requests: 5000
Failed requests: 577(Connect: 0, Receive: 0, Length: 577, Exceptions: 0)
Write errors: 0
Total transferred: 2352885 bytes
HTML transferred: 382885 bytes
Requests per second: 300.75 [#/sec] (mean)
Time per request: 332.506 [ms] (mean)
Time per request: 3.325 [ms] (mean, across all concurrent requests)
Transfer rate: 138.21 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 3 2.6 2 38
Processing: 11 306 566.7 92 6553
Waiting: 10 305 566.7 92 6552
Total: 11 308 567.5 95 6560Percentage of the requests served within a certain time (ms)50% 9566% 18875% 31880% 42490% 83795% 140598% 219099% 2905100% 6560 (longest request)
3、分布式锁程序存在的问题及测试
3.1、AlbumInfoServiceImpl --》testLock()
@Overridepublic void testLock(){// 加锁Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", "111");if (!lock) {try {// 获取锁失败,进行自旋Thread.sleep(50);this.testLock();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {// 获取锁成功,执行业务Object numObj = this.redisTemplate.opsForValue().get("num");if (numObj == null) {this.redisTemplate.opsForValue().set("num", 1);return;}Integer num = Integer.parseInt(numObj.toString());this.redisTemplate.opsForValue().set("num", ++num);// 解锁this.redisTemplate.delete("lock");}}
启动多个运行实例:
redis中的值重新改为0。
[root@localhost ~]# ab -n 5000 -c 100 http://192.168.74.1:8500/api/album/albumInfo/test/lock
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.74.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requestsServer Software:
Server Hostname: 192.168.74.1
Server Port: 8500Document Path: /api/album/albumInfo/test/lock
Document Length: 76 bytesConcurrency Level: 100
Time taken for tests: 46.550 seconds
Complete requests: 5000
Failed requests: 683(Connect: 0, Receive: 0, Length: 683, Exceptions: 0)
Write errors: 0
Total transferred: 2353415 bytes
HTML transferred: 383415 bytes
Requests per second: 107.41 [#/sec] (mean)
Time per request: 931.003 [ms] (mean)
Time per request: 9.310 [ms] (mean, across all concurrent requests)
Transfer rate: 49.37 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 2 5.0 1 58
Processing: 5 892 2805.1 13 43782
Waiting: 5 892 2805.1 13 43781
Total: 5 894 2805.7 14 43785Percentage of the requests served within a certain time (ms)50% 1466% 13475% 44180% 80490% 242895% 446998% 903799% 13259100% 43785 (longest request)