zookeeper使用场景

1、发布订阅(配置中心)

2、注册中心

3、分布式锁

4、master选举

5、分布式队列

6、分布式ID生成

如果我们想要理解zookeeper是如何实现以上功能的,那我们首先得了解下zookeeper节点的几个特性,以及我们如何利用这些特性实现以上场景功能。节点特性主要包括三个方面、(1)zookeeper的数据库结构格式

(2)几种zookeeper的节点类型

(3)zookeeper节点的watch机制


Zookeeper数据结构格式

zookeeper的数据结构非常简单,采用的是类似于的文件树形目录结构,同一个目录下节点名称是唯一的。




zookeeper 作为注册中心 Zookeeper的心跳检测 zookeeper实现注册中心原理_子节点


Zookeeper节点类型

zookeeper节点类型是zookeeper实现很多功能的核心原理,分为持久节点临时节点、顺序节点三种类型的节点。

持久节点

持久节点一旦被创建了,除非主动的进行删除,否则会一致保存在zookeeper上面。

临时节点

临时节点只在创建的当前会话中有效,一旦会话断开,临时节点就会删除。

顺序节点

有序节点是由父节点维护一个自增的序列号,每创建一个节点就会把该序列号追加到节点名称后面,通过此序列号我们可以知道节点的创建顺序,比如创建节点名称为node 的节点最后节点名称会是node001,node002这种样子。

通过以上节点的分类我们通常可以创建4种节点,持久节点、持久顺序节点、临时节点、临时顺序节点

节点事件通知机制(watch)

客户端可以为节点注册多种事件通知,一旦节点进行了对应类型操作,zookeeper就会通知注册了对应事件的客户端.


zookeeper 作为注册中心 Zookeeper的心跳检测 zookeeper实现注册中心原理_zookeeper_02


节点操作事件主要分为如下几种:

(1)节点创建事件:节点被创建时触发。

(2)节点修改事件:节点数据变更时触发。

(3)节点删除事件:节点被删除时触发。

(4)子节点变更事件:子节点子节点创建、修改、删除时触发。


Zookeeper实现配置中心

配置中心的使用场景

方便维护

在项目开发中我们常常会有多个项目或者服务需要连接同一个数据库、redis等等,这些地址我们通常是在每一个项目里面有一个xml或者yml、properties 文件维护,这种方式比较直观通用,但是维护方面不太方便,其实配置都一样的,我们可以放到一个统一的配置中心,各个项目只需要访问这个配置中心的节点就行,修改的话也只需要修改配置中心一个节点。

相对更安全

通常我们配置相关连接的时候都需要连接第三方的账号、密码,而这些账号密码通常权限比较高,在配置文件里面如果明文存储账号密码容易泄露,通常来说我们想安全点的做法就是对这些信息加密,或者说把这些信息存到其他地方去比如说zookeeper里,这样就避免了直接暴露这些敏感信息。

更灵活

如果我们在项目使用过程中动态的切换数据库、缓存得等服务的地址,那么原来配置文件的方式势必要通过修改配置文件,并且重启服务才行,而使用zookeeper后我们可以动态的修改这个地址,修改后zookeeper会通知其连接并注册了对应watch的客户端,让客户端可以及时更新到最新的配置信息。

zookeeper实现配置中心的原理

zookeeper实现配置中心的机制主要是利用了节点的watch机制

1、首先我们会在zookeeper上创建一个节点用于保存数据库连接信息。

2、然后我们的客户端连接zookeeper的时候会向该节点注册一个监听数据变更的watch事件。

3、当某个客户端操作修改了该节点时,zookeeper会通知向改节点注册了watch事件的每个客户端。

4、当我们客户端收到了zookeeper的通知,我们会从zookeeper读取到该节点的信息,然后动态的修改自身的配置信息。


zookeeper实现注册中心

使用场景

集群、负载均衡的服务地址维护

我们原来普遍使用nginx来做集群和负载均衡,通常我们会配一个集群的服务器地址,然后配置对应的负债均衡策略把请求分发到对应的服务器。因为提供服务器的地址是放在nginx的配置文件里面的,这种情况有两个问题:

1、集群的数量多起来,那nginx配置文件难以维护.

2、我们没办法实时知道集群里的服务提供者的状态,有可能有些服务已经挂了。

3、是我们如果想要动态添加集群的机器数量,那么就必须通过修改配置文件集群地址然后reload一下nignx的配置文件。如果在生产环境上通过这种方式去维护服务地址是很危险的,因为一个nginx一般不只你一个项目用,也许还做了很多其他的代理,一旦你修改配置文件出错很容易影响其他人的使用。

4、也许维护人本身也不知道有哪些人可以提供服务器,用nginx来维护集群的前提是我们的配置人员一定需要知道服务提供者的地址端口。

而对于上面的这几种类似的场景我们都可以使用注册中心来解决。

Zookeeper实现注册原理

zookeeper主要是利用了临时节点和节点watch事件的特性实现注册中心的。

1、服务提供者会向zookeeper 的某一个节点(比如说这里是/registry节点)下写入一个子节点(临时有序子节点),节点的名称也许是/registry/registry00001,节点的值就是自己服务的IP和端口。

2、服务消费者启动时向zookeeper的/registry节点注册一个子节点变更事件,同时会从zookeeper的/registry节点拉去所有子节点,从而获得服务提供者的地址。

3、当某个服务提供者与zookeeper断开了会话之后,那么zookeeper会将此会话创建的临时节点删除,然后再通知向/registry节点注册了对应监听事件的客户端。

