clllll  

1.why zookeeper

现在各个服务大部分都是集群。多个节点一起工作。就是传说中的分布式。
多个节点工作肯定不会个一个节点工作一模一样。需要来进行数据的同步等。高并发,就需要上锁。这里是分布式锁。不是单台机器的锁。
zookeeper 就是为了解决这些问题的。
zookeeper 是分布式协调服务。
登录官网看咋说的
image
准备用谷歌在线翻译。发现用不了了。。呵呵
使用微信翻译
image

可以维护配置信息,比如kafka的配置信息?
命名?这个不懂。
分布式同步。就是多个节点数据同步。
提供服务。
zookeeper就是把我们业务需要做的公共的东西做了。咱只需要关系咱自己的业务。出现bug。一般是咱自己导致的。不是zookeeper。

2.zookeeper应用场景

学习kafka的时候,前提就是zookeeper.

2.1、分布式协调组件

协调分布式中系统的状态。

2.2、分布式锁

比如俩个主机A和B 提供一样的服务,同一个数据D,有人请求肯定在其中一个主机上,如果修改了主机A的数据D。 那么B上的D也应该被修改。这就是zookeeper做的事,使用分布式锁,保证了数据的一致性。强一致性 或 最终一致性。

2.3、无状态化的实现

现在流行无状态化,就是服务器只负责处理数据,而不保存数据,每个节点都一样。这样扩缩容就很简单。数据肯定 是去其他地方保存了。那么就是zookeeper.但是zookeeper不能当做数据库一样来保存数据。

3.安装zookeeper

就是到官方下载包。然后解压就完事了。一般安装在 /usr/local
zookeeper的目录
image

  • bin 就是一些可以执行的命令。比如启动/停止zk. 客户端连接zk等。
    image
  • conf 配置文件的地方,每个软件一般都叫这个玩意。一些配置数据,启动数据就在这里
    zk的配置文件一般是zoo.cfg
    zoo_sample.cfg是示例
    image
  • logs
    默认保存数据、日志的路径

4.使用zookeeper.单节点

4.1 启动前需要先编辑配置文件

zoo.cfg配置如下

tickTime=2000 # zk最小时间单位。2s 
dataDir=/var/lib/zookeeper # zk保存数据的路径,如果没有logdatadir,log也在这个路径
clientPort=2181 # 客户端连接zk的端口

4.2 启动zk

在 bin目录下
./zkServer.sh start
还可以指定配置文件,默认就是config下的zoo.cfg
image

PS:使用zk,先要安装好jdk. 毕竟是apache的。

4.3 查看zk状态

./zkServer.sh status
image
Mode: standalone

4.4 停止服务器

./zkServer.sh stop

5.使用zkCli 客户端 来连接zk服务端,来学习一些基本命令

5.1 使用zkCli连接命令

./zkCli.sh
image

5.2 输入help就会有命令提示帮助,告诉我们有哪些命令可以执行

[zk: localhost:2181(CONNECTED) 0] help
ZooKeeper -server host:port -client-configuration properties-file cmd args
        addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
        addauth scheme auth
        close 
        config [-c] [-w] [-s]
        connect host:port
        create [-s] [-e] [-c] [-t ttl] path [data] [acl]
        delete [-v version] path
        deleteall path [-b batch size]
        delquota [-n|-b|-N|-B] path
        get [-s] [-w] path
        getAcl [-s] path
        getAllChildrenNumber path
        getEphemerals path
        history 
        listquota path
        ls [-s] [-w] [-R] path
        printwatches on|off
        quit 
        reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
        redo cmdno
        removewatches path [-c|-d|-a] [-l]
        set [-s] [-v version] path data
        setAcl [-s] [-v version] [-R] path acl
        setquota -n|-b|-N|-B val path
        stat [-w] path
        sync path
        version 
        whoami 

5.3、版本、获取节点信息

