zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

多台阿里云服务器上搭建ZooKeeper集群

2023-09-11 14:17:51 时间

0. 前言

为测试方便,电脑最好可以跑多台虚拟机,或者有2-3个云服务器(学生机9.9一月,可以买一个轻量级和ECS,或者借同学的用一下)

1. Dubbo 与 SpringCloud对比

  • dubbozookeeper + dubbo + springmvc + springboot
    • 官方地址:http://dubbo.apache.org/#!/?lang=zh-cn
    • 配套通信方式:rpc 性能高
    • 注册中心:zookeper/redis
    • 配置中心:diamond(企业很少用)
  • springcloud: 全家桶 + 轻松嵌入第三方组件(Netflix 奈飞)
    • 官网:http://projects.spring.io/spring-cloud/
    • 配套通信方式:http restful
    • 注册中心:eruka/consul
    • 配置中心:config
    • 断路器:hystrix
    • 网关:zuul
    • 分布式追踪系统:sleuth+zipkin
  • 二者对比:
DubboSpringCloud
服务注册中心ZookeeperSpring Cloud Netfilx Eureka
服务调用方式RPCREST API/HTTP
服务监控Dubbo-monitorSpring Boot Admin
断路器不完善Spring Cloud Netfilx Hystrix
服务网关Spring Cloud Netfilx Zuul
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth
消息总栈Spring Cloud Bus
数据流Spring Cloud Stream
批量任务Spring Cloud Task

最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式

严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这个优点在当下强调快速演化的微服务环境下,显得更加合适。

2. 微服务注册中心

简介:什么是注册中心,常用的注册中心有哪些?

  • 注册中心:服务管理,核心是有个服务注册表,心跳机制动态维护;
  • 服务提供者provider: 启动的时候向注册中心上报自己的网络信息
  • 服务消费者consumer: 启动的时候向注册中心上报自己的网络信息,拉取provider的相关网络信息

为什么要用注册中心?

微服务应用和机器越来越多,调用方需要知道接口的网络地址,如果靠配置文件的方式去控制网络地址,对于动态新增机器,维护带来很大问题!

主流的微服务注册中心

  • zookeeper(与Dubbo结合使用)

  • Eureka(与SpringCloud结合使用)

  • consul(与SpringCloud结合使用)

  • etcd(与SpringCloud结合使用)

在这里插入图片描述

3. Zookeeper下载与安装

