ZK高可用架构涉及常用功能整理

ZK高可用架构涉及常用功能整理

  • 1. zk的高可用系统架构和相关组件
    • 1.1 Quorum机制
    • 1.2 ZAB协议
  • 2. zk的核心参数
    • 2.1 常规配置
    • 2.2 特殊优化配置
  • 3. zk常用命令
    • 3.1 常用基础命令
    • 3.2 常用运维命令
  • 4. 事务性
    • 4.1 数据写流程
    • 4.2 数据读流程
  • 5. 疑问和思考
    • 5.1 zk不擅长处理哪些场景?
  • 6. 参考文档

探讨zk的系统架构以及以及整体常用的命令和系统分析,本文主要探讨高可用版本的zk集群,并基于日常工作中的沉淀进行思考和整理。更多关于分布式系统的架构思考请参考文档关于常见分布式组件高可用设计原理的理解和思考


1. zk的高可用系统架构和相关组件

zk在产品设计上,面对的存储数据量比较小,一台zk机器就能够满足数据的存储需求,因此在集群的架构设计上,使用镜像模式进行数据高可用,通过ZAB 协议进行选举leader,从而满足集群的高可用和数据一致性要求。

zk的系统架构如下

在这里插入图片描述

zk的数据模型,呈现树形,类似linux的文件目录系统。在这里插入图片描述

相关核心的组件和角色作用如下

角色数量角色作用备注
Leader有且必须只有1个它会发起并维护与各Follwer及Observer间的心跳,所有的写操作必须要通过Leader完成再由Leader将写操作广播给其它服务器通过内部选举选择出leader
Follower多个会响应Leader的心跳,可直接处理并返回客户端的读请求,同时会将写请求转发给Leader处理,并且负责在Leader处理写请求时对请求进行投票和Observer统称为Learner
Observer多个作用跟Follow相同,但是没有投票权和Follower统称为Learner

在这里插入图片描述

1.1 Quorum机制

Quorum机制(有效个数)模式:指分布式系统的每一次修改都要在大多数(超过半数)实例上通过来确定修改通过。

产生Quorum机制(有效个数)的背景如下:

分布式系统的LC矛盾
在一个分布式存储系统中,用户请求会发到一个实例上。通常在一个实例上面执行的修改,需要复制到其他的实例上,这样可以保证在原实例挂了的情况下,用户依然可以看到这个修改。这就涉及到一个问题,究竟复制到多少个其他实例上之后,用户请求才会返回成功呢?如果复制的实例个数过多,那么请求响应时间就会更长;如果复制的实例过少,则这个修改可能会丢失。取得这个平衡性很重要,这也是分布式 PACELC 中的 L(Latency) 与 C(Consistency) 的取舍。

解决方案
当一个修改,被集群中的大部分节点(假设个数为N)通过之后,这个修改也就被这个集群所接受。这个 N 就是有效个数。假设集群数量为 n,那么 N = n/2 + 1.例如 n = 5,则 N = 3,从而应运而生Quorum机制(有效个数)

1.2 ZAB协议

ZooKeeper为了保证集群中各个节点读写数据的一致性和可用性,设计并实现了ZAB协议,ZAB全称是ZooKeeper Atomic Broadcast,也就是ZooKeeper原子广播协议。这种协议支持崩溃恢复,并基于主从模式,同一时刻只有一个Leader,所有的写操作都由Leader节点主导完成,而读操作可通过任意节点完成,因此ZooKeeper读性能远好于写性能,更适合读多写少的场景。一旦Leader节点宕机,ZAB协议的崩溃恢复机制能自动从Follower节点中重新选出一个合适的替代者,即新的Leader,该过程即为领导选举。领导选举过程,是ZAB协议中最为重要和复杂的过程

2. zk的核心参数

2.1 常规配置

zoo.cfg配置