[zk: localhost:2181(CONNECTED) 1] version
ZooKeeper CLI version: 3.8.0-5a02a05eddb59aee6ac762f7ea82e92a68eb9c0f, built on 2022-02-25 08:49 UTC
[zk: localhost:2181(CONNECTED) 2] whoami
Auth scheme: User
ip: 0:0:0:0:0:0:0:1
[zk: localhost:2181(CONNECTED) 4] get /

[zk: localhost:2181(CONNECTED) 5] 
  • zk保存数据的格式
    zk保存数据的格式 是 类似目录的。 树结构。
    基于节点来保存的。叫znode.
    根路径 /
    根路径下test节点 /test
    test 节点下还可以有 /test/test_sub

5.4、创建节点

zk有多种类型的节点.对应不同的命令
create [-s] [-e] [-c] [-t ttl] path [data] [acl]

5.4.1 持久节点

创建出来的节点。会话结束后还存在

[zk: localhost:2181(CONNECTED) 5] create /test1 ll
Created /test1

5.4.2 持久序号节点

根据先后顺序。在节点之后带上一个数值,数值递增。 应用于分布式场景。 来区分不同的并发,时间先后。

[zk: localhost:2181(CONNECTED) 6] create -s /test2 ll2 
Created /test20000000016
[zk: localhost:2181(CONNECTED) 7] create -s /test2 ll22 
Created /test20000000017
[zk: localhost:2181(CONNECTED) 9] create /test1 ll2
Node already exists: /test1

名称后面自动加一个数值。
序号节点创建同名的不会报错。
创建同名的非序号节点,就会说已经存在

5.4.3 临时节点

会话结束,该节点就没了

[zk: localhost:2181(CONNECTED) 8] create -e /test3 ll3 
Created /test3

5.4.4 临时序号节点

用于临时的分布式锁场景。

[zk: localhost:2181(CONNECTED) 10] create -s -e /test4 ll4 
Created /test40000000019
[zk: localhost:2181(CONNECTED) 11] create -s -e /test4 ll42 
Created /test40000000020

5.5 查看节点信息

5.5.1 首先查看有哪些节点

ls [-s] [-w] [-R] path

[zk: localhost:2181(CONNECTED) 17] ls /
[admin, brokers, cluster, config, consumers, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, test1, test20000000016, test20000000017, test3, test40000000019, test40000000020, zookeeper]

默认只能查看当前路径下的节点。

  • -R : 一般是递归的意思,可以查看子路径下的节点信息
[zk: localhost:2181(CONNECTED) 18] ls -R /
/
/admin
/brokers
/cluster
/config
/consumers
/controller_epoch
/feature
/isr_change_notification
/latest_producer_id_block
/log_dir_event_notification
/test1
/test20000000016
/test20000000017
/test3
/test40000000019
/test40000000020
/zookeeper
/admin/delete_topics
/brokers/ids
/brokers/seqid
/brokers/topics
/brokers/topics/test
/brokers/topics/test/partitions
/brokers/topics/test/partitions/0
/brokers/topics/test/partitions/0/state
/cluster/id
/config/brokers
/config/changes
/config/clients
/config/ips
/config/topics
/config/users
/config/topics/test
/consumers/console-consumer-20678
/consumers/console-consumer-20678/offsets
/consumers/console-consumer-20678/offsets/test
/consumers/console-consumer-20678/offsets/test/0
/zookeeper/config
/zookeeper/quota

5.5.2 查看具体某个节点的信息

get [-s] [-w] path

  • 查看当前节点保存的数据
[zk: localhost:2181(CONNECTED) 19] get /test1
ll
  • 查看当前节点的元数据
[zk: localhost:2181(CONNECTED) 20] get -s  /test1
ll   # 数据
cZxid = 0xa1 # 创建事务ID 
ctime = Sun Jan 01 20:36:36 HKT 2023 # 创建时间
mZxid = 0xa1 # 修改事务ID
mtime = Sun Jan 01 20:36:36 HKT 2023 # 修改时间
pZxid = 0xa1 # 添加/删除子节点的事务ID 
cversion = 0 # 
dataVersion = 0 # 节点数据版本,每修改一次,就递增1 
aclVersion = 0 # 此节点的权限版本
ephemeralOwner = 0x0 # 如果当前节点是临时节点,是当前节点所有者的session id。如果节点不是临时节点,则该值为零
dataLength = 2 # 节点内数据的长度
numChildren = 0 # 节点的子节点个数

