分布式锁解决方案

常用的分布式锁的实现有三种方式:基于redis实现、基于MySQL实现、基于Zookeeper实现。
分布式锁要解决的问题有:
1、在分布式系统环境下一个方法同一时间只能被一个机器的一个线程执行
2、锁是可重入锁
3、锁是阻塞锁(根据业务需要决定)
4、锁是公平锁,也是根据业务需要爵士那个
5、有高可用的获取锁和释放锁的功能
6、 获取锁和释放锁的性能要好

MySQL 实现分布式锁

基于MySQL实现的分布式锁,基于MySQL的InnoDB的行锁来实现,有两种实现方式:悲观锁和乐观锁。
直接创建一张锁表,通过操作该锁表中的数据实现分布式锁。
第一种方法,想要多组某个方法时执行insert方法插入一条数据,method_name有唯一约束,可以保证多次提交只有一次成功,成功即获得锁,执行完成执行delete语句释放锁。缺点:依赖数据库可用性,数据库挂业务系统也挂;解锁失败锁将一直存在其他线程获取不到资源;这种锁是非阻塞的,一旦插入失败就会报错;也是非重入的,同一线程没有释放锁之前无法再次获得该锁;非公平。
第二种方法,通过数据库的排他锁实现分布式锁。在查询select语句后面增加for update,数据库会在查询过程给数据库记录加上排他锁,其他线程无法加排他锁。执行完毕后通过connection.commit()释放锁。使用排他锁加行级锁需要给method_name字段添加索引,才会在查询过程中使用行级锁。这种加锁方式解决了无法释放锁的问题,服务器宕机是数据库也会自己把锁释放掉;也解决了阻塞问题,for update语句执行成功立即返回,失败会处于阻塞状态直到成功。
第三种方法,乐观锁实现,在数据库表中再添加一个version字段来实现读取舒适版本号对比。一直则成功执行,不一致则更新失败。

Redis分布式锁

基于Redis缓存实现分布式锁,利用redis的原子性操作setnx即set if not exist来实现的。当用户向缓存成功写入一个key-value时,其他的客户端不嗯呢该在写入相同的key-value。
加锁:使用setnx命令,setnx(id,value),设置锁超时参数防止宕机锁无法释放,使用set(key,threadID,expire)实现获取锁并设置过期时间原子操作。其中value设置为线程id,在删除锁时线程id进行对比,是本线程加的锁着进行删除操作。同时,在基于设置锁过期时间的问题下,为获取锁的线程开启一个守护线程,当锁即将过期且线程并未执行完毕时,搜狐线程会执行expire命令为锁续命线程执行完任务会显式的关闭守护线程。
解锁:使用del命令 del(id)

Zookeeper 分布式锁

Zookeeper提供了树形结构命名空间分为几种节点类型分别为:永久节点、临时节点:会话结束或超时就消息,和有序节点:在节点名后加数字后缀,并且有序。
Zookeeper为一个节点注册监听器,在节点状态改变时会向客户端发送消息。分布式锁的实现:
● 创建锁目录 /lock
● 当一个客户端需要锁的时候在/lock目录下创建临时有序子节点
● 客户端获取/lock目录下的子节点列表,判断自己是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁;否则监听自己前一个子节点,获得前一个序号子节点状态变更通知重复检查循环此步骤,直到获得锁。
● 执行完业务代码后,会删除相应的子节点,即释放锁。会话超=超时的情况下,会话的临时节点也会被删除。不会出现释放锁失败情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值