cat /data/zookeeper-3.4.14/conf/zoo.cfg 
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=16
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=8
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/data/zookeeper-3.4.14/data
dataLogDir=/data/zookeeper-3.4.14/log
# 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=10000
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
autopurge.snapRetainCount=50
# Purge task interval in hours
# Set to "0" to disable auto purge feature
autopurge.purgeInterval=1
# 配置允许删除临时数据
extendedTypesEnabled=true# https://issues.apache.org/jira/plugins/servlet/mobile#issue/ZOOKEEPER-2164。
cnxTimeout=20000
# Add default super user to zookeeper for administration.
# if you want the passwd. please contact to administration.
DigestAuthenticationProvider.superDigest=super:2bS8Usm0IRIIwal5O1c6meW8uxI=server.1=xx.xx.xx.xx:2888:3888
server.2=xx.xx.xx.xx:2888:3888
server.3=xx.xx.xx.xx:2888:3888

myid配置

# cat /data/zookeeper-3.4.14/data/myid
1

不同的zk节点,配置对应的myid,配置依据来自zoo.cfg中的server.x配置

2.2 特殊优化配置

根据经验,可以增加zoo.cfg的管理账号

# fix the bug that 3888 listener will lost when network down and check_zk.sh restart the server
quorumListenOnAllIPs=true# Add default super user to zookeeper for administration.
# if you want the passwd. please contact to administration.
DigestAuthenticationProvider.superDigest=super:2bS8Usm0IRIIwal5O1c6meW8uxI=

3. zk常用命令

利用zk安装包中自带的zkCli.sh命令,能够链接到zk中,并进行相关的操作

# 连接本地zk
./zkCli.sh# 远程连接zk
./zkCli.sh -server xx.xx.xx.xx:2181

3.1 常用基础命令

整理日常操作zk常用的命令,便于针对zk的文件操作

1, ls 列出当前节点下的子节点

[zk: 127.0.0.1:2181(CONNECTED) 28] ls -R /
/
/node1
/zk
/zookeeper
/node1/node1.1
/node1/node1.2
/zookeeper/config
/zookeeper/quota
[zk: 127.0.0.1:2181(CONNECTED) 29] 

2, stat 列出节点状态

[zk: 127.0.0.1:2181(CONNECTED) 29] stat /
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0xc
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3

3,get 获取节点内容和节点状态

[zk: 127.0.0.1:2181(CONNECTED) 35] get /zk
jiang1234

4,create 创建永久节点

[zk: 127.0.0.1:2181(CONNECTED) 39] create /node_1 node-data
Created /node_1

5, 创建临时节点 &session过期临时节点删除

# 创建临时节点
[zk: 127.0.0.1:2181(CONNECTED) 40] create -e /czk/tmp temp-data
Created /czk/tmp# 要求先配置 extendedTypesEnabled=true
# 创建带ttl的临时节点
create -t 10 /zkttl# 10s后再ls就看不到创建的目录
ls /zkttl

在这里插入图片描述

6, 创建顺序节点

[zk: 127.0.0.1:2181(CONNECTED) 46] ls /czk
[tmp]
[zk: 127.0.0.1:2181(CONNECTED) 47] create -s /czk/sec seq
Created /czk/sec0000000001
[zk: 127.0.0.1:2181(CONNECTED) 48] create -s /czk/sec seq
Created /czk/sec0000000002
[zk: 127.0.0.1:2181(CONNECTED) 49] ls /czk
[sec0000000001, sec0000000002, tmp]
[zk: 127.0.0.1:2181(CONNECTED) 50] 

7,set 设置数据:

[zk: 127.0.0.1:2181(CONNECTED) 50] get /czk
czk-data
[zk: 127.0.0.1:2181(CONNECTED) 51] set /czk czk-data2
[zk: 127.0.0.1:2181(CONNECTED) 52] get /czk
czk-data2

8,delete 删除目录

[zk: 127.0.0.1:2181(CONNECTED) 57] ls /czk
[sec0000000001, sec0000000002, tmp]
[zk: 127.0.0.1:2181(CONNECTED) 58] delete /czk/sec000000001
Node does not exist: /czk/sec000000001
[zk: 127.0.0.1:2181(CONNECTED) 59] ls /czk
[sec0000000001, sec0000000002, tmp]
[zk: 127.0.0.1:2181(CONNECTED) 60] delete /czk/sec0000000001
[zk: 127.0.0.1:2181(CONNECTED) 61] ls /czk
[sec0000000002, tmp]