table键会有提示

[zk: localhost:2181(CONNECTED) 22] get -s /test2000000001
test20000000016   test20000000017   
[zk: localhost:2181(CONNECTED) 22] get -s /test20000000016
ll2
cZxid = 0xa2
ctime = Sun Jan 01 20:45:13 HKT 2023
mZxid = 0xa2
mtime = Sun Jan 01 20:45:13 HKT 2023
pZxid = 0xa2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 23] get -s /test3
ll3
cZxid = 0xa4
ctime = Sun Jan 01 20:47:47 HKT 2023
mZxid = 0xa4
mtime = Sun Jan 01 20:47:47 HKT 2023
pZxid = 0xa4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x10002ee9e300000
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 24] get -s /test400000000
test40000000019   test40000000020   
[zk: localhost:2181(CONNECTED) 24] get -s /test40000000019
ll4
cZxid = 0xa6
ctime = Sun Jan 01 20:50:04 HKT 2023
mZxid = 0xa6
mtime = Sun Jan 01 20:50:04 HKT 2023
pZxid = 0xa6
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x10002ee9e300000
dataLength = 3
numChildren = 0

5.6 权限设置

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

addauth scheme auth

  • 节点的权限
    c: create,创建
    w: write,更新
    d: delete,删除
    a: admin,管理者,进行acl权限设置
    r: read,读
[zk: localhost:2181(CONNECTED) 27] addauth digest lzl:123 
[zk: localhost:2181(CONNECTED) 28] 

lzl 是用户 123 是密码

[zk: localhost:2181(CONNECTED) 28] 
[zk: localhost:2181(CONNECTED) 28] create /test5 ll5 auth:lzl:123:cdw
Created /test5
[zk: localhost:2181(CONNECTED) 29] get /test5
Insufficient permission : /test5
[zk: localhost:2181(CONNECTED) 30] getAcl -s /test5
Insufficient permission : /test5
[zk: localhost:2181(CONNECTED) 31] whoami
Auth scheme: User
digest: lzl
ip: 0:0:0:0:0:0:0:1
[zk: localhost:2181(CONNECTED) 35] create /test6 ll6 auth:lzl:123:cdwra
Created /test6
[zk: localhost:2181(CONNECTED) 36] get /test6
ll6
[zk: localhost:2181(CONNECTED) 38] getAcl /test6
'digest,'lzl:ctz2pGX7T978GzU15rvOzb8mJeM=
: cdrwa

5.7 删除节点

delete [-v version] path

  • 删除持久节点
[zk: localhost:2181(CONNECTED) 40] delete /test1
[zk: localhost:2181(CONNECTED) 41] ls 
ls [-s] [-w] [-R] path
[zk: localhost:2181(CONNECTED) 42] ls /
[admin, brokers, cluster, config, consumers, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, test20000000016, test20000000017, test3, test40000000019, test40000000020, test5, test6, zookeeper]
  • 删除持久序号节点
[zk: localhost:2181(CONNECTED) 43] delete /test20000000016
[zk: localhost:2181(CONNECTED) 45] ls /
[admin, brokers, cluster, config, consumers, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, test20000000017, test3, test40000000019, test40000000020, test5, test6, zookeeper]
  • 更新节点数据
