中间件(三)- Zookeeper

在这里插入图片描述

1. Zookeeper介绍

官网 https://zookeeper.apache.org/

1.1 什么是Zookeeper

Zookeeper 是一种分布式协调服务,用于管理大型主机。在分布式环境中协调和管理服务是一个复杂的过程,ZooKeeper通过其简单的架构和API解决了这个问题。ZooKeeper 能让开发人员专注于核心应用程序逻辑,而不必担心应用程序的分布式特性。

1.2 Zookeeper的应用场景

  • 分布式协调组件
    这个其实是 zookeeper 很经典的一个用法,简单来说,就好比,你 A 系统发送个请求到 mq,然后 B 系统消息消费之后处理了。那 A 系统如何知道 B 系统的处理结果?用 zookeeper 就可以实现分布式系统之间的协调工作。A 系统发送请求之后可以在 zookeeper 上对某个节点的值注册个监听器,一旦 B 系统处理完了就修改 zookeeper 那个节点的值,A 系统立马就可以收到通知,完美解决。
    在这里插入图片描述

  • 分布式锁
    zk在实现分布式锁上,可以做到强一致性

    例如:对某一个数据连续发出两个修改操作,两台机器同时收到了请求,但是只能一台机器先执行完另外一个机器再执行。那么此时就
    可以使用 zookeeper 分布式锁,一个机器接收到了请求之后先获取 zookeeper 上的一把分布式锁,就是可以去创建一个 znode,接着执行
    操作;然后另外一个机器也尝试去创建那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等着,等第一个机器执行完了自己再执行。

    在这里插入图片描述

  • 元数据/配置信息管理
    zookeeper 可以用作很多系统的配置信息的管理,比如 kafka、storm 等等很多分布式系统都会选用 zookeeper 来做一些元数据、
    配置信息的管理,包括 dubbo 注册中心不也支持 zookeeper 么?
    在这里插入图片描述

  • 高可用性
    这个应该是很常见的,比如 hadoop、hdfs、yarn 等很多大数据系统,都选择基于 zookeeper 来开发 HA 高可用机制,就是一个
    重要进程一般会做主备两个,主进程挂了立马通过 zookeeper 感知到切换到备用进程。

    在这里插入图片描述

2. 搭建ZooKeeper服务器

依赖:JDK 必须是7或以上版本

2.1 下载安装包

下载地址

[root@node-251 conf]# cd /opt/;wget https://dlcdn.apache.org/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz
[root@node-251 opt]# tar -zxvf apache-zookeeper-3.8.0-bin.tar.gz
[root@node-251 opt]# cp apache-zookeeper-3.8.0-bin /usr/share/zookeeper -r
[root@node-251 opt]# ll /usr/share/zookeeper/
total 36
drwxr-xr-x 2 root root  4096 May 19 01:10 bin
drwxr-xr-x 2 root root    72 May 19 01:10 conf
drwxr-xr-x 5 root root  4096 May 19 01:10 docs
drwxr-xr-x 2 root root  4096 May 19 01:10 lib
-rw-r--r-- 1 root root 11358 May 19 01:10 LICENSE.txt
-rw-r--r-- 1 root root  2084 May 19 01:10 NOTICE.txt
-rw-r--r-- 1 root root  2335 May 19 01:10 README.md
-rw-r--r-- 1 root root  3570 May 19 01:10 README_packaging.md

2.2 配置文件

进入zookeeper目录下的conf目录,将目录中的zoo_sample.cfg改成zoo.cfg

[root@node-251 conf]# cp zoo_sample.cfg zoo.cfg
[root@node-251 conf]# vim zoo.cfg
[root@node-251 conf]# cat zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpHost=0.0.0.0
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