3.2 常用运维命令

用于日常运维命令,便于进行服务运维,提升系统稳定性。

1, 服务启停

# 启动ZK服务
sh bin/zkServer.sh start
# 查看ZK服务状态
sh bin/zkServer.sh status
# 停止ZK服务
sh bin/zkServer.sh stop
# 重启ZK服务
sh bin/zkServer.sh restart

2, 检查zk集群的状态

#!/usr/bin/python
# -*- coding: utf-8 -*-import json
import logging
import os
import random
import subprocess
import sys
import time
import datetimeif sys.getdefaultencoding() != 'utf-8':reload(sys)sys.setdefaultencoding('utf-8')logfile = "log_" + os.path.basename(sys.argv[0]).split(".")[0].split(".")[0] + ".log"
working_path = sys.path[0] + os.path.sep
log_path = "./"log_level = logging.DEBUG# 检查zk集群状态
zk_ips = []
zk_port = 2181
zoo_conf = "/data/zookeeper-3.4.14/conf/zoo.cfg"def getlogger(name, path_file_name):logger = logging.getLogger(name)if len(logger.handlers) == 0:logger.setLevel(log_level)fh = logging.FileHandler(path_file_name, encoding='utf-8')formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')fh.setFormatter(formatter)logger.addHandler(fh)if name != "file":console = logging.StreamHandler()console.setLevel(log_level)formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')console.setFormatter(formatter)logger.addHandler(console)return loggerif not os.path.exists(log_path):os.makedirs(log_path)logger = getlogger("default", log_path + logfile)
file_logger = getlogger("file", log_path + logfile)def run_shell(cmd, stderr2out=True):p = Noneif stderr2out:p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT)else:p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)out, err = p.communicate()if logger:logger.debug('running:%s,output:\n%s' % (cmd, out))return p.returncode, outdef get_zoo_server_list(conf_path):server_list = [](status, output) = run_shell("cat " + zoo_conf)if status != 0:return server_listlines = output.split("\n")for line in lines:if "server." in line and "#" not in line:tmp = line.split("=")if len(tmp) != 2:continuehost = tmp[1].split(":")[0]server_list.append(host)return server_listdef main():result = []all_ips = []all_ips = get_zoo_server_list(zoo_conf)all_ips = all_ips + zk_ipsfor ip in all_ips:(status, output) = run_shell("echo mntr|nc -w 3 " + ip + " " + str(zk_port))ip_result = {"conn": ip + ":" + str(zk_port), "result": None, "server_state": None}if status != 0:ip_result["result"] = "dead:conn " + ip + ":" + str(zk_port) + " failed."else:server_info = output.split("\n")for info in server_info:if "zk_server_state" in info:ip_result["server_state"] = info.split("\t")[-1]if ip_result["server_state"] is None:ip_result["result"] = "dead:zk role failed."else:ip_result["result"] = "alive"result.append(ip_result)# 输出结果print("=================result=================")for ip_result in result:print(json.dumps(ip_result))if len(all_ips) == 0:print("get server empty from " + zoo_conf + ",and zk_ips empty.")if __name__ == '__main__':main()

4. 事务性

4.1 数据写流程

zk的数据写流程,整体流程如下。
在这里插入图片描述

  1. Client向Zookeeper的server1发送一个写请求,客户端写数据到服务器1上;
  2. 如果server1不是Leader,那么server1会把接收到的写请求转发给Leader;然后Leader会将写请求转发给每个server;
  3. server1和server2负责写数据,并且两个Follower的写入数据是一致的,保存相同的数据副本;
  4. server1和server2写数据成功后,通知Leader;
  5. 当Leader收到集群半数以上的节点写成功的消息后,说明该写操作执行成功;
  6. 因为client访问的是server1,所以Leader会告知server1集群中数据写成功;
  7. 被访问的server1进一步通知client数据写成功,这时,客户端就知道整个写操作成功了。