[Zookeeper官网下载地址][https://zookeeper.apache.org/releases.html#download]

3.1 在CentOS下安装Zookeeper

注意: Zookeeper 的安装依赖于jdk环境!所以先确保服务器活着虚拟机中配置过了jdk环境!

  • 将下载的zookeeper压缩包上传到云服务器,我自己是将所有压缩包放到**/usr/local/src/software/ **下

    • tar -zxvf zookeeper-3.4.14.tar.gz 解压zookeeper压缩包

    • mv zookeeper-3.4.14 zookeeper 修改文件夹名字为zookeeper方便记忆

    • 在zookeeper目录下创建data 目录mkdir data,并pwd获取data目录的路径**/usr/local/src/software/zookeeper/data**

    • cd /usr/local/src/software/zookeeper/conf 进入conf目录下

      • mv zoo_sample.cfg zoo.cfg修改zoo_sample.cfg文件名称为zoo.cfg

      • vim zoo.cfg 修改配置文件,wq保存退出:

        在这里插入图片描述

    • useradd zookeeper 创建一个名为zookeeper的用户

    • chown -R zookeeper:zookeeper zookeeper/ 将zookeeper文件夹权限交给刚添加的zookeeper用户

      在这里插入图片描述

  • 然后我们就可以进行启动zookeeper操作了

    • 我们进入zookeeper的bin目录中:

      在这里插入图片描述

    • ./zkServer.sh start 启动zookeeper:

      在这里插入图片描述

  • 为了验证是否启动成功,我们来使用客户端连接一下zookeeper服务:

    • 先使用netstat -tlun 查看端口服务开启情况:

      在这里插入图片描述

    • 建议可以直接把防火墙关闭,这样就不用在防火墙中添加规则了

    • 阿里云安全组开端口

      在这里插入图片描述

    • 然后我们在本机电脑(windows下zookeeper下载好解压即可使用)上用zookeeper的客户端连接下服务器的zookeeper

      • .\zkCli.cmd -timeout 5000 -server X.XXX.XX.XXX:2181 ip地址为自己服务其的ip

        在这里插入图片描述

        在这里插入图片描述

      • 完成连接zookeeper!

3.2 ZooKeeper数据模型

在这里插入图片描述

  • 每一个节点都叫做zNode,可以有子节点,也可以有数据
  • 每个节点都能设置相应的权限控制用户的访问
  • 每个节点存储的数据不宜过大
  • 每个节点都带有一个版本号,数据变更时,版本号变更(乐观锁)
  • 节点分永久节点跟临时节点

4. Zookeeper 常用命令之zkCli

  • chown -R zookeeper:zookeeper zookeeper/ 将zookeeper文件夹权限赋给zookeeper用户

  • su zookeeper 切换到zookeeper用户

  • 然后进入zookeeper的bin目录下执行./zkServer.sh start启动zookeeper,关闭zookeeper ./zkServer.sh stop

    • 如果出现下面错误信息,说明zookeeper权限赋于失败,重新su root 切换root 用户再次将整个zookeeper文件夹的权限赋给zookeeper用户:

      a

  • 然后即可成功启动:

    在这里插入图片描述

  • 然后我们就可以来学习下zkCli 命令

4.1 zkCli命令

  • 启动zkCli ,在bin目录下执行./zkCli.sh -h
  • 关闭zkCli,close
ZooKeeper -server host:port cmd args
	stat path [watch]
	set path data [version]
	ls path [watch]
	delquota [-n|-b] path
	ls2 path [watch]
	setAcl path acl
	setquota -n|-b val path
	history 
	redo cmdno
	printwatches on|off
	delete path [version]
	sync path
	listquota path
	rmr path
	get path [watch]
	create [-s] [-e] path data acl
	addauth scheme auth
	quit 
	getAcl path
	close 
	connect host:port

创建节点和查看节点

  • create [-s] [-e] path acl 创建节点

    • -s : 表示创建顺序节点

    • -e : 表示创建临时节点

    • data : 表示创建的节点的数据内容

      在这里插入图片描述

  • 查看节点

    • 获取根节点:ls /

    • 获取某个节点的子节点:ls /path,eg:ls /csp0020000000001

    • 获取某个节点的数据:get /path

      [zk: localhost:2181(CONNECTED) 5] get /csp0010000000000
      csp001												---> 节点的值
      cZxid = 0x5									          ---> 事务id
      ctime = Wed Nov 18 16:06:18 CST 2020			         ---> 节点创建的时间
      mZxid = 0x5											 ---> 最后一次更新时的事务id
      mtime = Wed Nov 18 16:06:18 CST 2020					---> 最后一次更新的时间
      pZxid = 0x5											 ---> 该节点的子节点列表最后一次被修改的事务id
      cversion = 0										 ---> 子节点列表的版本
      dataVersion = 0									      ---> 数据内容的版本
      aclVersion = 0									      ---> acl版本
      ephemeralOwner = 0x0								  ---> 用于临时节点,表示创建该临时节点的事务id
      														如果当前节点不是临时节点,则该字段值为0
      dataLength = 6										 ---> 数据内容的长度
      numChildren = 0										 ---> 子节点的数量
      
    • 查看某个节点的状态:stat /path

      [zk: localhost:2181(CONNECTED) 4] stat /csp0020000000001    
      cZxid = 0x5									          ---> 事务id
      ctime = Wed Nov 18 16:06:18 CST 2020			         ---> 节点创建的时间
      mZxid = 0x5											 ---> 最后一次更新时的事务id
      mtime = Wed Nov 18 16:06:18 CST 2020					---> 最后一次更新的时间
      pZxid = 0x5											 ---> 该节点的子节点列表最后一次被修改的事务id
      cversion = 0										 ---> 子节点列表的版本
      dataVersion = 0									      ---> 数据内容的版本
      aclVersion = 0									      ---> acl版本
      ephemeralOwner = 0x0								  ---> 用于临时节点,表示创建该临时节点的事务id
      														如果当前节点不是临时节点,则该字段值为0
      dataLength = 6										 ---> 数据内容的长度
      numChildren = 0										 ---> 子节点的数量
      
    • 获取某个节点的子节点以及当前节点的状态:ls2 /path

      [zk: localhost:2181(CONNECTED) 6] create -e /csp0010000000000/csp1999 my name is csp #为该节点添加临时子节点
      Created /csp0010000000000/csp1999
      [zk: localhost:2181(CONNECTED) 7] ls2 /csp0010000000000  #获取该节点的子节点以及当前节点的状态
      [csp1999]  #该节点的子节点
      cZxid = 0x4
      ctime = Wed Nov 18 16:05:27 CST 2020
      mZxid = 0x4
      mtime = Wed Nov 18 16:05:27 CST 2020
      pZxid = 0xc
      cversion = 1
      dataVersion = 0
      aclVersion = 0
      ephemeralOwner = 0x0
      dataLength = 6
      numChildren = 1
      [zk: localhost:2181(CONNECTED) 8] 
      

修改节点

  • 修改节点的数据:set /path data [version]

    [zk: localhost:2181(CONNECTED) 10] set /csp0010000000000 HelloWorld    
    cZxid = 0x4
    ctime = Wed Nov 18 16:05:27 CST 2020
    mZxid = 0xd
    mtime = Wed Nov 18 16:28:10 CST 2020
    pZxid = 0xc
    cversion = 1
    dataVersion = 1  # dataVersion 由0变为1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 10
    numChildren = 1
    [zk: localhost:2181(CONNECTED) 11] get /csp0010000000000
    HelloWorld
    cZxid = 0x4
    ctime = Wed Nov 18 16:05:27 CST 2020
    mZxid = 0xd
    mtime = Wed Nov 18 16:28:10 CST 2020
    pZxid = 0xc
    cversion = 1
    dataVersion = 1  # dataVersion 由0变为1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 10
    numChildren = 1
    
    # dataVersion 其实就相当于MySQL中的乐观锁,即数据的版本号
    # 如果set 命令修改节点的数据时,附带上version,如果版本号不匹配,就不能修改!
    # 例如:
    [zk: localhost:2181(CONNECTED) 12] set /csp0010000000000 HelloWorld 0
    version No is not valid : /csp0010000000000 # version 不匹配,不能修改
    [zk: localhost:2181(CONNECTED) 13] set /csp0010000000000 HelloWorld 2 
    version No is not valid : /csp0010000000000 # version 不匹配,不能修改
    [zk: localhost:2181(CONNECTED) 14] set /csp0010000000000 HelloWorld 1 # version匹配修改成功!
    cZxid = 0x4
    ctime = Wed Nov 18 16:05:27 CST 2020
    mZxid = 0x10
    mtime = Wed Nov 18 16:33:34 CST 2020
    pZxid = 0xc
    cversion = 1
    dataVersion = 2 # dataVersion 由1变为2
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 10
    numChildren = 1
    

删除节点

  • delete /path [version] 非递归删除
  • rmr /path [version] 递归删除
[zk: localhost:2181(CONNECTED) 15] ls /
[csp0010000000000, csp0040000000003, zookeeper, csp0020000000001, csp0030000000002]
[zk: localhost:2181(CONNECTED) 16] delete /csp0030000000002  # 该节点没有子节点,可以直接删除
[zk: localhost:2181(CONNECTED) 17] ls /                    
[csp0010000000000, csp0040000000003, zookeeper, csp0020000000001] # 删除成功!
[zk: localhost:2181(CONNECTED) 18] delete /csp0010000000000 # 该节点有子节点,不可以直接删除
Node not empty: /csp0010000000000 # 该节点有子节点,删除失败!
[zk: localhost:2181(CONNECTED) 19] rmr /csp0010000000000 # 使用递归删除
[zk: localhost:2181(CONNECTED) 20] ls /                    
[csp0040000000003, zookeeper, csp0020000000001] # 删除成功!

5. Zookeeper 中的Session 机制 与 Watcher 机制

5.1 Zookeeper 中的Session 机制

  • 用于客户端与服务端之间的连接,可设置超时时间,通过心跳包的机制(客户端向服务端ping包请求)检查心跳结束,session就过期
  • session过期的时候,该session创建的所有临时节点都会被抛弃

5.2 Zookeeper 中的Watcher 机制

在这里插入图片描述

  • 对节点的watcher操作 get/stat + watch

    针对每一个节点的操作,都可以有一个监控者,当节点发生变化,会触发watcher事件 zk中watcher是一次性的,触发后立即销毁 所有有监控者的节点的变更操作都能触发watcher事件

    • 为什么说watch事件是一次性的呢?看下实操:

      在这里插入图片描述

      在这里插入图片描述

      前面哪个客户端打印的结果是:

      在这里插入图片描述

  • 子节点的watcher操作(监控父节点,当父节点对应的子节点发生变更的时候,父节点上的watcher事件会被触发)ls/ls2 + watch删会触发、修改不会,如果子节点再去新增子节点,不会触发(也就是说,触发watcher事件一定是直系子节点

6. Zookeeper 中的 ACL 权限控制

  • 针对节点可以设置相关的读写等权限,目的是为了保证数据的安全性

  • 权限permissions可以指定不同的权限范围及角色

  • 常用的命令

    • getAcl 获取节点权限
    • setAcl 设置节点权限
    • addauth 输入认证授权信息,注册时输入明文密码,但是在zk里,以加密的形式保存
    [zk: localhost:2181(CONNECTED) 3] rmr /csp0001
    [zk: localhost:2181(CONNECTED) 4] create /csp0001 HelloWorld
    Created /csp0001
    [zk: localhost:2181(CONNECTED) 5] getAcl /csp0001 # 获取节点权限
    'world,'anyone
    : cdrwa  # acl 的组成[scheme:id: permissions]
    
  • acl 的组成**[scheme: id:permissions]** ,即:【约束:id:权限】

  • scheme 授权机制

    • world 下只有一个id,也就是anyone,表示所有人 world:anyone:permissions
    • auth 代表认证登录,需要注册用户有权限才可以 auth:user:password:permissions
    • digest 需要密码加密才能访问 digest:username:BASE64(SHA1(password)):permissions(跟auth区别在于,auth明文,digest为密文)
    • ip 例如:ip:localhost:psermissions
    • super 代表超管,拥有所有的权限;
    • 打开zk目录下的/bin/zkServer.sh服务器脚本文件,找到如下一行:
  • id:允许访问的用户

  • permissions:权限组合字符串

    cdrwa:
    c ---> create 创建子节点
    d ---> delete 删除子节点
    r ---> read 读取节点的数据
    w ---> write 写入数据
    a ---> admin 可管理的权限
    cdrwa cdr cdw 
    
  • acl的使用场景:

  • 开发环境跟测试环境,使用acl就可以进行分离,开发者无权去操作测试的节点,生产环境上控制指定ip的服务可以访问相关的节点

7. Zookeeper 中的三种角色及其选举机制

7.1 三种角色及其作用

  • leader:作为整个zk集群写请求的唯一处理者,并负责进行投票的发起和决议,更新系统的状态
  • follower接收客户端请求,处理读请求,并向客户端返回结果;将写请求转给 Leader;在选举 Leader过程中参与投票。
  • observer:可以理解为无选举投票权的 Flollower,其主要是为了协助 Follower 处理更多的读请求。如果 Zookeeper 集群的读请求负载很高,或者客户端非常非常多,多到跨机房,则可以设置一些 Observer 服务器,以提高读取的吞吐量。

7.2 注册中心常见的三种模式

  • zk的核心是广播机制,该机制保证了各个zk之间数据同步(数据一致性)zk实现的机制为ZAB协议
  • 恢复模式: 如果leader崩溃,这个时候就会进入恢复模式,使整个zk集群恢复到正常的工作状态
  • 同步模式:新的leader选举出来后,就乎进入同步模式(各个follower会去同步新的leader上的数据),当大多数zkServer完成了与leader的状态同步之后,恢复模式就结束
  • 广播模式:客户端想写入数据,这个时候leader发起提议,当leader的提议被大多数的zkServer统一之后,leader就会去修改自身的数据,并将修改后的数据广播给其他的follower

7.3 Zookeeper 的选举机制

  • myid

    这是 zk 集群中服务器的唯一标识,称为 myid。例如,有三个 zk 服务器,那么编号分别是 1,2,3。

  • zxid

    ReentranReadWriteLock 32位
    
    高位              低位
    0000000000000000  0000000000000000
    
                       epoch                                 xid
    00000000000000000000000000000000   00000000000000000000000000000000
    zxid 为 Long 类型,其中高 32 位表示 epoch,低 32 位表示 xid。即 zxid 由两部分构成:epoch 与 xid。
    每个 Leader 都会具有一个不同的 epoch 值,表示一个时期、时代。新的 Leader 产生,则会更新所有zkServer 的 zxid 中的 epoch。
    而 xid 则为 zk 的事务 id,每一个写操作都是一个事务,都会有一个 xid。每一个写操作都需要由 Leader 发起一个提议,由所有 Follower 表决是否同意本次写操作。
    
  • 逻辑时钟

    逻辑时钟,Logicalclock,是一个整型数,该概念在选举时称为 logicalclock,而在 zxid 中则为 epoch 的值。即 epoch 与 logicalclock 是同一个值,在不同情况下的不同名称。

  • zk的选举状态

    LOOKING,选举状态(查找 Leader 的状态)。
    LEADING,领导者状态。处于该状态的服务器称为 Leader。
    FOLLOWING,随从状态,同步 leader 状态。处于该状态的服务器称为 Follower。
    OBSERVING,观察状态,同步 leader 状态。处于该状态的服务器称为 Observer。
    

8. Zookeeper 集群搭建实操

首先我准备了三台阿里云服务器(如果没有服务器,可以考虑克隆自己本地的虚拟机克隆3台):

在这里插入图片描述

然后按照章节3 的步骤,为其他两个服务器搭建好zookeeper环境!

注意:搭建zookeeper集群的时候别忘了给阿里云服务器安全组的对应端口都开放!

  • 端口的作用

    • 2181 对client端提供服务
    • 2888 集群内及其通讯使用的端口
    • 3888 集群选举leader
  • 修改三台服务器的 zk 配置

    • 进入zookeeper的conf目录下修改zoo.cfg,添加如下内容:

      dataDir=/usr/local/src/software/zookeeper/data
      # the port at which the clients will connect
      clientPort=2181
      server.1=8.XXX.XX.136:2182:2183
      server.2=8.XXX.XX.45:2182:2183
      server.3=39.XXX.XXX.61:2182:2183
      
    • 在zk的根目录下,新建一个data目录,并在data目录下新增一个myid的文件

    • 将修改好配置的zk,分别放到三台服务器的**/usr/local/src/software/zookeeper**中,并将目录权限改为zookeeper用户

    • 三台服务器,分别新增一个叫做zookeeper的用户 useradd zookeeper

    • 三台服务器,均修改 **/usr/local/src/software/zookeeper/data/**目录里的myid文件,文件内容是一个数字,对应server.1=8.XXX.XX.136:2182:2183 里的1,依次类推!

    • 三台服务器的zk的权限,都赋给zookeeper用户chown -R zookeeper:zookeeper zookeeper/

    • 关闭防火墙 : systemctl stop firewalld.service

    • 进入zk的bin目录:rm -rf *.cmd,然后chmod +x *.sh

    • 从第一台机子开始依次启动zookeeper服务:./zkServer.sh start

    • 三台机子均启动完成之后,可以使用zkServer.sh status去查看状态

    查看结果如图:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    这样就搭建成了三台阿里云服务器,一台leader,两台follower的集群了!

    踩坑:

    如果运行zookeeper后,./zkServer status 查看状态出现如下错误:

    在这里插入图片描述

    可以参考这篇文章补坑:https://blog.csdn.net/kenneth_chen_/article/details/83059470

Zookeeper集群搭建另一篇参考文章

如果文章对您有帮助,请点赞支持一下~