4、客户端收到Zookeeper的节点变更通知后,从新从zookeeper拉去/registry节点的子节点信息。


Zookeeper实现分布式锁

解决分布式环境下资源冲突问题

锁主要是解决资源冲突的问题,而分布式锁主要是解决分布式环境下多个请求访问同一个资源引起的资源冲突问题,从而保证数据的一致性。在原来单服务的情况下我们可以通过sychronyzi 关键字来同步请求,但是在分布式情况下这种方法是不行的。因为多个服务同时执行一个业务还是会存在有并发的情况。 所以我们必须通过一个统一的第三方来分配资源的锁。实现分布式锁的方式有很多比如通过数据库、redis、zookeeper等等,其核心思路就是大家都从一个地方来获取这个资源锁。

Zookeeper实现分布式锁的原理

Zookeeper主要是利用临时节点,watch 和非有序节点只允许被创建一次的特性来实现分布式锁的。

首先:我们此次把分布式锁的节点建立在/lock节点下

1、所有客户端在与zookeeper建立连接的时候都会向/lock节点注册子节点变更事件。

2、客户端获取锁的时候,他们都会向zookeeper的/lock节点下创建一个名叫/lock/locked的临时节点,因为zookeeper的节点名称是唯一的,所以这里只会有一个人创建成功,创建成功的节点则获取到了锁,可以执行自己对应的业务,当执行完自己的业务之后删除/lock/locked子节点,或者在客户端与服务端断开会话之后此节点也会被删除(这里创建的是临时节点)。

3、没有创建/lock/locked节点成功的客户端则会在此等待,因为他们已经向/lock节点注册了子节点变更事件,所以当子节点被删除之后他们会收到一个通知,收到通知之后它们又会执行第2步的流程来获取锁。


zookeeper 作为注册中心 Zookeeper的心跳检测 zookeeper实现注册中心原理_客户端_03



master选举

数据处理在集群环境下数据同步都是一个头疼的问题,我们为了保证数据的一致性所以多台服务之前要进行数据同步,而没有一个统一的处理数据同步的master那么各个机器间实现数据同步会出很多问题,所以我们一般都会采用master的模式来处理数据同步的问题,其他服务器都统一从master同步数据,这样就会避免各个服务之间的数据不同而产生的数据不同步问题。master场景通常都是由master统一来处理数据的变更,其他服务器只负责处理查询并同步master的数据。

有了master的概念后,就产生了master选举的问题,因为我们没办法保证master的服务永远不会挂,所以一旦master挂了之后我们就要从其他服务器里面选举出一个作为master。

master选举会在两种情况下进行,一是首次服务启动,二是其中一台master 挂掉了要从其他服务里面选举出一个作为master.

Zookeeper 选举master的实现原理

Zookeeper主要是利用了临时节点、watch机制、还有节点的唯一性原理来实现master选举的。

1、首次进行master选举时,所有客户端都会向zookeeper创建一个名称/master的临时节点,因为zookeeper节点的唯一性,所以只会有一个客户端创建节点成功。

2、所有节点都会以创建创建成功的节点作为master节点,然后在/master节点上注册一个节点变更的watch。

3、当我们的master挂掉的时候,因为master与zookeeper的会话也断开了,此时zookeeper会删除/master节点,并向注册了对应事件的客户端发送通知。

4、当客户端收到了/master节点删除的通知时,客户端又都会去通过创建/master节点的方式去竞选master。


分布式队列

队列的场景使用比较多,先进先出的顺序队列,定时处理的延时队列,条件限制型的屏障队列。产品也比较多,比如activeMq,rabbitMq,kafka,这里我们主要了解下如何利用zookeeper实现分布式队列。

Zookeeper实现分布式队列的原理

zookeeper主要是利用临时节点、有序节点、watch机制的特性来完成队列的实现的。

1、首先我们在zookeeper里面创建一个节点/queue用于存储队列信息。

2、在客户端执行业务前,分别向/queue节点创建临时有序节点。

3、客户端通过getchildren 来获取/queue节点的所有子节点,然后验证自己的创建的节点顺序号是不是最小的,如果不是最小的,那么监听比自己小的前一个节点,同时等待。

如果自己是最小的节点,那么执行自己的业务,执行完之后删除自己所创建的节点。

4、因为每个客户端都会监听在自己前面的一个节点,所以当前一个节点删除后,zookeeper都会向注册了该节点时间的客户端发送通知,当监听的客户端收到通知,它又会重新通过getchildren 来获取所有子节点,然后执行第三步相同的流程。


分布式ID生成

在数据库分库分表的情况下,我们又要保证ID的唯一性,所以我们需要有一个统一生成ID的服务保证生成的ID不会重复。我们通常会使用UUID,但是使用UUID一般都比较长,而且没有顺序规律,难以识别先后顺序,通常ID我们一般都会建立索引,而太长而没有顺序规律的ID会影响索引的效率。

所以我们会尝试其他方式来生成分布式的ID,比如会提供一个服务,这个服务建一个表只生成ID ,其他需要生成ID都统一调用此服务。还有redis 自增序列也可以作为统一ID的生成,zookeeper也可以满足这方面的需求。

zookeeper生成分布式ID的原理

Zookeeper主要利用顺序节点的特性来生成分布式ID,因为每个zookeeper节点都会为子节点维护一个自增的序列号,当某个服务需要生成ID时候,只要往对应节点里面创建对应顺序节点,创建成功后会返回对应节点的节点名称,我们就可以直接使用此名称来作为ID。