[zk: localhost:2181(CONNECTED) 46] get /test3
ll3
[zk: localhost:2181(CONNECTED) 47] get -s /test3
ll3
cZxid = 0xa4
ctime = Sun Jan 01 20:47:47 HKT 2023
mZxid = 0xa4
mtime = Sun Jan 01 20:47:47 HKT 2023
pZxid = 0xa4
cversion = 0
dataVersion = 0  # 数据版本0 
aclVersion = 0
ephemeralOwner = 0x10002ee9e300000
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 48] set -e /test3 ll333
org.apache.commons.cli.UnrecognizedOptionException: Unrecognized option: -e
[zk: localhost:2181(CONNECTED) 49] set  /test3 ll333
[zk: localhost:2181(CONNECTED) 50] 
[zk: localhost:2181(CONNECTED) 50] get /test3
ll333
[zk: localhost:2181(CONNECTED) 51] get -s /test3
ll333
cZxid = 0xa4
ctime = Sun Jan 01 20:47:47 HKT 2023
mZxid = 0xae
mtime = Sun Jan 01 21:22:07 HKT 2023
pZxid = 0xa4
cversion = 0
dataVersion = 1 # 数据版本加1 
aclVersion = 0
ephemeralOwner = 0x10002ee9e300000
dataLength = 5
numChildren = 0
zk: localhost:2181(CONNECTED) 58] create -e /test3 ll3
Created /test3
[zk: localhost:2181(CONNECTED) 59] set /test3 ll3+1 
[zk: localhost:2181(CONNECTED) 60] get /test3
ll3+1
[zk: localhost:2181(CONNECTED) 61] ls /
[admin, brokers, cluster, config, consumers, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, test20000000017, test3, test40000000019, test40000000020, test5, test6, zookeeper]
[zk: localhost:2181(CONNECTED) 62] get -s /test3
ll3+1
cZxid = 0xb3
ctime = Sun Jan 01 21:24:35 HKT 2023
mZxid = 0xb4
mtime = Sun Jan 01 21:24:48 HKT 2023
pZxid = 0xb3
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x10002ee9e300000
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 63] delete -v 1 /test3 
[zk: localhost:2181(CONNECTED) 64] ls /
[admin, brokers, cluster, config, consumers, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, test20000000017, test40000000019, test40000000020, test5, test6, zookeeper]

6 Gurator 客户端

是 java写的一个api 库,可以更方便的在代码中调用。而不是 使用zkCli
就zkCli能操作的。Gurator都封装好方法了。调用就完事了。

7 zk 的分布式锁

7.1 zk中锁的种类

  • 读锁: 读锁是共享的,获取读锁的前提是没有写锁
  • 写锁:写锁是排他的,获取写锁的前提是没有任何锁

7.2 读锁的实现

  1. 创建一个临时序号节点,节点的数据是read. 表示是读锁。
  2. 获取zk中序号比自己小的所有节点。如果最小的节点是读锁。则上锁成功。因为如果最小的锁是读锁。后面不可能会有写锁。读锁共享。所以可以直接上锁。如果最小的节点是写锁。上锁失败,监听最小的节点。阻塞,如果最小节点释放了。然后重新执行第二步。

但是这样有一个坏处,并发的时候。多个客户端都监听 最小的节点,最小的节点释放之后会触发所有的客户端 重新获取锁。
也叫惊群效应。
解决方案:并发的操作,不去监听最小的,而是监听自己的上一个。这样就会按照请求的顺序依次获取锁。像个链表一样。

7.3 写锁的实现

  1. 创建一个临时序号节点,节点的数据是write.
  2. 获取zk中所有的子节点。
  3. 判断自己是不是最小的节点,如果是,上锁成功,如果不是,上锁失败,监听上一个节点。直到自己是最小的节点。

8 zk的watch机制

就是需要监听某一个节点的事件。类似于监听器。如果更新或删除了执行某些动作。

image

一个客户端修改了数据,另一个客户端会收到数据被修改的时间通知。
如果想监听是单次生效的。使用 get -w /test-watch

监听当前目录 ls -w /
监听当前目录及子目录 ls -w -R /

9 zk集群

9.1 伪集群,在一台服务器上创建四个目录。目录下分别有myid文件,保存id