配置文件说明:

  • tickTime

      (tickTime=2000):Client-Server通信心跳时间
      
      zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳。
      tickTime以毫秒为单位
    
  • initLimit

      (initLimit=10):Leader - Follower 初始通信时限。
      用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器
      集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5 个心跳的时
      间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的
      时间长度就是 5*2000 = 10 秒。
    
  • syncLimit

      (syncLimit=5):Leader- Follower 同步通信时限。
    
      这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,
      总的时间长度就是 5*2000 = 10 秒。
    
  • dataDir

      (dataDir=/tmp/zookeeper):数据文件目录。
      
      ​ Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
    
  • clientPort

      (clientPort=2181):客户端连接端口。
    
      客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
    
  • maxClientCnxns

      (maxClientCnxns=60):对于一个客户端的连接数最大限制。
      
      默认是 60,这在大部分时候是足够了。但是在我们实际使用中发现,在测试环境经常超过这个数,经过调查发现有的团队
      将几十个应用全部部署到一台机器上,以方便测试,于是这个数字就超过了。
    
  • autopurge.snapRetainCount、autopurge.purgeInterval

      设置清除时间和保留个数。
      
      客户端在与 zookeeper 交互过程中会产生非常多的日志,而且 zookeeper 也会将内存中的数据作为 snapshot 保存下来,
      这些数据是不会被自动删除的,这样磁盘中这样的数据就会越来越多。不过可以通过这两个参数来设置,让 zookeeper 自动
      删除数据。
      
      autopurge.purgeInterval 就是设置多少小时清理一次。
      
      autopurge.snapRetainCount 是设置保留多少个 snapshot ,之前的则删除。
    
  • 集群信息的配置
    在zoo.cfg这个文件中,配置集群信息是存在一定的格式:service.N =YYY: A:B

    N:代表服务器编号(也就是myid里面的值)

    YYY:服务器地址

    A:表示 Flower 跟 Leader的通信端口,简称服务端内部通信的端口(默认2888)

    B:表示 是选举端口(默认是3888)

    例如:

    server.1=hadoop05:2888:3888
    server.2=hadoop06:2888:3888
    server.3=hadoop07:2888:3888

2.3 启动测试

进入bin目录下,启动服务端

[root@node-251 bin]# ./zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/share/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@node-251 bin]# ss -nltp
...
LISTEN     0      50                                    [::]:2181                                              [::]:*                   ...

jps查看进程

 [root@node-251 opt]# jps
59140 Bootstrap
72861 Jps

如果jps命令找不到,安装一下就可以了

yum install java-1.8.0-openjdk-devel.x86_64

启动/停止/重启/状态 zk服务器:

./zkServer.sh start/stop/restart/status ../conf/zoo.cfg

回到zookeeper目录下,启动客户端


[root@node-251 bin]# ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 0] quit

3. Zookeeper内部的数据模型

3.1 zk如何保存数据?

zk中的数据是保存在节点上的,节点就是znode,多个znode之间构成一棵树的目录结构。Zookeeper的数据模型是什么样子呢?类似于数据结构中的树,同时也很像文件系统的目录。树是由节点所组成,Zookeeper的数据存储也同样是基于节点,这种节点叫做Znode,但是不同于树的节点,Znode的引用方式是路径引用,类似于文件路径:
在这里插入图片描述

这样的层级结构,让每一个Znode的节点拥有唯一的路径,就像命名空间一样对不同信息做出清晰的隔离。

3.2 zk中的znode是什么样的数据结构

zk中的znode包含了四个部分:

  • data:保存数据

  • acl:权限:

      c:create 创建权限,允许在该节点下创建子节点
      w:write 更新权限,允许更新该节点的数据
      r:read 读取权限,允许读取该节点的内容以及子节点的列表信息
      d:delete 删除权限,允许删除该节点的子节点信息
      a:admin 管理者权限,允许对该节点进行acl权限设置
    
  • stat:描述当前znode的元数据

      cZxid 就是 Create ZXID,表示节点被创建时的事务ID。
      ctime 就是 Create Time,表示节点创建时间。
      mZxid 就是 Modified ZXID,表示节点最后⼀次被修改时的事务ID。
      mtime 就是 Modified Time,表示节点最后⼀次被修改的时间。
      pZxid 表示该节点的⼦节点列表最后⼀次被修改时的事务 ID。只有⼦节点列表变更才会更新 pZxid,
      ⼦节点内容变更不会更新。
      cversion 表示⼦节点的版本号。
      dataVersion 表示内容版本号。
      aclVersion 标识acl版本
      ephemeralOwner 表示创建该临时节点时的会话 sessionID,如果是持久性节点那么值为 0
      dataLength 表示数据⻓度。
      numChildren 表示直系⼦节点数
    
  • child:当前节点的子节点

