分布式事务锁

1.redis实现分布式事务锁

为什么可以用redis实现分布式事务所,因为redis是单进程单线程执行的的程序。

SETNX命令(SET if Not eXists)
语法:
SETNX key value
功能:
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

GETSET命令
语法:
GETSET key value
功能:
将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回nil。

GET命令
语法:
GET key
功能:
返回 key 所关联的字符串值,如果 key 不存在那么返回特殊值 nil 。

DEL命令
语法:
DEL key [KEY …]
功能:
删除给定的一个或多个 key ,不存在的 key 会被忽略。

通过redis这四个命令实现分布式事务锁

服务器A,服务器B

方案一

服务器A访问某个事务

执行SETNX("KEY","A")

成功则获得锁,执行业务方法,否则等待重试。

业务方法执行完毕后就执行DEL("KEY")

真的这么简单就实现了吗?

假如说服务器A执行了SETNX,在执行业务时down机了。此时不久造成死锁了。

优化方案二

服务器A通过GET("KEY")获取值

假如说是NULL,则执行SETNX("KEY",curr_time)获得锁。

否则判断值+超时时间(需要设置业务处理超时时间)小于当前时间

如果大于则回到第一步(最好等待一段时间),否则执行GETSET("KEY",curr_time)获得锁。

执行业务

执行完毕DEL("A")

解决了down机问题,假如down机超时了,就会自动强制获得锁。

新问题,假如说服务器A通过GET获得了锁,此时B也拿到了。A与B分别都判断通过了,执行GETSET同时获得了锁。

优化方案三

在执行GETSET时,将获取出来的值与上次GET的值进行对比,是否一致,假如一致,则获得锁,继续执行。否则回到第一步。

这里就解决了同时获得锁的问题。

存在新问题,假如说服务器A执行业务时超时了,然而实际上并没有超时。此时服务器B强行拿到锁,服务器A还行执行业务,B又进来了。就会出现问题。这个无法避免,需要运维人员合理配置好超时时间。配置过大会导致服务器卡顿,造成大量队列阻塞。配置过小,会导致出现事务问题,出现脏数据。等待时间也要合理配置,以及等待次数等等。

猜你喜欢

转载自my.oschina.net/u/3551926/blog/1600167