课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
分布式编程开发相信大家应该都不陌生的吧,而今天我们就通过案例分析来了解一下,在微服务开发环境下分布式锁的实现方法都有哪些。
基于数据库做分布式锁
基于表主键做分布式锁
思路:利用主键的特性,如果有多个请求同时提交到数据库,数据库只会保证只有一个操作可以成功,那么就可以认为操作成功的线程获取到了该方法的锁。当方法执行完毕之后,通过删除该行数据就可释放锁。
单点数据库导致强依赖,可以通过多数据库主从切换
通过定时器删除超时数据避免死锁
通过自旋CAS的方式插入实现阻塞
可重入可以通过检查对应的记录是否存在实现
公平锁可以通过等待线程表的方式实现
在大并发的情况下,通过主键冲突防重容易导致锁表,尽量在程序中生产主键进行防重
基于表字段版本号做分布式锁
基于mysql的mvcc机制,只有版本号一致才能进行对应的修改,修改后版本号加1,通过CAS的方式进行修改。
基于数据库排他锁做分布锁
通过事务和forupdate语句实现,数据库会在该事务下给数据库增加排他锁。在InnoDB引擎加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则使用表级锁。
基于Redis做分布锁
基于Redis的SETNX()、EXPIRE()方法做分布式锁
setnx方法的语义为SETifNotExists,其主要有两个参数,setnx(key,value)。该方法是原子的,如果key不存在,则设置当前的key成功,返回1;如果当前key已经存在,则设置当前key失败,返回0。
expire方法设置过期时间,setnx命令不能设置key的超时时间,只能通过expire()来对key设置。
如果在setnx执行成功后,在expire命令执行成功,执行的线程出现宕机的现象,就可能出现死锁现象。
基于Redis的SETNX()、GET()、GETSET()方法做分布式锁
getset方法有两个参数getset(key,newValue)。该方法是原子的,对key设置newValue这个值,并且返回key原来的旧值。假设key原来是不存在的,那么多次执行这个命令,会出现下边的效果:getset(key,“value1”)返回null此时key的值会被设置为value1;getset(key,“value2”)返回value1此时key的值会被设置为value2。
使用步骤:
setnx(lockkey,当前时间+过期超时时间),如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。
get(lockkey)获取值oldExpireTime,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。
计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey,newExpireTime)会返回当前lockkey的值currentExpireTime。
判断currentExpireTime与oldExpireTime是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。
在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。
基于REDLOCK做分布式锁
Redlock是Redis的作者开发的集群模式的Redis分布式锁,它基于N个完全独立的Redis节点.
客户端获取当前时间,以毫秒为单位。客户端尝试获取N个节点的锁(每个节点获取锁的方式和前面说的缓存锁一样),N个节点以相同的key和value获取锁。客户端需要设置接口访问超时,接口超时时间需要远远小于锁超时时间,比如锁自动释放的时间是10s,那么接口超时大概设置5-50ms。这样可以在有redis节点宕机后,访问该节点时能尽快超时,而减小锁的正常使用。
客户端计算在获得锁的时候花费了多少时间,方法是用当前时间减去在步骤一获取的时间,只有客户端获得了超过3个节点的锁,而且获取锁的时间小于锁的超时时间,客户端才获得了分布式锁。
客户端获取的锁的时间为设置的锁超时时间减去步骤三计算出的获取锁花费时间。
如果客户端获取锁失败了,客户端会依次删除所有的锁。
基于REDISSON做分布式锁
Redisson是redis官方的分布式锁组件。在Redisson中,如果如果线程获取锁成功,Redisson会在后台起开一个定时任务watchdog,定时任务会定时检查调用renewExpirationAsync(threadId)对锁进行续约。定时调度的时间差为internalLockLeaseTime/3,即10秒,默认加锁时间为30s。
基于Consul做分布式锁
基于Consul的分布式锁主要利用Key/Value存储API中的acquire和release操作来实现。acquire和release操作是类似Check-And-Set的操作。
acquire操作只有当锁不存在持有者时才会返回true,并且set设置的Value值,同时执行操作的session会持有对该Key的锁,否则就返回false
release操作则是使用指定的session来释放某个Key的锁,如果指定的session无效,那么会返回false,否则就会set设置Value值,并返回true。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请在707945861群中学习了解。