3.3 zk中节点znode的类型

1、持久节点:创建出的节点,在会话结束后依然存在。保存数据
2、持久序号节点:创建出的节点,根据先后顺序,会在节点之后带上一个数值,越后执行数值越大,适用于分布式锁的应用场景-单调递增
3、临时节点:临时节点是在会话结束后,自动被删除的,通过这个特性,zk可以实现服务注册与发现的效果。
4、临时序号节点:跟持久序号节点相同,适用于临时的分布式锁
5、Container节点(3.5.3版本新增):Container容器节点,当容器中没有任何子节点,该容器节点会被zk定期删除
6、TTL节点:可以指定节点的到期时间,到期后被zk定时删除。只能通过系统配置zookeeper.extendedTypeEnablee=true开启

3.4 zk的数据持久化

zk的数据运行在内存中,zk提供了两种持久化机制:

  • 事务日志
    zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中(如果没有指定dataLogDir,则按照 dataDir指定的路径)。
  • 数据快照
    zk会在一定的时间间隔内做一次内存数据快照,把时刻的内存数据保存在快照文件中。

zk通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复,这样恢复的速度更快。

4. Zookeeper客户端(zkCli)的使用

4.1 多节点类型创建

创建节点指令

[-s]表示节点是序号节点
[-e]表示节点是临时节点
[-c]表示节点是Container节点

create [-s] [-e] [-c] [-t ttl] path [data] [acl]
  • 创建持久节点 create path [data] [acl]
  • 创建持久序号节点 create -s path [data] [acl]
  • 创建临时节点 create -e path [data] [acl]
  • 创建临时序号节点 create -e -s path [data] [acl]
  • 创建容器节点 create -c path [data] [acl]
[zk: localhost:2181(CONNECTED) 0] create /lasting_node
Created /lasting_node
[zk: localhost:2181(CONNECTED) 1] create -s /lasting_serial_node
Created /lasting_serial_node0000000001
[zk: localhost:2181(CONNECTED) 2] create -e /temporary_node
Created /temporary_node
[zk: localhost:2181(CONNECTED) 3] create -e -s /temporary_serial_node
Created /temporary_serial_node0000000003
[zk: localhost:2181(CONNECTED) 4] create -c /container_node
Created /container_node
[zk: localhost:2181(CONNECTED) 5] ls
ls [-s] [-w] [-R] path
[zk: localhost:2181(CONNECTED) 6] ls /
[container_node, lasting_node, lasting_serial_node0000000001, temporary_node, temporary_serial_node0000000003, zookeeper]

4.2 查询节点

普通查询

ls [-s -R] path
# -s 详细信息
# -R 当前目录和子目录中的所有信息

[zk: localhost:2181(CONNECTED) 1] ls -s /lasting_node
[]
cZxid = 0x4
ctime = Fri May 19 19:22:49 CST 2023
mZxid = 0x4
mtime = Fri May 19 19:22:49 CST 2023
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0
[zk: localhost:2181(CONNECTED) 2] ls -R /lasting_node
/lasting_node

查询节点相关信息

- cZxid:创建节点的事务ID
- mZxid:修改节点的事务ID
- pZxid:添加和删除子节点的事务ID
- ctime:节点创建的时间
- mtime:节点最近修改的时间
- dataVersion:节点内数据的版本,每更新一次数据,版本会+1
- aclVersion:此节点的权限版本
- ephemeralOwner:如果当前节点是临时节点,该是是当前节点所有者的session id。如果节点不是临时节点,则该值为零
- dataLength:节点内数据的长度
- numChildren:该节点的子节点个数

查询节点的内容

get [-s] path    
# -s 详细信息

[zk: localhost:2181(CONNECTED) 0] get -s /lasting_node
null
cZxid = 0x4
ctime = Fri May 19 19:22:49 CST 2023
mZxid = 0x4
mtime = Fri May 19 19:22:49 CST 2023
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0

