• 【zookeeper】zk选举、使用与三种节点简介,以及基于redis分布式锁的缺点的讨论


    这里我准备了4台虚拟机,从node1到node4,其myid也从1到4.

    一,zk server的启动和选举

    zk需要至少启动3台Server,按照配置的myid,选举出参与选举的myid最大的server为Leader。(与redis的master、slave不同,zk的叫leader、follower)。
    如果已经选举成功,那么即使新加入的zk server的myid比现有leader的myid更大,也不会成为新的leader,除非现有的Leader挂掉,那么新加入的myid最大的zk server会成为leader。

    我们通过zkServer.sh start-foreground命令来前台阻塞的启动zk server,这样方便看到日志输出。注意,start 和-foreground之间是没有空格的。

    启动后,看到如下日志,是已经启动成功。后面的日志是一些同步快照的日志。(前面有异常是因为其他zk server还没有起来)
    在这里插入图片描述

    二、zk cli的启动和基础命令

    我们通过zkCLi.sh,默认的连接Localhost,本机(node1,一个folloer)上的server,连上了follower,就连上了zk集群。你在follower上做的增改,会发送到leader那里,由leader广播给所有zk的follower。

    进入客户端后,使用help查看zk cli的命令。如下所示

    [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 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    刚进入zk,zk的根节点/下会有一个默认的节点zookeeper

    [zk: localhost:2181(CONNECTED) 1] ls /
    [zookeeper]
    
    
    • 1
    • 2
    • 3

    create:当然你可以自己去在根节点下创建一个新的节点Node1。
    在创建节点时,可以在节点名字后面跟上你想要赋予节点的信息,这里我跟了一个空字符串,在我这个版本3.7也可以将空串直接不写,存储的信息就是空。

    [zk: localhost:2181(CONNECTED) 2] create /node1 ""
    Created /node1
    [zk: localhost:2181(CONNECTED) 3] ls /
    [node1, zookeeper]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在node1下再创建一个节点node2

    [zk: localhost:2181(CONNECTED) 4] create /node1/node2 ""
    Created /node1/node2
    
    
    • 1
    • 2
    • 3

    set:可以更改节点中的信息

    
    [zk: localhost:2181(CONNECTED) 8] set /node1/node2 "this is node2"
    
    
    
    • 1
    • 2
    • 3
    • 4

    get:可以获取节点中的信息,带上-s可以在信息的下面带上节点的事务id等信息,效果同stat命令。

    [zk: localhost:2181(CONNECTED) 9] get /node1/node2
    this is node2
    
    • 1
    • 2

    stat:获取节点的事务id、创建和修改时间等信息。

    这些信息每个数据节点如/node1,每个数据节点都会有自己的一份。

    其中,cZxid为创建节点事务id,开头的0x表示数据为16进制,x后的2表示集群leader为第几代(集群旧的leader挂掉,新的Leader上台,这个数就会+1)。2后面的8位16进制,表示节点创建的事务id,数值范围为从0~16^8。

    类似的,mZxid为修改节点事务id,pZxid为该节点的子节点(或该节点)的最近一次创建 / 删除 的事务id。

    //todo cZxid mZxid如何递增

    [zk: localhost:2181(CONNECTED) 15] stat /node1
    cZxid = 0x200000002
    ctime = Fri Sep 22 00:12:28 PDT 2023
    mZxid = 0x200000002
    mtime = Fri Sep 22 00:12:28 PDT 2023
    pZxid = 0x200000003
    cversion = 1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 0
    numChildren = 1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三,zk的三种节点

    zk有三种节点,永久节点临时节点序列节点

    永久节点
    我们使用create命令,不加参数,创建的是第一种节点,即永久节点,这种节点不会随着客户端断开连接而消失,也没有序列号。

    临时节点
    使用create -e,创建的节点为临时节点。

    这种节点会随着客户端断开连接,如果未在一定时间内重新连接,临时节点数据将会在集群内被清除。

    假设客户端cli连接的server挂掉,导致客户端断开连接,如果客户端在一定时间内重新连接上,临时节点仍然不会被清除。这是因为客户端在连接server的时候,会产生一个会话session,客户端提示如下图所示。

    session id = 0x1000014a34d0000, negotiated timeout = 30000
    session id 0x1000014a34d0000将会被同步到整个集群(这次同步也会增加一次事务id),使得每个server都会持有这个客户端的session id。
    negotiated timeout = 30000意为客户端断连后需要在3秒内重新连接,否则视为退出。
    在这里插入图片描述

    node1上的这台服务端也会有日志,session id会作为全局id提交给集群。
    在这里插入图片描述

    创建临时节点后,可以通过stat命令结果中的ephemeralOwner查看该临时节点的创建者的session id。

    [zk: localhost:2181(CONNECTED) 23] create -e /node4 "this is node4"
    Created /node4
    [zk: localhost:2181(CONNECTED) 24] stat /node4
    cZxid = 0x200000007
    ctime = Fri Sep 22 01:03:39 PDT 2023
    mZxid = 0x200000007
    mtime = Fri Sep 22 01:03:39 PDT 2023
    pZxid = 0x200000007
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x1000014a34d0000
    dataLength = 13
    numChildren = 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    毫无疑问,临时节点天然就可以用来表征其他集群中节点的状态。也很适合做分布式锁,抢占锁,就在某数据节点(如表示某系统的节点)如/DataCenter下创建一个固定名称如Lock临时节点,能创建,即为抢占到锁,且能通过stat查看到锁的主人是哪一台服务器。不能抢占,即为锁被抢占,要进行等待。

    zk的分布式锁,相较于redis实现的分布式锁,要更简单。

    因为redis想要不死锁,需要指定一个固定的过期时间,指定的过期时间长了,锁性能不高;指定过期时间短了,还没操作完锁就被释放了。

    为此,redis分布式锁的实现者们需要考虑诸如引入守护线程或者线程池[1] (因为锁持有者释放锁后守护线程没用了就要被销毁,引入线程池减小线程开销)为锁自动续过期时间,例如Redission的WatchDog看门狗机制[1];而早期的setnx命令+expire命令不具备原子性,为此需要引入Lua脚本等等诸多问题[2](redis 2.7后的版本可以在set 命令上同时指定过期时间参数和nx参数)。

    zk就不一样,zk的临时节点销毁由zk自己保证,leader挂掉后可在200毫秒内选举出新的Leader,且性能极高[3],使用者不需要考虑太多。
    在这里插入图片描述
    在这里插入图片描述

    序列节点
    使用create -s创建的节点为序列节点。这种节点在创建节点如create -s node时,不会直接创建Node,而是会在node后面跟上一个从0开始的序列号,每创建一个,序列号就+1。即使这些序列节点都删除了,再创建序列节点,仍然会再之前的基础上再+1.

    可以在某个节点如node下创建序列节点,可以实现一个类似于队列的特性,按照创建顺序来争抢代表了node的锁。

    关于zk的暂时就先写这么多,后面有了再继续写或者补充。

    参考文章:
    [1],面试官:Redis 分布式锁如何自动续期?
    [2],面试被问Redis锁🔒的缺点,被打击的扎心了
    [3],ZooKeeper

  • 相关阅读:
    Oracle-opatchauto自动安装补丁失败导致RAC集群异常问题
    LaTeX之一:macos上latex环境搭建(homebrew安装+vscode配置+ MacTex)和B站视频、网站、教程等相关资料推荐(Overleaf、公式预览网站)
    自动化测试如何准备测试数据
    都2022年了,Python Web框架你不会只知道Django和Flask吧?
    30.10.2 认证插件更新
    gsap中文地址
    JavaScript的位操作符你知道吗?
    LTD248次升级 | 竞赛数字化:在线答题赛、反复多轮赛,答题领取现金 • 官微名片展示个人简介 • 官网可搜索各类文件
    redis Lettuce客户端
    Redis入门 看这一篇就够了
  • 原文地址:https://blog.csdn.net/gengzhihao10/article/details/133184402