4.2 数据读流程

相比写数据流程,读数据流程就简单得多;因为每台server中数据一致性都一样,所以随便访问哪台server读数据就行;没有写数据流程中请求转发、数据同步、成功通知这些步骤。

5. 疑问和思考

5.1 zk不擅长处理哪些场景?

zk擅长处理kv小量数据(v一般不能超过1M),基于zk进行分布式锁、选主、服务发现等均有比较好的应用和实践。但是zk不擅长处理大量数据的存储,通常需要注意不能在zk路径下写入过多数据,通常znode的目录数量应当控制在20M以内,单个zk节点的数据存储不应该超过10G,否则可能会由于zk存储了过多的数据而导致服务异常。

6. 参考文档

  • ZooKeeper 的总体架构图
  • 从0到1详解ZooKeeper的应用场景及架构原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/645687.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gitlab runner 安装、注册、配置、使用

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

「一本通 3.6 例 1」分离的路径

题目描述 为了从 F F F 个草场中的一个走到另一个,贝茜和她的同伴们不得不路过一些她们讨厌的可怕的树。奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一…

vue常用指令(v-show)

一、v-show 指令 作用: 根据真假值,切换元素的显示状态 二、代码演示 1、v-show 绑定判断条件后&#xff0c;根据布尔值决定是否显示图片 不显示图片 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><…

骨传导是哪个意思?骨传导的应用领域在哪

很多人都问我骨传导是哪个意思&#xff1f;骨传导的应用领域在哪&#xff1f;我们都知道声音能够在固体、液体、空气三种介质中传播。通常情况下&#xff0c;声音进入我们内耳的方式主要有两种&#xff1a;空气传导和骨传导&#xff0c;骨传导也就是通过固体传导。我们比较熟悉…

深度学习——pycharm远程连接

目录 远程环境配置本地环境配置&#xff08;注意看假设&#xff01;&#xff01;!这是很多博客里没写的&#xff09;步骤1步骤2步骤2.1 配置Connection步骤2.2 配置Mappings 步骤3 配置本地项目的远程解释器技巧1 pycharm中远程终端连接技巧2 远程目录技巧3 上传代码文件技巧4 …

自锁设计更稳固,同为科技(TOWE)服务器电脑IEC 60320电源线

说起IEC 60320标准电源线&#xff0c;可能很多人不知道具体是什么东西&#xff0c;但要说到台式电脑电源线&#xff0c;那大家就都能耳熟能详了。IEC 60320电源线的用途十分广泛&#xff0c;包括家用电器、医疗设备、数据中心服务器、商业机械设备、自动化生产线等都是用此类电…

API网关-Apinto压缩包方式自动化安装配置教程

文章目录 前言一、Apinto安装教程1. 复制脚本2. 增加执行权限3. 执行脚本4. Apinto命令4.1 启动Apinto4.2 停止Apinto4.3 重启Apinto4.4 查看Apinto版本信息4.5 加入Apinto集群4.6 离开Apinto集群4.7 查看Apinto节点信息 5. 卸载Apinto 二、Apserver(Apinto Dashboard V3)安装教…

力扣1027. 最长等差数列

动态规划 思路&#xff1a; 可以参考力扣1218. 最长定差子序列目前不清楚公差&#xff0c;可以将序列最大最小值找到&#xff0c;公差的范围是 [-(max - min), (max - min)]&#xff0c;按公差递增迭代遍历求出最长等差数列&#xff1b; class Solution { public:int longest…

IDEA 创建maven项目没有src

环境&#xff1a; IntelliJ IDEA 2022.3.3 (Ultimate Edition) JDK 17 Windows 11 10.0 Maven 3.9.5 创建maven项目的时候没有src目录 试过网上说的重新配置maven库&#xff0c;增加vm-options&#xff0c;并没有什么用。直到我看见了 正常创建就好了。

[计算机提升] 清理系统盘的前期准备

