redis集群,原理是因为redis单线程串行处理.
(1). SETNX方案:
①. SETNX(Set if not exists):
a. 命令在指定的key不存在时,为key设置指定的值.
b. SETNX Key Value设置成功,返回1.设置失败,返回0.
c. 没有有效期的
②. 原子操作(多个执行命令):
Multi
SETNX Key Value
expire key seconds // 设置失效时间
exec
③. 两条命令要求是原子操作:
a. 如果有可能会某一条命令失败,如expire失败了,这把锁就没有有效期,就会变成死锁.
b. 要求是要么都成功、要么都失败.
c. redis把原子性的操作变成一个lua脚本.
④. 弊端:
a. Multi不检查语义本身,导致后果是有可能一个命令执行失败.
(1). set name 'david'
incr name // 报错了,但是multi还是会执行成功.
b. 事务是不严谨的.
(2). set方案:
①. set key value NX PX milliseconds:
a. 命令在指定的key不存在时,为key设置指定的值,并设置生存时间.
②. 弊端 - 单机redis一般不会开持久化:
a. 在用户1拿到锁的时候,这个锁还没有释放,突然进程挂了.
b. 马上redis重启,内存是空的.
c. 此时,用户2又可能拿到同一把锁,存在同一把锁会被拿多次的情况.
③. 改进 - 分布式redis:
a. 一台主节点、一台从节点,主从是异步来同步数据的(不是同步的过程).
b. 用户A在主节点加锁后,会在一定时间内同步到从节点.
c. 在用户B访问时,主节点挂了,从节点会成为主节点,再去拿同一把锁,发现是存在的.
④. 疑问?
a. 当主节点锁还没有同步过从节点时,主节点挂了.
b. 此时,从节点升级为主节点,还是会产生同一把锁被拿多次的情况.
⑤. 深层次挖掘:
a. 因为锁只有能一个,所以是CP模型.
b. redis主从分布式来实现这个锁,它的模型是AP模型.
(1). 主从缓存走的是吞吐量.
c. 总结:
(1). 这个锁是CP模型,但是用的redis主从是AP模型.
(2). 所以,最终还是会达到一个锁拿两次的情况.
①. 短信消息场景(AP模型):
a. 利用分布式锁来对消息去重,比如发一个短信,没有锁住,重复又发了一次.
b. 只是说体验不是太好,目的最终还是达到了.
②. 交易的场景(CP模型):
a. 重复转了两次,肯定是业务不能接受的.
③. 总结:
a. 业务的容忍度决定架构的设计.
(1). 中间件对比:
redis zookeeper etcd
一致性算法 无 paxos raft
CAP AP CP CP
高可用 主从 N+1可用 N + 1可用
接口类型 客户端 客户端 http/grpc
实现 setNX createEphemeral restful api
zookeeper对锁实现使用创建临时节点和watch机制,并发执行效率、扩展能力、社区活跃度等方面低于etcd.