ls和get
ls命令可以列出Zookeeper指定节点下的所有子节点,只能查看指定节点下的第一级的所有子节点;get命令可以获取Zookeeper指定节点的数据内容和属性信息

4.3 删除节点

普通删除

delete path [dataVersion]

乐观锁删除

delete [-v version] path
# -v 版本

deleteall path [-b batch size]

想要删除某个节点,极其后代节点,可以使用递归删除

rmr path

4.4 权限设置

注册当前会话的账号和密码:

    addauth digest xiaowang:123456

创建节点并设置权限(指定该节点的用户,以及用户所拥有的权限s)

    create /test-node abcd auth:xiaowang:123456:cdwra

在另一个会话中必须先使用账号密码,才能拥有操作节点的权限

    addauth digest xiaowang:123456

5. kazoo客户端的使用(python)

环境:

  1. python 2.7.8
  2. kazoo 2.6.1 下载地址

5.1 基本操作

#coding:utf-8
from kazoo.client import KazooClient

zk = KazooClient(hosts='192.168.71.251:2181')    #如果是本地那就写127.0.0.1
zk.start()    #与zookeeper连接
zk.stop()    #与zookeeper断开

5.2 创建节点

from kazoo.client import KazooClient
zk = KazooClient(hosts='192.168.71.251:2181')    #如果是本地那就写127.0.0.1
zk.start()    #与zookeeper连接
#makepath=True是递归创建,如果不加上中间那一段,就是建立一个空的节点
zk.create('/abc/JQK/XYZ/0001',b'this is my house',makepath=True)
node = zk.get_children('/')  # 查看根节点有多少个子节点
print(node)
zk.stop()    #与zookeeper断开

5.3 删除节点

如果要删除这个/abc/def/ghi/0001的子node,但是想要上一级ghi这个node还是存在的

#coding:utf-8
from kazoo.client import KazooClient

zk = KazooClient(hosts='192.168.71.251:2181')    #如果是本地那就写127.0.0.1
zk.start()    #与zookeeper连接
#zk.create('/abc/def/ghi/0001', b'this is test', makepath=True)
node = zk.get_children('/abc/def/ghi/')

zk.delete('/abc/def/ghi/0001',recursive=True)
print node

zk.stop()    #与zookeeper断开
-----------------------
[]

5.4 更改节点

现在假如要在0001这个node里更改value,比如改成:“this is my horse!”,

由于上面节点已经被删除掉了,需要先创建一次。

#coding:utf-8
from kazoo.client import KazooClient

zk = KazooClient(hosts='192.168.71.251:2181')    #如果是本地那就写127.0.0.1
zk.start()    #与zookeeper连接
zk.create('/abc/JQK/XYZ/0001',b'this is my house',makepath=True)
zk.set('/abc/JQK/XYZ/0001',b"this is my horse!")


node = zk.get('/abc/JQK/XYZ/0001')

print node

zk.stop()    #与zookeeper断开
-------------------------------
('this is my horse!', ZnodeStat(czxid=48, mzxid=49, ctime=1684503782537L, mtime=1684503782540L, version=1, cversion=0, aversion=0, ephemeralOwner=0, dataLength=17, numChildren=0, pzxid=48))

注意!set这种增加节点内容的方式是覆盖式增加,并不是在原有基础上增添。而且添加中文的话可能在ZooInspecter里出现的是乱码

5.5 一键清空zookeeper

有些时候,需要将zookeeper的数据全部清空,可以使用以下代码

#coding:utf-8
from kazoo.client import KazooClient

zk = KazooClient(hosts='192.168.71.251:2181')    #如果是本地那就写127.0.0.1
zk.start()    #与zookeeper连接

jiedian = zk.get_children('/')  # 查看根节点有多少个子节点
print(jiedian)
for i in jiedian:
    if i != 'zookeeper':  # 判断不等于zookeeper
        print(i)
        # 删除节点
        zk.delete('/%s'%i,recursive=True)

zk.stop()    #与zookeeper断开

注意:默认的zookeeper节点,是不允许删除的,所以需要做一个判断。

5.6 watches 事件