5.1 清理系统盘的前期准备 5.1.1 系统盘之殇&#xff1a;为什么系统盘会越来越大 在windows系统中&#xff0c;系统盘一般是C盘&#xff0c;随着电脑使用时间变长&#xff0c;系统盘会变得越来越大。而系统盘通常在安装系统时已经固定好了&#xff0c;如果系统盘的剩余空间太…

接收邮件触发器

无代码自动化-接收邮件触发器-做的最好的是make.com。数环通和集简云在这方面差了很多&#xff0c;我考虑主要原因应该是国内没有用邮件的习惯&#xff0c;都是微信来微信去。 2024年1月25日的观察结果 集简云 有邮件触发器&#xff0c;但是它获取的邮件信息很少。 我最关心…

【动态规划】【map】【C++算法】1289. 下降路径最小和 II

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 map LeetCode1289. 下降路径最小和 II 给你一个 n x n 整数矩阵 grid &#xff0c;请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为&#xff1a;从 grid 数组中的每一行选择一个数字&#xff0c;…

什么是超融合?

文章标题 前言一、超融合是什么&#xff1f;二、超融合原理2.1、超融合三大组件2.2、超融合和传统架构对比2.3、传统方案和超融合软件架构与资源管理模式对比 三、 超融合与SDS、分布式存储关系3.1、SDS是什么 &#xff1f;3.2、分布式存储是什么&#xff1f;3.3、超融合是什么…

开始学习Vue(路由)

一、什么是路由 SPA 指的是一个 web 网站只有唯一的一个 HTML 页面&#xff0c;所有组 件的展示与切换都在这唯一的一个页面内完成。 此时&#xff0c;不同组件之间的切换需要通过前端路由来实现。 结论&#xff1a;在 SPA 项目中&#xff0c;不同功能之间的切换&#xff0…

CAN总线接头(接线端子)都有哪些种类。

CAN总线是广泛应用在汽车控制和工业自动化控制领域里的现场总线&#xff0c;具有广阔的发展前景。基于CAN总线&#xff0c;工程师们开发出了各种各样的相关设备&#xff0c;比如USBCAN分析仪以及CAN转换网关等等。不知道你是否注意过&#xff0c;这些CAN总线设备的CAN接口都是什…

结合Tensuns管理prometheus的blackbox与告警设置

场景说明&#xff1a; 因为业务服务器已经完成了三级等保&#xff0c;禁止在业务服务器上部署任何应用&#xff0c;遂选择一台新的服务器部署prometheus&#xff0c;采用blackbox_exporter监控业务服务器的端口与域名状态。 Tensuns项目介绍 https://github.com/starsliao/T…

链表--24. 两两交换链表中的节点/medium 理解度C

24. 两两交换链表中的节点 1、题目2、题目分析3、复杂度最优解代码示例4、适用场景 1、题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&…

forEach()方法跳出循环

forEach方法如何跳出循环_foreach跳出循环-CSDN博客 forEach方法遍历数组&#xff0c;每次遍历都根据条件判断&#xff0c;当条件符合时&#xff0c;就跳出整个遍历&#xff0c;不再继续遍历后面的元素 forEach()方法跳出整个循环遍历 forEach方法一般用抛出异常的方式跳出整…

【JAVA语言-第15话】集合框架(二)——List、ArrayList、LinkedList、Vector集合

目录 List集合 1.1 概述 1.2 特点 1.3 常用方法 1.4 ArrayList集合 1.4.1 概述 1.4.2 练习 1.5 LinkedList集合 1.5.1 概述 1.5.2 特点 1.5.3 常用方法 1.5.4 练习 1.6 Vector类 1.6.1 概述 1.6.2 练习 1.7 List实现类的异同点 List集合 1.1 概述 java.util…

函数式接口

文章目录 函数式接口函数式接口当做方法的参数函数式接口作为返回值生产者接口 - Supplier消费者接口 - Consumer使用方式&#xff1a;案例&#xff1a;字符串拆分 判断接口 - Predicate使用方式应用场景 加工接口 - Function 函数式接口 只有一个抽象方法的接口&#xff0c;转…