分布式高可用的ZooKeeper集群搭建与基本操作

本文详细介绍了ZooKeeper,一种用于分布式应用的协调服务。它提供了简单原语,如创建、删除、读取节点,用于解决分布式环境中命名、配置、同步等问题。ZooKeeper强调高性能、高可用性和严格有序访问,支持复制和快速选举Leader。文章还展示了如何搭建和操作ZK集群,以及Leader选举过程。
摘要由CSDN通过智能技术生成

ZooKeeper介绍

ZooKeeper是一个为分布式应用提供的分布式、开源的协调服务

它公开了一组简单的原语,分布式应用程序可以根据这些原语来实现用于同步、配置维护以及组和命名的更高级别的服务。

怎么理解协调服务呢?比如我们有很多应用程序,他们之间都需要读写维护一个id,那么这些id怎么命名呢,程序一多,必然会乱套,ZooKeeper能协调这些服务,解决命名、配置、同步等问题,而做到这些,只需要一组简单的原语即可:

create : 在树中的某个位置创建一个节点

delete : 删除一个节点

exists : 测试节点是否存在于某个位置

get data : 从节点读取数据

set data : 往一个节点里写入数据

get children : 检索节点的子节点列表

sync : 等待数据被传播

从这些ZooKeeper(以下简称ZK)的API可以看到,都是围绕node来操作,下文实操看一下怎么操作node。

ZK的特征

  • 简单

ZooKeeper允许分布式进程通过共享的层级命名空间相互协调,该命名空间的组织类似于标准文件系统。

命名空间由数据寄存器组成——在ZooKeeper的说法中称为znodes——它们类似于文件和目录。与典型的文件系统不同,它是为存储而设计的,ZooKeeper数据保存在内存中,这意味着ZooKeeper可以实现高吞吐量低延迟数

ZooKeeper很重视高性能高可用性严格有序访问

ZooKeeper的性能方面意味着它可以在大型分布式系统中使用。

可靠性方面使它不会成为单点故障。

严格的排序意味着可以在客户端上实现复杂的同步原语。

  • 可被复制

像它协调的分布式进程一样,ZooKeeper本身也可以在称为集合的一组主机上进行复制。

组成ZooKeeper服务的服务器都必须彼此了解。它们维护内存中的状态镜像,以及持久存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper服务将可用。

客户端连接到单个ZooKeeper服务器。客户端维护一个TCP连接,通过该连接发送请求,获取响应,获取监视事件并发送心跳。如果与服务器的TCP连接断开,则客户端将连接到其他服务器。

在这里插入图片描述

  • 有序的

ZooKeeper用一个反映所有ZooKeeper事务顺序的数字标记每个更新。后续操作可以使用该命令来实现更高级别的抽象,例如同步原语。

在“读取为主”的工作负载中,它特别快。ZooKeeper应用程序可在数千台计算机上运行,并且在读取比写入更常见的情况下,其性能最佳,比率约为10:1。

分层命名空间

ZooKeeper提供的名称空间与标准文件系统的名称空间非常相似。名称是由斜杠(/)分隔的一系列路径元素。ZooKeeper命名空间中的每个节点均由路径标识。

在这里插入图片描述

一个zk node可以存储1M数据,node分为持久节点和临时性节点。

  • 持久节点

与标准文件系统不同,ZooKeeper命名空间中的每个节点都可以具有与其关联的数据以及子节点。就像拥有一个文件系统一样,该文件系统也允许文件成为目录。(ZooKeeper旨在存储协调数据:状态信息,配置,位置信息等,因此存储在每个节点上的数据通常很小,在字节到千字节范围内。)

Znodes维护一个统计信息结构,其中包括用于数据更改,ACL更改和时间戳的版本号,以允许进行缓存验证和协调更新。znode的数据每次更改时,版本号都会增加。例如,每当客户端检索数据时,它也会接收数据的版本。