zookeeper 所有读操作都有设置 watch 选项(get_children() 、get() 和 exists())。watch 是一个触发器,当检测到 zookeeper 有子节点变动 或者 节点value发生变动时触发。下面以 get() 方法为例。

#coding:utf-8
from kazoo.client import KazooClient

zk = KazooClient(hosts='192.168.71.251:2181')
zk.start()

def test(event):
    print('触发事件')

if __name__ == "__main__":
    zk.create('/testplatform/test',b'this is test',makepath=True)
    zk.get('/testplatform/test',watch = test)
    print("第一次获取value")
    zk.set('/testplatform/test',b'hello')
    zk.get('/testplatform/test',watch = test)
    print("第二次获取value")
    zk.stop()
------------------------------------------------
第一次获取value
触发事件
第二次获取value

高阶运用
好文推荐 - 详细参考

6. zk实现分布式锁

6.1 zk中锁的种类:

  • 读锁(读锁共享):大家都可以读。上锁前提:之前的锁没有写锁
  • 写锁(写锁排他):只有得到写锁的才能写。上锁前提:之前没有任何锁

6.2 zk如何上读锁

  • 创建一个临时序号节点,节点的数据是read,表示是读锁
  • 获取当前zk中序号比自己小的所有节点
  • 判断最小节点是否是读锁
    • 如果不是读锁的话,则上锁失败,为最小节点设置监听。阻塞等待,zk的watch机制会当最小节点发生变化时通知当前节点,再执行第二步的流程
    • 如果是读锁的话,则上锁成功。

6.3 zk如何上写锁

  • 创建一个临时序号节点,节点的数据是write,表示写锁
  • 获取zk中所有的子节点
  • 判断自己是否是最小的节点:
    • 如果是,则上写锁成功
    • 如果不是,说明前面还有锁,则上锁失败,监听最小节点,如果最小节点有变化,则再执行第二步。

在这里插入图片描述

6.4 羊群效应

如果用上述的上锁方式,只要有节点发生变化,就会触发其他节点的监听事件,这样对zk的压力非常大,而羊群效应,可以调整成链式监听。zookeeper的羊群效应
在这里插入图片描述

7. zk的watch机制

7.1 Watch机制介绍

我们可以把Watch理解成是注册在特定Znode上的触发器。当这个Znode发生改变,也就是调用了create,delete,set方法的时候,将会触发Znode上注册的对应事件,请求Watch的客户端会收到异步通知。

具体交互过程如下:

  • 客户端调用getData方法,watch参数是true。服务端接到请求,返回节点数据,并且在对应的哈希表里插入被Watch的Znode路径,以及Watcher列表。
  • 当被Watch的Znode已删除,服务端会查找哈希表,找到该Znode对应的所有Watcher,异步通知客户端,并且删除哈希表中对应的key-value。

7.2 zkCli客户端使用Watch

create /test date
get -w /test    # 一次性监听节点
ls -w /test    	# 监听目录,创建和删除子节点会收到通知。但是子节点中新增节点不会被监听到
ls -R -w /test  # 监听子节点中节点的变化,但内容的变化不会收到通知

8. Zookeeper集群实战

8.1 Zookeeper集群角色

zookeeper集群中的节点有三种角色:

  • Leader:处理集群的所有事务请求,集群中只有一个Leader
  • Follower:只能处理读请求,参与Leader选举
  • Observer(观察者):只能处理读请求,提升集群读的性能,但不能参与Leader选举

8.2 集群搭建

搭建4个节点,其中一个节点为Observer

  • 创建4个节点的myid并设值,在usr/local/zookeeper中创建一下四个文件