└─# pwd                                                                  2 ⚙
/usr/local/zookeeper/zkdata
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/zkdata]
└─# ll                                                                   2 ⚙
total 16
drwxr-xr-x 2 root root 4096 Jan  1 21:55 zk1
drwxr-xr-x 2 root root 4096 Jan  1 21:55 zk2
drwxr-xr-x 2 root root 4096 Jan  1 21:55 zk3
drwxr-xr-x 2 root root 4096 Jan  1 21:55 zk4
(base) ┌──(root💀kali)-[/usr/local/zookeeper/zkdata/zk1]
└─# ll                                                                   2 ⚙
total 4
-rw-r--r-- 1 root root 2 Jan  1 21:55 myid
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/zkdata/zk1]
└─# cat myid                                                             2 ⚙
1

9.2 创建4个配置文件zoo*.cfg

每个配置文件的监听端口不一样,zoo1.cfg如下

tickTime=2000
dataDir=/usr/local/zookeeper/zkdata/zk1  # zk1-4 
clientPort=2181  # 客户端连接端口 2181-4
# 2001-4 是 集群间 数据同步端口, 3001-4是集群间选举用的。 oberver是代表当前节点的角色 
server.1=192.168.31.27:2001:3001
server.2=192.168.31.27:2002:3002
server.3=192.168.31.27:2003:3003
server.4=192.168.31.27:2004:3004:observer 
(base) ┌──(root💀kali)-[/usr/local/zookeeper/conf]
└─# ll                                                                   2 ⚙
total 36
-rw-r--r-- 1 lzl  staff  535 Feb 25  2022 configuration.xsl
-rw-r--r-- 1 lzl  staff 4559 Feb 25  2022 logback.xml
-rw-r--r-- 1 root root   201 Jan  1 22:02 zoo1.cfg
-rw-r--r-- 1 root root   201 Jan  1 22:05 zoo2.cfg
-rw-r--r-- 1 root root   201 Jan  1 22:06 zoo3.cfg
-rw-r--r-- 1 root root   201 Jan  1 22:06 zoo4.cfg
-rw-r--r-- 1 root root    57 Oct 23 16:02 zoo.cfg
-rw-r--r-- 1 lzl  staff 1187 Oct 23 16:00 zoo_sample.cfg

9.3 启动zk,分别使用不同的配置文件

└─# ./zkServer.sh start ../conf/zoo1.cfg                                 2 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: ../conf/zoo1.cfg
Starting zookeeper ... STARTED
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh start ../conf/zoo2.cfg                                 2 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: ../conf/zoo2.cfg
Starting zookeeper ... STARTED
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh start ../conf/zoo3.cfg                                 2 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: ../conf/zoo3.cfg
Starting zookeeper ... STARTED
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh start ../conf/zoo4.cfg                                 2 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: ../conf/zoo4.cfg
Starting zookeeper ... STARTED
                                                                             
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]

发现启动失败,看出启动日志。报错信息如下
image

(base) ┌──(root💀kali)-[/usr/local/zookeeper/logs]
└─# cat zookeeper-lzl-server-kali.out                                                                                                                                                                           1 ⚙
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
2023-01-01 22:34:17,833 [myid:] - INFO  [main:o.a.z.s.q.QuorumPeerConfig@177] - Reading configuration from: /usr/local/zookeeper/conf/zoo1.cfg
2023-01-01 22:34:17,859 [myid:] - INFO  [main:o.a.z.s.q.QuorumPeerConfig@440] - clientPortAddress is 0.0.0.0:2181
2023-01-01 22:34:17,860 [myid:] - INFO  [main:o.a.z.s.q.QuorumPeerConfig@444] - secureClientPort is not set
2023-01-01 22:34:17,860 [myid:] - INFO  [main:o.a.z.s.q.QuorumPeerConfig@460] - observerMasterPort is not set
2023-01-01 22:34:17,860 [myid:] - INFO  [main:o.a.z.s.q.QuorumPeerConfig@477] - metricsProvider.className is org.apache.zookeeper.metrics.impl.DefaultMetricsProvider
2023-01-01 22:34:17,884 [myid:1] - ERROR [main:o.a.z.s.q.QuorumPeerMain@99] - Invalid config, exiting abnormally
org.apache.zookeeper.server.quorum.QuorumPeerConfig$ConfigException: Error processing /usr/local/zookeeper/conf/zoo1.cfg
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:198)
        at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:125)
        at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:91)
