持续学习&持续更新中…
守破离
【Java从零到架构师第Ⅳ季】【02】分布式协调服务_ZooKeeper应用场景_核心工作机制
分布式协调服务
-
所谓分布式主要是指:一个整体的应用服务系统是由部署在多个机器上的许多的微服务去统一组合完成的。 对于部署在多个机器上的应用,它们通常具有不同的角色,比如有Master和Slave角色的区分。
-
对于Zookeeper集群, 也会有多个节点,主要包括leader节点和follower节点。
-
所谓协调服务(ZooKeeper很重要的角色就是来做协调服务):主要是指让Zookeeper在我们的分布式系统中充当一个协调者的角色,帮助具体的业务系统之间相互协调,当然它并不会干预其它业务系统的运行,保证系统的正常运行。
-
对ZooKeeper来说,我们做集群,一般最佳实践是三(2n+1)个节点(避免出现单点故障、如果leader节点挂了会从剩下的follower节点中选出一个,有选举策略)。
PS:图中的客户端并不一定是浏览器;大部分是“服务调用者”,是系统之间的RPC调用或者HTTP调用。
ZooKeeper应用场景
服务器在线感知
- 所有服务器启动的时候,都向Zookeeper指定的一个目录中写入一个数据,比如:/server/serverxxx
- 客户端连接Zookeeper,获取到/servers/目录下面所有的可用的服务信息
- 客户端监听/servers这个目录下面的数据改变, 如果ZooKeeper的这个目录下的数据发生改变,那么会及时的通知客户端数据已经发生改变
- 客户端收到Zookeeper的通知, 及时的去获取最新的数据
- 当应用程序宕机,在ZooKeeper中会及时的删除对应的服务信息
以秒杀服务为例:
- 秒杀服务启动时,向ZooKeeper进行注册,注册当前的信息:name、ip、port、…
- ZooKeeper会根据秒杀服务的相关数据进行动态的创建节点
- 客户端(服务调用者)连接ZooKeeper,获取服务的地址列表信息,并且注册(绑定)节点改变事件
注意:并不是每次发送请求都去注册中心获取,客户端获取一次后,会把地址列表信息缓存在本地 - 客户端随机选择一台服务器(根据负载均衡等策略),发送秒杀服务请求
- 如果有一台服务器(server04)宕机,ZooKeeper可以察觉到有server04宕机了(心跳机制:ZooKeeper与server04会建立一个socket长连接,让server04定时向ZooKeeper通知自己还活着,比如发送请求之类的方法),ZooKeeper就会移出掉server04对应的地址信息节点
- 当ZooKeeper移除掉对应的地址信息的时候,会通知绑定了节点改变事件的客户端进行数据更新
- 客户端获取到事件通知,重新向ZooKeeper获取最新的数据
主从协调
对于我们的集群环境中的多个机器,其中一台是处于活跃状态,可以正常的提供对应的服务;另外的服务器处于备份状态, 只有当活跃状态的机器出现问题,不能提供服务的时候,才会把备份状态的机器切换为活跃状态
- Server01是Active状态的机器, 向ZooKeeper中的/server/目录写入数据server01
- Server02是StadyBy状态的机器, 向Zookeeper中监听/server/目录中的数据改变
- 当server01出现宕机, 删除/server/server01这个数据,并且会及时的通知到server02
- Server02收到ZooKeeper的事件通知,启动服务, 并且向Zookeeper注册自己的信息/server/server02
- 客户端只需要向ZooKeeper中找到/server/目录下面的服务信息,既可以正常的访问服务
配置管理
在我们的大型的应用中,对于一个系统的配置会有很多需要配置的参数,比如说数据库的配置,Tomcat的线程数的配置等等,如果我们不使用统一的配置管理中心的话,需要在每个应用服务去进行一个单独的配置,这样操作比较麻烦,而且还容易出错,我们可以使用一个统一的配置管理:
- 提供一个配置管理程序,用于向ZooKeeper中写入对应的数据,主要包括属性名称和属性值
- 所有的服务启动的时候都去读取ZooKeeper中的配置信息,加载到应用程序,完成系统的正常启动
名称服务
-
Dubbo里面会用到名称服务
-
名称服务(命名服务)就是指通过指定的名字来获取资源或者服务的地址。
-
ZooKeeper会在自己的文件系统上(树结构的文件系统)创建一个以路径为名称的节点,它可以指向提供服务的地址,远程对象等。
-
简单来说使用ZooKeeper做命名服务就是用路径作为名字,路径上的数据就是其名字指向的实体。
分布式锁
在分布式系统的架构设计中,有时候需要保证分布式系统中对于某些接口的操作是原子性的, 我们需要控制在同一时刻只能有一个应用程序可以正常操作,其他的程序必须等待在操作的程序完成以后才可以正常的操作数据
- 所有需要访问生成ID的接口的服务的应用都去ZooKeeper的指定目录生成一个自己的数据/lock/serverxxx
- 所有的业务系统都判断一下自己生成的服务地址是否是所有的地址列表中的最小的一个, 如果是最小的一个,则可以正常访问接口,否则,处于等待状态
- 当获得锁对象的应用访问完生成ID的接口以后, 我们需要删除自己在ZooKeeper中的服务列表,然后再进行对应的操作
- 其他的应用再去判断自己的数据是否是ZooKeeper中的地址列表中的最小的一个数据,如果是的话,即可以获取到锁对象,开始资源对象的访问
ZooKeeper核心工作机制
ZooKeeper的特性
-
Zookeeper leader的选举策略:一个leader,多个follower组成的集群(3个节点最佳实践),当leader节点挂掉之后,我们需要在集群中选择一个节点作为leader节点,其中选举的策略是少数服从多数。
-
全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的(如果集群节点比较多,会影响写数据的性能,因为写数据只能在 Leader 节点,并且需要同步到从节点才可以访问。)
-
分布式读写:由leader实施更新请求、转发
-
更新请求顺序进行:来自同一个client的更新请求按其发送顺序依次执行
-
数据更新原子性:一次数据更新要么成功(半数以上节点成功),要么失败
-
实时性:在一定时间范围内,client能读到最新数据(毫秒级别) ;注意:写的数据量最好不要超过1MB
ZooKeeper的数据结构
- 层次化的目录结构,命名符合常规文件系统规范(见下图)
- 每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识
- 节点znode可以包含数据(只能存储很小量的数据,<1M)和子节点(但是EPHEMERAL类型的节点不能有子节点)
- 客户端应用可以在节点上设置监听器
ZooKeeper的节点类型
-
ZooKeeper中的每个节点叫做Znode
-
znode有四种形式的目录节点:
- PERSISTENT:持久化节点
- PERSISTENT_SEQUENTIAL:持久化顺序节点
- EPHEMERAL:临时节点
- EPHEMERAL_SEQUENTIAL:临时节点顺序节点
-
短暂(ephemeral)(断开连接自动删除数据);持久(persistent)(断开连接不删除数据)
-
创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
-
在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序
注意
-
RPC是一个完整的远程调用方案,它包括了:接口规范、序列化反序列化规范、通信协议等
-
HTTP只是一个通信协议,工作在OSI的第七层,不是一个完整的远程调用方案。
-
RPC 相当于 HTTP + 接口规范(比如:RESTful) + 序列化反序列化规范
-
RPC和HTTP等可以互补,世界上的任何技术其实都没有必要比个高下,将它们互补起来创造价值才是一个程序员应该做的事。
- Nginx示意图:
参考
小码哥: Java从0到架构师④高级互联网架构师.
本文完,感谢您的关注支持!