精选文章 分布式锁

分布式锁

作者:飞火龙在天 时间: 2021-02-05 10:02:20
飞火龙在天 2021-02-05 10:02:20
【摘要】分布式主要是产生了多个虚拟机JVM,故同一个变量会同时存在多个虚拟机里 
分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题! 
分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consiste...

分布式主要是产生了多个虚拟机JVM,故同一个变量会同时存在多个虚拟机里

分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。”所以,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法在同一时间内只能被同一个线程执行。

1.基于数据库实现分布式锁; 
2.基于缓存(Redis等)实现分布式锁; 
3.基于Zookeeper实现分布式锁;

一。

缺点:

1、这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
2、这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。
3、这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

解决方案:
1、数据库是单点?搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。
2、没有失效时间?只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。
3、非阻塞的?搞一个while循环,直到insert成功再返回成功。
4、非重入的?在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。
二。

缺点:

在这种场景(主从结构)中存在明显的竞态:
客户端A从master获取到锁,
在master将锁同步到slave之前,master宕掉了。
slave节点被晋级为master节点,
客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。安全失效

try{
lock = redisTemplate.opsForValue().setIfAbsent(lockKey, LOCK);
logger.info("cancelCouponCode是否获取到锁:"+lock);
if (lock) {
// TODO
redisTemplate.expire(lockKey,1, TimeUnit.MINUTES); //成功设置过期时间
return res;
}else {
logger.info("cancelCouponCode没有获取到锁,不执行任务!");
}
}finally{
if(lock){
redisTemplate.delete(lockKey);
logger.info("cancelCouponCode任务结束,释放锁!");
}else{
logger.info("cancelCouponCode没有获取到锁,无需释放锁!");
}
}

三。

缺点:
性能上可能并没有缓存服务那么高。因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同不到所有的Follower机器上。

其实,使用Zookeeper也有可能带来并发问题,只是并不常见而已。考虑这样的情况,由于网络抖动,客户端可ZK集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这时候其他客户端就可以获取到分布式锁了。就可能产生并发问题。这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,Curator客户端支持多种重试策略。多次重试之后还不行的话才会删除临时节点。(所以,选择一个合适的重试策略也比较重要,要在锁的粒度和并发之间找一个平衡
以直接使用zookeeper第三方库Curator客户端,这个客户端中封装了一个可重入的锁服务。

public boolean tryLock(long timout, TimeUnit unit) throws InterrruptedException{
try{
return interProcessMutex. acquire (timout, unit);
) catch (Exception e) t
e.printstackTrace ();

}
return true;

}
public boolean  unlock(){

try{
interProcessMutex.release ();
} catch (Throwable e) {
Log.error (e.getMessage(),e);
}finally {
executorService.schedule (nw Cleaner(client, path), delayTlmeForClean, timeunit. MILL ISECONDS);

}
return true;

}

Curator提供的InterProcessMutex是分布式锁的实现。acquire方法用户获取锁,release方法用于释放锁。

使用ZK实现的分布式锁好像完全符合了本文开头我们对一个分布式锁的所有期望。但是,其实并不是,Zookeeper实现的分布式锁其实存在一个缺点,那就是性能上可能并没有缓存服务那么高。因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同不到所有的Follower机器上。

其实,使用Zookeeper也有可能带来并发问题,只是并不常见而已。考虑这样的情况,由于网络抖动,客户端可ZK集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这时候其他客户端就可以获取到分布式锁了。就可能产生并发问题。这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,Curator客户端支持多种重试策略。多次重试之后还不行的话才会删除临时节点。(所以,选择一个合适的重试策略也比较重要,要在锁的粒度和并发之间找一个平衡。)

使用Zookeeper实现分布式锁的优点

有效的解决单点问题,不可重入问题,非阻塞问题以及锁无法释放的问题。实现起来较为简单。

使用Zookeeper实现分布式锁的缺点

性能上不如使用缓存实现分布式锁。

 

从理解的难易程度角度(从低到高)

数据库 > 缓存 > Zookeeper

从实现的复杂性角度(从低到高)

Zookeeper >= 缓存 > 数据库

从性能角度(从高到低)

缓存 > Zookeeper >= 数据库

从可靠性角度(从高到低)

Zookeeper > 缓存 > 数据库

勿删,copyright占位
您找到想要的结果了吗?
分布式锁
提交成功!非常感谢您的反馈,我们会继续努力做到更好
分享文章到微博
分享文章到朋友圈

上一篇:MTK 平台工具

下一篇:iOS如何编译OpenSSL静态库(openssl版本:1.1.1b)

您可能感兴趣

  • 分布式技术

    分布式技术 低成本, 高性能, 高可用, 易扩展, 高安全 Dubbo与Zookeeper: 解决服务的远程调用问题(RPC问题). 把service拆成独立的微服务, 每个微服务包括完成一项功能的全部方法. 通过分布式集群部署, 以牺牲一致性为代价, 获得高可用和高容错的特性. 使用zookeeper用来管理这些分布式服务. Zooke...

  • 分布式跟踪系统收藏

    分布式跟踪系统(application Performance Management ),原理: https://research.google.com/pubs/pub36356.html (英文)、https://bigbully.github.io/Dapper-translation/ (中文翻译) pinpoint,参考地址:https:...

  • java分布式解析

    对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了。而并发问题是绝大部分的程序员头疼的问题, 但话又说回来了,既然逃避不掉,那我们就坦然面对吧~今天就让我们一起来研究一下常见的并发...

  • oracl 锁表 解锁 杀死进程

    1  查询数据库被锁的表: SELECT l.session_id sid,          s.serial#,          l.locked_mode 锁模式,          l.oracle_username 登录用户,          l.os_user_name 登录机器用户名,          s.machine 机器名...

  • MongoDB加索引导致锁库的问题记录

    1、问题描述 执行以下语句时,导致其他对MongoDB的请求无法被相应,线上应用程序报错。 db.getCollection('***').ensureIndex({key:1}) 2、原因分析 MongoDB建索引时,默认前台操作,原因是为了尽可能快的创建索引,在此过程中会阻塞其他对数据库的IO操作。可以通过设置background=tr...

  • 《分布式服务架构》笔记 chapter2 一致性问题

    服务拆分有两种方式,水平和垂直。 水平拆分:单节点无法满足要求,扩展为多节点,每个节点服务一部分请求量,一个dhcp服务器水平扩展的例子: 如图,用户流量上到负载均衡器,应用一致性hash算法负载到每个节点,每个节点就是一对dhcp服务器,包含一个master和一个slave,主备之间灾备通过failover机制。每个节点设置阈值,当可分配的...

  • 无锁消息队列

    一个无锁消息队列引发的血案(三)——地:q3.h 与 RingBuffer 目录 (一)起因 (二)混合自旋锁 (三)q3.h 与 RingBuffer  (四)RingQueue(上) 自旋锁  (五)RingQueue(中) 休眠的艺术 (六)RingQueue(中) 休眠的艺术 [续] 无锁队列   第一篇文章末尾我们提到的《无锁队...

  • Android N默认锁屏壁纸的实现

    从Android N开始,原生系统增加了锁屏壁纸开关: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/Phone...

CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。
分布式锁介绍:华为云为您免费提供分布式锁在博客、论坛、帮助中心等栏目的相关文章,同时还可以通过 站内搜索 查询更多分布式锁的相关内容。| 移动地址: 分布式锁 | 写博客