1.   Zookeeper

    1.1 Zookeeper 概述

    Zookeeper是应用于分布式应用程序的高性能分布式协调服务,它暴露了一组简单的公共服务(提供java和C接口),如命名、配置管理、集群服务、分布式锁等,分布式应用程序可以基于此实现更高级别的服务进行同步、组合命名。

   1.1.1 Zookeeper作用

    配置管理

在微服务架构中,往往存在诸多配置,有很多服务都需要这些配置,这时就需要一种集中管理配置,我们在集中管理的地方变更配置,对这个配置感兴趣的服务都能获得变更。Zookeeper提供集中管理配置方法使用Zab(Zookeeper Atomic Broadcast 原子广播)这种一致性协议来提供一致性。目前需要开源框架使用Zookeeper维护配置,比如HBase、Kafka、Dubbo。

    命名服务

Zookeeper提供统一的入口,方便维护微服务架构中应用地址。

    集群管理

在分布式的集群中,经常因为各种原因,比如硬件故障、网络问题、软件故障等,有些节点会进进出出。有新的节点加入集群,也有老的节点退出集群。这个时候集群其他机器需要感知这个变化,然后根据这个变化做出相应决策。例如一个分布式存储系统,有个中央节点负责存储分配,当有新的存储进来需要根据集群状态来分配存储节点,这时就需要动态感知集群状态;又如分布式SOA架构中,消费者需要访问某个服务时,需要某种机制发现那些节点可以提供服务(这也称为服务发现)。alibaba 开源分布式SOA架构Dubbo使用Zookeeper作为服务发现的底层机制,Kafka队列也是使用Zookeeper作为Customer服务的上下线管理。

    分布式锁

    1.1.2 Zookeeper存储结构

    命名空间

    Zookeeper允许分布式进程通过类似文件系统的共享分层命名空间相互协调。命名空间由Zookeeper语法中数据寄存器(Znodes)组成,这类似文件和目录。Zookeeper数据保存在内存中,Zookeeper可以实现高吞吐量和低延迟数。

    Zookeeper分层命名空间:

springcloud接入apollo_服务器

Zookeeper名称是以反斜杠(/)分隔的路径元素序列。Zookeeper名称空间每个节点都由路径标识。

    节点和短暂节点

    和标准文件系统不一样,Zookeeper每个节点(Znode)都有与其相关联的数据和子节点,就好像是一个允许文件也是目录的文件系统。Zookeeper设计为存储协调数据:状态信息、配置、位置信息等,存储在每个节点的数据都很小。

    Znodes维护统计结构,其中包括数据更改、ACL更改和时间戳的版本号,以缓存验证和协调更新。每次Znode节点更新,Znodes版本号都会增加。

    存储在Znode节点的数据以原子的方式读取和写入,获取和Znode相关所有数据,写入替换所有数据。每个节点都有一个访问控制列表(ACL),它限制谁能做什么。

    Zookeeper还存短暂节点的概念。只要创建的Znode的会话处于活动状态,就会存在,当会话结束,Znode就会删除。

    有条件的更新和观察者Watcher

    Zookeeper 支持观察者概念。客户端可以在Znode上设置观察者(Watcher),当Znode更改时,观察者将被触发并移除。当观察者触发时,客户端接收到一个数据包,说明Znode已经改变了。

    提供应用唯一标识

    Zookeeper集群中,每个节点需要唯一标识,这个唯一标识要求是自然数,且唯一标识保存位置是:$dataDir/myid,其中 dataDir 为配置文件 zoo.cfg 中的配置参数 在 data 目录中创建文件 myid : touch myid 为应用提供唯一标识。

    1.2 Zookeeper原理

只要Zookeeper大部分服务器可用,Zookeeper服务可用。

   Zoopeeper由一个

springcloud接入apollo_服务器_02

    客户端Client连接到Zookeeper服务器,客户端维持TCP联系,通过它发送请求和获取响应,获取Watcher时间并发送心跳。如果客户端TCP连接中断,将连接到其他服务器。

    Zookeeper组件显示Zookeeper的高级服务组件。除了请求处理器外,组成Zookeeper服务的每个服务器都会复制其每个组件的副本。