/usr/local/zookeeper/zkdata/zk1# echo 1 > myid
/usr/local/zookeeper/zkdata/zk2# echo 2 > myid
/usr/local/zookeeper/zkdata/zk3# echo 3 > myid
/usr/local/zookeeper/zkdata/zk4# echo 4 > myid
  • 编写4个zoo.cfg
      # The number of milliseconds of each tick
  tickTime=2000    --基本时间单位
  # The number of ticks that the initial
  # synchronization phase can take
  initLimit=10 --允许follower连接到leader的最大时长 tickTime*initLimit 2000*10
  # The number of ticks that can pass between
  # sending a request and getting an acknowledgement
  syncLimit=5 --允许与leader同步的最大时长
  # the directory where the snapshot is stored.
  # do not use /tmp for storage, /tmp here is just
  # example sakes. 修改对应的zk1 zk2 zk3 zk4
  dataDir=/usr/local/zookeeper/zkdata/zk1 --数据及日志保存路径
  # the port at which the clients will connect
  clientPort=2181

  #2001为集群通信端口,3001为集群选举端口,observer(观察者身份)
  server.1=192.168.200.128:2001:3001
  server.2=192.169.200.128:2002:3002
  server.3=192.168.200.128:2003:3003
  server.4=192.168.200.128:2004:3004:observer

8.3 连接Zookeeper集群

./bin/zkCli.sh    -server 192.168.200.128:2181,192.168.200.128:2182,192.168.200.128:2183

9. ZAB协议

9.1 什么是ZAB协议

zookeeper作为非常重要的分布式协调组件,需要进行集群部署,集群中会以一主多从的形式进行部署。zookeeper为了保证数据的一致性,使用了ZAB(Zookeeper Atomic Broadcast,zookeeper的原子广播协议)协议,这个协议解决了Zookeeper的崩溃恢复和主从数据同步的问题。

9.2 ZAB协议定义的四种节点状态

  • Looking:选举状态
  • Following:Following节点(从节点)所处的状态
  • Leading:Leader节点(主节点)所处状态
  • Observing:观察者节点所处的状态

9.3 集群上线Leader选举过程

在这里插入图片描述
前提:本次4台机器,其中一台observer不参加选举,剩3台
第一轮:

  • 1.选票格式:
    Myid:节点ID
    ZXid:事务ID
    生成这一张自己的选票
  • 2.把选票给对方
  • 3.把zxid/myid更大的选票投入投票箱,zxid/myid表示先按zxid比较,如果相同再按myid比较
  • 4.由于每个节点的投票箱只有一票,而要求拥有超过半数以上的节点,才算选举成功,需要至少2票以上

第二轮:

  • 1.把上一轮较大的票给对方
  • 2.再次统计,节点2获胜,选举结束
    当3进入的时候,发现已有leader,把自己当为follower

9.4 崩溃恢复时的Leader选举

Leader建立完后,Leader周期性地不断向Follower发送心跳(ping命令,没有内容的socket)。当Leader崩溃后,Follower发现socket通道已关闭,于是Follower开始进入到Looking状态,重新回到上一节中的Leader选举状态,此时集群不能对外提供服务。

9.5 主从服务器之间的数据同步

ACK:(Acknowledge character)即是确认字符
在这里插入图片描述

9.6 Zookeeper中的NIO与BIO的应用

NIO(NIO全称 java non-blocking IO,NIO是可以做到用一个线程处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或100个线程来处理。不像BIO一样需要分配10000个线程来处理)

  • 用于被客户端连接的2181端口,使用的是NIO模式与客户端建立连接
  • 客户端开启Watch时,也使用NIO,等待Zookeeper服务器的回调

BIO(BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销)

  • 集群在选举时,多个节点之间的投票通信端口,使用BIO进行通信

10. CAP理论

10.1 CAP理论

一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

  • —致性(Consistency)
    一致性指"all nodespsee the same data at the same time",即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致。

  • 可用性(Availability)
    可用性指"Reads and writes always succeed",即服务一直可用,而且是正常响应时间。

  • 分区容错性(Partition tolerance)
    分区容错性指"the system continues to operate despite arbitrary message loss or failure of part of the system",即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。——避免单点故障,就要进行冗余部署,冗余部署相当于是服务的分区,这样的分区就具备了容错性。

10.2 BASE理论

eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论,BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性《Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency) 。

  • 基本可用(Basically Available)
    基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用,电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。

  • 软状态(Soft State)
    软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication的异步复制也是一种体现。

  • 最终一致性(Eventual Consistency)
    最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的—种特殊情况。

10.3 Zookeeper追求的一致性

Zookeeper在数据同步时,追求的并不是强一致性,而是顺序一致性(事务id的单调递增)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值