谈谈谈谈Redis分布式锁的正确实现方法分布式锁的正确实现方法
前言前言
最近在参加学校安排的实训任务,我们小组需完成一套分布式&微服务跨境电商,虽然这题目看起来有点老套,并且队友多是
Java 技术栈,所以我光荣(被迫)
的成为了一名前端,并顺路使用 PHP 的 Swoole 帮助负责服务器端的同学编写了几个微服务模块。在小组成员之间的协作
中,还是出现了不少有趣的火花。
在昨天 review 队友代码的过程中,发现了我们组分布式锁的写法似乎有点问题,实现代码如下:
加锁部分
解锁部分
主要原理是使用了 redis 的 setnx 去插入一组 key-value,其中 key 要上锁的标识(在项目中是锁死用户 userId),如果上锁
失败则返回 false。但是根据二段锁的思路,仔细思考会存在这么一个有趣的现象:
假设微服务 A 的某个请求对 userId = 7 的用户上锁,则微服务 A 的这个请求可以读取这个用户的信息,且可以修改其内容 ;
其他模块只能读取这个用户的信息,无法修改其内容。
假设微服务 A 的当前请求对 userId = 7 的用户解锁,则所有模块可以读取这个用户的信息,且可以修改其内容
如此一来:
若微服务模块 A 接收到另一个需要修改 userId = 7 的用户 的请求时,假设这个用户还在被锁状态下,这次请求可以修改它
吗?(可以,解个锁就行)
若微服务模块 B 接收到另一个需要修改 userId = 7 的用户 的请求时,假设这个用户还在被锁状态下,这次请求可以修改它
吗?(可以,解个锁就行)
若微服务模块 A 执行上锁的请求中途意外崩掉,其他用户还能修改信息吗? (可以,解个锁就行)
很明显,这三点并不是我们所希望的。那么如何实现分布式锁才是最佳实践呐?
一个好的分布式锁需要实现什么一个好的分布式锁需要实现什么
由某个模块的某次请求上锁,并且只有由这个模块的这次请求解锁(互斥,只能有一个微服务的某次请求持有锁)