Caused by: java.lang.IllegalArgumentException: initLimit is not set
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.checkValidity(QuorumPeerConfig.java:786)
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.setupQuorumPeerConfig(QuorumPeerConfig.java:663)
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parseProperties(QuorumPeerConfig.java:487)
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:194)
        ... 2 common frames omitted
Invalid config, exiting abnormally
2023-01-01 22:34:17,885 [myid:1] - INFO  [main:o.a.z.a.ZKAuditProvider@42] - ZooKeeper audit is disabled.
2023-01-01 22:34:17,889 [myid:1] - ERROR [main:o.a.z.u.ServiceUtils@42] - Exiting JVM with code 2

initLimit is not set
集群必须设置这个参数。。。
zoo*.cfg新增如下俩个参数

└─# cat zoo1.cfg                                                                                                                                                                                                1 ⚙
tickTime=2000
dataDir=/usr/local/zookeeper/zkdata/zk1
clientPort=2181
initLimit=10
syncLimit=5
# 
server.1=192.168.31.27:2001:3001
server.2=192.168.31.27:2002:3002
server.3=192.168.31.27:2003:3003
server.4=192.168.31.27:2004:3004:observer

重新启动后查看 每个节点的状态。全部启动之后才能查看得到。
启动是否成功,根据是否有对应的配置文件进程

(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh status /usr/local/zookeeper/conf/zoo4.cfg                                                                                                                                                     1 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/conf/zoo4.cfg
Client port found: 2184. Client address: localhost. Client SSL: false.
Mode: observer
                                                                                                                                                                                                                    
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh status /usr/local/zookeeper/conf/zoo3.cfg                                                                                                                                                     1 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/conf/zoo3.cfg
Client port found: 2183. Client address: localhost. Client SSL: false.
Mode: follower
                                                                                                                                                                                                                    
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh status /usr/local/zookeeper/conf/zoo2.cfg                                                                                                                                                     1 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/conf/zoo2.cfg
Client port found: 2182. Client address: localhost. Client SSL: false.
Mode: leader
                                                                                                                                                                                                                    
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]
└─# ./zkServer.sh status /usr/local/zookeeper/conf/zoo1.cfg                                                                                                                                                     1 ⚙
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/conf/zoo1.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
                                                                                                                                                                                                                    
(base) ┌──(root💀kali)-[/usr/local/zookeeper/bin]

9.4 连接集群

/zkCli.sh -server 192.168.31.27:2181,192.168.31.27:2182,192.168.31.27:2183,192.168.31.27:2184
四个节点的参数都填上。

10 ZAB 协议

zookeeper atomic broadcast 协议
微信翻译哈哈,zookeeper起名本来就是动物园管理的意思,因为好多产品都拿动物起名。其实就是zookeeper 原子广播协议
image

zookeeper是一主多从的。根据zab协议来 解决zookeeper的崩溃恢复和主从数据同步的问题。

10.1 集群节点的四个状态

  • following: 从节点所处的状态
  • leading: 主节点所处的状态
  • looking: 选举状态

10.2 集群上线时选举

先启动zoo1.cfg. 称为节点1.
再启动zoo2.cfg. 称为节点2.

节点1 给节点2 发送自己的选票。 选票格式:(myid,zXid) (当前节点的myid.集群中唯一,zxid是事务ID)(1, 0)
节点2 给节点1 发送自己的选票。(2, 0)

目前节点1有俩张选票,自己的(1,0) 和 节点2发送给节点1的(2,0)。根据zXid,myid 的优先级 谁大投谁。 投 (2,0)。节点2 有1票
为啥事务ID优先级比myid高:因为事务ID越大,说明请求越多。所以就让这个来当老大。
目前节点2也有俩张选票子节点(2,0) 和节点1 发送给节点2的(1,0)。投(2,0)。 节点2有1票。