Zookeeper组件:

springcloud接入apollo_服务器_03

复制的数据库包含整个数据树的内存数据库。将更新记录到磁盘已获得可恢复性,并将序列化到磁盘,然后才能应用到内存数据库。

    Zookeeper每个服务器都为客户端服务,客户端所有写入请求都转发到单个服务器,称为主管/领导者。其他称为学习者/关注者的Zookeeper服务器从领导者接受消息提议,并同意消息传递。Zookeeper使用自定义的原子消息协议。由于协议是原子的,所有Zookeeper可以保证本地副本不会发散。

   Zookeeper集群中主要分为三大类角色:

  •    领导者-负责投票的发起和决议,更新系统状态;
  •    学习者/关注者

     跟随者-接收客户端请求并返回响应,在选主过程参与投票;

    观察者-接收客户端连接,将写请求转发给leader节点,但观察者不参与投票,只同步leader状态。观察者目的是扩展系统,提高读取速度。

  •     客户端-请求发起方  

   1.3 Zookeeper特性及设计目的

  • 顺序性:客户端的更新将按照发送的顺序进行应用。
  • 原子性:更新结果只有成功和失败,没有中间状态。
  • 最终一致性/单一系统映像-客户端无论连接那个Server,展示给它的都是同一视图。
  • 可靠性:具有简单、健壮、良好的性能,一旦应用更新了,将从当前持续到客户端覆盖更新。
  • 实时性:系统的客户端在一定时间保证是最新的。

   1.4. 使用Zookeeper协调分布式应用

    1.4.1 Zookeeper安装

    单机模式安装

     Step1:下载解压缩并重命名cfg 

官网下载后需要修改\zookeeper-xxx\conf文件夹下zoo_sample.cfg文件名称为zoo.cfg

    Step2: 启动Zookeeper

    \zookeeper-xxx\conf\bin\zkServer.sh start

    Step3:检查启动是否成功,使用Zookeeper客户端连接下服务器

    集群模式安装

    Step1:下载并解压缩

    Step2:重命名\zookeeper-xxx\conf文件夹下zoo_sample.cfg

# cp conf/zoo_sample.cfg conf/zoo-1.cfg

    Step3:修改cfg配置,设置服务、投票、选举端口

# vim conf/zoo-1.cfg
tickTime = 2000 
dataDir = /var/lib/zookeeper1 
clientPort = 2181 
initLimit = 5 
syncLimit = 2 
#服务端口根据应用做对应修改
server.1 = zoo1:2888:3888 
server.2 = zoo2:2888:3888
server.3 = zoo3:2888:3888

    Step4:复制zoo.cfg出来两个zoo1.cfg和zoo2.cfg,修改对应的dataDir和clientPort即可

# cp conf/zoo-1.cfg conf/zoo-2.cfg
# cp conf/zoo-1.cfg conf/zoo-3.cfg
# vim conf/zoo-2.cfg
dataDir=/tmp/zookeeper-2
clientPort=2182
# vim conf/zoo-2.cfg
dataDir=/tmp/zookeeper-3
clientPort=2183

    Step5:标识Server ID,创建三个目录,在每个目录创建myid文件,写入当前实例Server ID,即1、2、3

# cd /tmp/zookeeper-1
# vim myid
1
# cd /tmp/zookeeper-2
# vim myid
2
# cd /tmp/zookeeper-3
# vim myid
3

    Step6: 分别启动Zookeeper三个实例

# bin/zkServer.sh start conf/zoo-1.cfg
# bin/zkServer.sh start conf/zoo-2.cfg
# bin/zkServer.sh start conf/zoo-3.cfg

    Step7:检查集群状态,使用命令“zkCli.sh -server IP:PORT” 连接Zookeeper服务检测

     安装配置说明

  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
  • initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒
  • syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10秒
  • dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
  • server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。

需要注意Zookeeper集群模式,至少需要三台服务,强烈建议奇数个服务。如果是两台服务器,那么在Leader出现故障后,则没有足够机器形成大多数法定人数,从而无法选举出新的Leader。两台服务本身比单机模式稳定,因为有两个单点故障。