首页 > 编程知识 正文

分布式开发面试题,分布式面试题及答案

时间:2023-05-05 22:36:27 阅读:153025 作者:755

1 .为什么需要分布式锁定? publicsynchronizedvoidtest ((system.out.println ) )“获取锁”; }获取公共void test2((synchronized ) test.class ) { System.out.println ) )锁; }如果将上述代码部署到多台服务器上,此独占锁是否有效? 答案是否定的。 这时,分布式摇滚应运而生。

2.Redis分布式锁? 接下来,介绍完整的进化过程,以便更深入地理解分布式锁。

Redis setnx线程1已申请解除锁定。 这个时候没有人有摇滚。 解锁成功:

127.0.0.1:6379 setnxlock1(integer ) 1线程2申请解锁,并注意到有人未解锁,解锁失败:

127.0.0.1:6379 setnxlock1(integer ) 0线程1执行完成业务逻辑后,运行DEL命令解锁:

127.0.0.1:6379戴尔锁定(integer ) 1有问题:

假设线程1运行到一半,系统挂起。 如果此时没有释放锁定,则会发生死锁。

在Redis锁定后,如果Master锁定而不与Slave同步,则会导致两个客户端获得锁定

解决方案: setnx expire

Redis setnx expire为了解决上述死锁问题,在setnx之后,在这个key上加上了失效时间。

此时,线程1锁定的代码如下所示:

127.0.0.1:6379 setnx lock 1 ##登录(integer ) 1127.0.0.133606379 expire lock3# #设置key 3秒失效) integer ) 1存在问题:

假设setnx lock 1运行成功,但expire lock 3运行失败。 果然有死锁的问题。 这两个命令是原子性

失效时间是我们写的,不能自动更新。 如果业务运行时间超过失效时间,则线程1可能仍在运行,线程2可能无法成功锁定,并且无法获得独占效果。

如果在Redis锁定后Master未同步到Slave而是锁定,则两个客户端将获得锁定

解决方案:修复锁定

RedissonLock的上述两个问题由RedissonLock解决。 我用源代码进行分析,看看RedissonLock是如何解析的。 基础好的伙伴能很好地读源代码。 其实RedissonLock的源代码也不难。

我先写结论。 基础薄弱的伙伴,记住结论就好了:

在RedisssonLock的基础上,使用了保证锁定和失效命令原子性的lua脚本执行的redis命令。

RedisssonLock底部有看门狗机构,解锁成功后,定时器调度任务打开,每10秒检查是否解锁一次,否则将无效时间更新为30秒。 这样锁定就会一直持续下去,不会被释放。

我正在查看3.12.5版的源代码,不同版本的实现可能会有一些差异。

APP位置锁定代码:

rocklock=redissonlock.get lock (anylock ); lock.lock (; RedissonLock锁定核心代码:

RedissonLock获取锁定核心代码:

低位锁定逻辑:

KEYS[1]=anyLock,锁的名称。

按ARGV[1]=30000、失效时间、lockWatchdogTimeout配置。

argv [2]=c1b 51dd B-1505-436 c-a308-B3 b 75b 4bd 40733601,他是连接管理器的身份,这可以简单地理解为客户端线程感知的唯一象征。

RedissonLock解锁核心代码:

有个问题。 如果redis是单节点,则存在单节点故障问题。 对于主从体系结构,在Redis锁定后,如果Master在未同步到Slave之前锁定,则会有两个客户端获得锁定

朋友问我,在这里使用集群的话会有这个问题吗? 集群的本质是瓦片,这个key最终会落到某个具体节点。 由于该节点要么单独存在,要么是主从结构,所以仍然存在上述问题。

解决方案:红色锁定

补充: RedLock可以解决上述问题,但很少在生产环境中使用。 因为部署成本很高,性能比RedissonLock稍低。

如果业务可以接受极端情况下存在互斥失败,且对性能要求较高,请选择RedissonLock并制定相应的驱动器计划。

如果业务要求数据绝对正确,请使用Zookeeper进行分布式锁定。

Redlock假设有五个完全独立的Redis Master独立节点,因此必须在五台计算机上运行这些实例,如下图所示()

全相互独立)

为了取到锁,客户端应该执行以下操作:

①获取当前Unix时间,以毫秒为单位。

②依次尝试从N个Master实例使用相同的key和随机值获取锁(假设这个key是LOCK_KEY)。当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。

③客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。

④如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。

⑤如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。

缺点:像我们系统,并发量比较大,生产环境必须要做分片才能扛住并发,像上述方案,我们需要准备5个Redis集群,这种机器成本是非常高的。

3.Zookeeper分布式锁

如果有一把锁,被多个人给竞争,此时多个人会排队,第一个拿到锁的人会执行,然后释放锁,后面的每个人都会去监听排在自己前面的那个人创建的node上,一旦某个人释放了锁,排在自己后面的人就会被zookeeper给通知,一旦被通知了之后,就ok了,自己就获取到了锁,就可以执行代码了。

为了帮助大家理解,我暂时不用框架,通过手写代码带大家理解Zookeeper锁:

此时有小伙伴问,如果业务执行一半,系统宕机了怎么办?

zk创建的是临时节点,客户端获取到锁执行业务,执行到一半突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉,其他客户端自动获取锁,不会存在死锁问题。

一般生产环境我们都会使用Curator来完成分布式锁编码,他提供了可重入锁、非可重入锁、Semaphore、可重入读写锁、MultiLock等各种分布式锁。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。