目前还没有选出来主节点,当票数大于集群内所有节点个数的一半才行。
观察节点不参与选举,当前集群有三个节点参与选举。 不是已经启动的节点。是配置文件里所有的非观察节点。
还要继续投票。第二轮投票。把自己选票中最大的zxid,myid 发送给对方。
节点1 给节点2 (2,0),节点 2 有俩张选票(2,0)(第一轮自己的)(2,0)(第二轮节点1发给节点2的)
节点2 给节点1 (2, 0),节点 1 有俩张选票(2,0)(第一轮节点2发给节点1的,自己选出来的)(2,0)(第二轮节点2发给节点1的)

目前节点2 有2票。当选主节点

此时,再启动节点3. 查看集群已经有主节点,就不抢了。自己就当从节点。

10.3 崩溃恢复时的选举

节点2 是主节点。 当主节点 负责读写数据、从节点和观察节点只负责读数据。

当主节点挂掉之后。需要在从节点再选择一个主节点

主 从节点之间 会有故障检测。 就是2001,2002,2003,2004端口。
主节点周期性的发送ping命令给从节点。主节点挂掉之后,从节点一段时间没收到主节点的ping命令,就认为主节点挂了。
开始新一轮的选举。从节点的状态从following 切换为looking状态。选举就是集群上线时选举一样。

PS:没有leader就不对外提供服务。

10.4 主从节点的数据同步

客户端可能连接集群里的任意一台。
当读数据的时候。主从都一样。
但当写数据的时候。从会发送给主,让主来写数据。
主会先保存数据到 数据文件中,自己会给自己返回一个ack , 然后主会发送数据给所有的从节点。
从节点也是先保存数据到数据文件中,然后给主节点回复 ack, 当超过集群一半的节点 回复 ack给 主节点,也就是超过一般的节点已经写到自己的本地文件。
主节点就会发送commit给从节点。
从节点会保存数据到内存中。客户端读取数据是读取 内存里的数据。 不是数据文件中的。
然后客户端连接的主或从节点才会收到 写成功。

  • why 半数以上?
    kafka集群也有这个机制。
    为了提高吞吐量。 要是等所有的节点都 写成功才算成功。那么就会很慢。
    PS: 半数以上计算的时候 包括主节点

11 CAP理论

2000年提出的理论。分布式集群有了理论指导。

  • Consistency 一致性
    就是写成功返回给客户端的前提是所有的节点的数据已经保持一致了,这种叫强一致性。 zk不是这样子的,zk是最终一致性。半数以上之后。后面会同步未同步的节点。最后数据肯定会一致。
    但是有些系统不能使用最终一致性。比如银行,金融。 有一台数据没同步。查询的时候,发现钱没了。其实过几秒或几十秒会同步过来,但是还是对用户影响挺大的。

  • Availability 可用性
    服务可用就是当前集群能够提供正常的功能,能在正常的时间内返回,而不是时延太大。
    这个和 一致性就会有冲突。不可能同时满足。

  • Partition tolerance 分区容错性
    就是分布式系统,在多个节点的情况下,一个节点挂了。还能用。 这是分布式的目的。这个是必要条件。

所有CAP只能有其中俩个共存。

CP 或 AP
zk属于AP
CA就是单机了。不算分布式了。个人理解。

12 BASE理论

就是在特殊情况下,系统的功能不一定要全部能用。比如双十一的时候。那天晚上退款功能,评论功能会禁止取消。为了给下单功能让路。

  • Basically Available 基本可用
    核心功能能用。 服务降级。
  • Soft State 软状态
    系统存在中间状态。该中间状态不影响系统整体可用。 运行不同的节点之间数据不一致。延时一致。
  • Eventual Consistency
    就是在运行一定时间后,所有节点的数据保证会一致。 也叫弱一致性。

13 关于分布式推荐书籍

-《分布式高可用算法》

posted on 2023-01-02 00:12  llcl  阅读(238)  评论(0编辑  收藏  举报