前面花了30天时间整理了设计模式系列文章,得到了非常好的反馈,也让我更加有动力坚持写作,有兴趣的朋友可以回顾这篇文章。
同时,也收到了很多建议,希望我多发一些面试题,今天开始连载互联网公司高频面试题。经常有小伙伴提到分布式锁在面试的过程中经常被问到,通常面试官会从服务框架(Spring Cloud、Dubbo)聊起,一路聊到分布式事务、分布式锁、ZooKeeper等知识。所以这篇文章以面试问答的角度带你了解分布式锁这块知识。
1、ZooKeeper 提供了什么?
2、Zookeeper 做了什么?
3 、Zookeeper 的配置管理
程序分布式的部署在不同的机器上,将程序的配置信息放在 zk 的 znode 下,当有配置发生改变时,也就是 znode 发生变化时,可以通过改变 zk 中某个目录节点的内容,利用 watcher 通知给各个客户端,从而更改配置。
4、Zookeeper 集群管理
所谓集群管理有两点:是否有机器退出和加入、选举 master。
对于第一点,所有机器约定在父目录下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper 的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount又有了,
对于第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为 master 就好。
5、Zookeeper 分布式锁
有了 zookeeper 的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。
对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过 createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的 distribute_lock 节点就释放出锁。
对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选 master 一样,编号最小的获得锁,用完删除,依次方便。
6、获取分布式锁的流程
在获取分布式锁的时候在 locker 节点下创建临时顺序节点,释放锁的时候 删除该临时节点。
客户端调用 createNode 方法在 locker 下创建临时顺序节点, 然后调用 getChildren(“locker”)来获取 locker 下面的所有子节点,注意此时不用设置任何 Watcher。
客户端获取到所有的子节点 path 之后,如果发现自己创建的节点在所有创建的子节点序号最小,那么就认为该客户端获取到了锁。如果发现自己创建的节点并非 locker 所有子节点中最小的,说明自己还没有获取到锁, 此时客户端需要找到比自己小的那个节点,然后对其调用 exist()方法,同时对其注册事件监听器。
之后,让这个被关注的节点删除,则客户端的 Watcher 会收到相应通知,此时再次判断自己创建的节点是否是 locker 子节点中序号最小的, 如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点 并注册监听。当前这个过程中还需要许多的逻辑。
代码的实现主要是基于互斥锁,获取分布式锁的重点逻辑在于 BaseDistributedLock,实现了基于 Zookeeper 实现分布式锁的细节。
7、Zookeeper 工作原理
Zookeeper 的核心是原子广播,这个机制保证了各个 Server 之间的同步。实现这个机制的协议叫做 Zab协议。Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
当服务启动或者在领导者崩溃后,Zab 就进入 了恢复模式,当领导者被选举出来,且大多数 Server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 Server 具有相同的系统状态。
8、Zookeeper 同步流程
选完 Leader 以后,zk 就进入状态同步过程。
①Leader 等待 server 连接;
②Follower 连接 leader,将最大的 zxid 发送给 leader;
③Leader 根据 follower 的 zxid 确定同步点;
④完成同步后通知 follower 已经成为 uptodate 状态;
⑤Follower 收到 uptodate 消息后,又可以重新接受 client 的请求进行服务了。
9、zk 节点宕机如何处理?
Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。
Zookeeper 自身也要保证当一个节点宕机时,其他节点会继续提供服务。如果是一个 Follower 宕机,还有 2 台服务器提供访问,因为 Zookeeper 上 的数据是有多个副本的,数据并不会丢失;如果是一个 Leader宕机,Zookeeper 会选举出新的 Leader。
ZK 集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在 ZK 节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。所以 3 个节点的 cluster 可以挂掉1个节点(leader 可以得到 2 票>1.5),2 个节点的 cluster 就不能挂掉任何 1个节点了(leader 可以得到 1 票<=1)。
10、Zookeeper 机制的特点
①一次性触发数据发生改变时,一个 watcher event 会被发送到 client,但 是 client 只会收到一次这样的信息。
②watcher event 异步发送 watcher 的通知事件从 server 发送到 client是异步的,这就存在一个问题,不同的客户端和服务器之间通过 socket 进行通信, 由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于 Zookeeper 本身提供了 ordering guarantee,即客户端监听事件后,才会感知它所监视 znode 发生了变化。所以我们使用 Zookeeper 不能期望能够监控到节点每次的变化。Zookeeper 只能保证最终的一致性,而无法保证强一致性。
③数据监视 Zookeeper 有数据监视和子数据监视 getdata() and exists()设置 数据监视,getchildren()设置了子节点监视。
④注册 watcher getData、exists、getChildren
⑤触发 watcher create、delete、setData
⑥setData()会触发 znode 上设置的 data watch(如果 set 成功的话)。一个 成功的 create() 操作会触发被创建的 znode 上的数据 watch,以及其父节点上 的 child watch。而一个成功的 delete()操作将会同时触发一个 znode 的 data watch 和 child watch(因为这样就没有子节点了),同时也会触发其父节点的 childwatch。
⑦当一个客户端连接到一个新的服务器上时,watch 将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到 watch 的。而当client 重新连接时,如果需要的话,所有先前注册过的 watch,都会被重新注册。通常这是完全透明的。
只有在一个特殊情况下,watch 可能会丢失:对于一个未创建 的 znode 的 exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个 watch 事件可能会被丢失。
⑧Watch是轻量级的,其实就是本地 JVM 的 Callback,服务器端只是存了是否有设置了 Watcher 的布尔类型。
根据岗位不同,各厂笔试的内容也不尽相同,技术岗尤其会重点考察编程硬实力。
对于互联网行业来说,出题主要有以下几个方向:
● 历年的题目
● 对互联网行业知识掌握
● 岗位要求的能力
● 结合时事热点话题
● 围绕公司的产品