原子地读取和写入存储在名称空间中每个znode上的数据。读取将获取与znode关联的所有数据字节,而写入将替换所有数据。每个节点都有一个访问控制列表(ACL),用于限制谁可以做什么。

  • 临时节点

只要创建znode的会话处于活动状态,这些znode就存在。会话结束时,将删除znode。

类比于web容器比如tomcat的session,创建临时节点的session存在,则node存在,session结束,删除node。

以上BB了这么多,还是实际操作一遍比较靠谱,理解一下zk创建连接、node、session这些概念,以及看看zk的leader出故障后,选出leader的速度。

搭建ZK集群

首先准备4台CentOS 7虚拟机,都安装好了JDK 11(JDK版本最好不要小于8)。

在这里插入图片描述

先配置好一台服务器的zk,然后用scp分发到各个服务器,再分别修改zk server的id。

下载zk,注意一定要是apache-zookeeper-3.6.2-bin.tar.gz这个带bin的,否则如果不是带bin的,启动的时候会报如下错误:

Error: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain
Caused by: java.lang.ClassNotFoundException: org.apache.zookeeper.server.quorum.QuorumPeerMain

安装zk步骤:

将下载好的apache-zookeeper-3.6.2-bin.tar.gz放到/opt目录下
1. cd /opt
2. tar xf apache-zookeeper-3.6.2-bin.tar.gz
3. mv apache-zookeeper-3.6.2-bin zookeeper
4. vi /etc/profile

export JAVA_HOME=/opt/jdk-11.0.8
export ZK_HOME=/opt/zookeeper
export PATH=$PATH:$JAVA_HOME/bin:$ZK_HOME/bin

5. source /etc/profile
6. cd /opt/zookeeper/conf
7. cp zoo_example.cfg zoo.cfg
8. vi zoo.cfg

设置 dataDir=/var/zookeeper
末尾:
server.1=zknode1:2888:3888
server.2=zknode2:2888:3888
server.3=zknode3:2888:3888
server.4=zknode4:2888:3888

9. mkdir -p /var/zookeeper
10. echo 1 > /var/zookeeper/myid

这样zknode1的zkserver就搭建好了,现在将zk和配置文件分发到其余三台服务器:

scp -r /opt/zookeeper/ root@zknode2:/opt/
scp /opt/zookeeper/conf/zoo.cfg root@zknode2:/opt/zookeeper/conf/
scp /etc/profile

对zknode3、zknode4如法炮制。

别忘了,每台主机都需要执行source /etc/profile和创建/var/zookeeper/myid文件,myid的内容分别为2,3,4。

这样zk集群就搭建好了。

启动zk集群

按顺序启动zknode1,zknode2,zknode3,zknode4的zk服务

zkServer.sh start-foreground

zk默认后台启动,start-foreground表示前台启动,方便看日志。

启动zknode1的zk server:

在这里插入图片描述

会报错,因为zoo.cfg配置了4台主机,其余三台还未启动,接着启动zknode2的:

在这里插入图片描述

现象同zknode1,继续启动第三台:

在这里插入图片描述

这个时候也会报zknode4连接不上(因为还没启动),但是整个zk集群已经启动了,并且选择了zknode3这个为leader。

把zknode4也启动一下:

在这里插入图片描述

启动完成后,开一个zknode1的zk客户端:

zkCli.sh

[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] path
	get [-s] [-w] path
	getAcl [-s] path
	getAllChildrenNumber path
	getEphemerals path
	history 
	listquota path
	ls [-s] [-w] [-R] path
	printwatches on|off
	quit 

用上面的命令操作一波:

[zk: localhost:2181(CONNECTED) 1] ls
ls [-s] [-w] [-R] path
[zk: localhost:2181(CONNECTED) 2] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 3] 
[zk: localhost:2181(CONNECTED) 3] create /laogong
Created /laogong
[zk: localhost:2181(CONNECTED) 4] ls /
[laogong, zookeeper]
[zk: localhost:2181(CONNECTED) 5] get /laogong 
null
[zk: localhost:2181(CONNECTED) 6] create /laogong "laogong"
Node already exists: /laogong
[zk: localhost:2181(CONNECTED) 7] delete /laogong
[zk: localhost:2181(CONNECTED) 8] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 9] create /laogong "laogong"
Created /laogong
[zk: localhost:2181(CONNECTED) 10] ls /
[laogong, zookeeper]
[zk: localhost:2181(CONNECTED) 11] get /laogong
laogong
[zk: localhost:2181(CONNECTED) 12] create /laogong/laopo "laopo"
Created /laogong/laopo
[zk: localhost:2181(CONNECTED) 13] ls /
[laogong, zookeeper]
[zk: localhost:2181(CONNECTED) 14] ls /laogong
[laopo]
[zk: localhost:2181(CONNECTED) 15] get /laogong/laopo
laopo
[zk: localhost:2181(CONNECTED) 16] 

上面的操作我都是在zknode1上面连接zk进行操作的,来看一下,在其他zkserver上有没有同步过来数据:

在这里插入图片描述

发现数据已经同步,zknode3/zknode4数据也同步了。

再来看一下连接zknode2的连接状态:

[root@zknode2 ~]# netstat -natp   |   egrep  '(2888|3888)' 
tcp6       0      0 192.168.134.137:3888    :::*                    LISTEN      2759/java           
tcp6       0      0 192.168.134.137:3888    192.168.134.139:47268   ESTABLISHED 2759/java           
tcp6       0      0 192.168.134.137:3888    192.168.134.138:38128   ESTABLISHED 2759/java           
tcp6       0      0 192.168.134.137:38968   192.168.134.138:2888    ESTABLISHED 2759/java           
tcp6       0      0 192.168.134.137:49788   192.168.134.136:3888    ESTABLISHED 2759/java 

在这里插入图片描述

连接状态:

在这里插入图片描述

上图是从zknode2服务器查看的,通过查看每台服务器,最终,zk集群的服务器每台都互相通信。

这个3888端口就是选举master用的,而2888端口是leader接受write请求用的。

zk集群master选举

前面演示了有4个服务器的zk集群,其中zknode3是leader。

现在我把zknode3服务干掉:

^C[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Error contacting service. It is probably not running.
[root@localhost ~]# 

再来分别看一下zknode1~zknode4的zk server状态:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以看到zknode4自动成了leader!

事实上,zk集群选举leader采用的是谦让的办法,谁的id大,选举谁。

那么前面为什么zknode3是leader呢?

因为我启动的顺序是zknode1 ~ zknode4启动的,当zknode3的zk server 启动的时候,已经满足集群的最少节点数了,而且zknode3的id是当时最大的,所以zknode3的server自动成了leader。

小结

ZooKeeper非常快速且非常简单。但是,由于其目标是作为构建更复杂的服务(例如同步)的基础,因此它提供了一组保证:

  • 顺序一致性-来自客户端的更新将按照发送的顺序应用;
  • 原子性-更新成功或失败。没有中间结果;
  • 单个系统映像-无论客户端连接到哪个服务器,客户端都将看到相同的服务视图。也就是说,即使客户端故障转移到具有相同会话的其他服务器,客户端也永远不会看到系统的较旧视图;
  • 可靠性-应用更新后,此更新将一直持续到客户端覆盖更新为止;
  • 及时性-确保系统的客户视图在特定时间范围内是最新的。

概括出如下关键字:

  • 简单的API

create,get等一组简单的原语保证

  • 高可用

选leader非常快,200ms之内

  • 统一配置管理

每个命名空间上的节点存储1M数据

  • 分组管理

path结构保证

  • 统一命名

顺序,sequential保证

  • 同步

临时节点保证

推荐阅读

看完点赞,养成习惯。

举手之劳,赞有余香。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值