热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Zookeeper参数详解及原理与优化

Zookeeper是什么Zookeeper是一个基于GoogleChubby论文实现的一款解决分布式数据一致性问题的开源实现,方便了依赖Zookeeper的应用实现数

Zookeeper 是什么

 Zookeeper 是一个基于 Google Chubby 论文实现的一款解决分布式数据一致性问题的开源实现,方便了依赖 Zookeeper 的应用实现 数据发布 / 订阅负载均衡服务注册与发现分布式协调事件通知集群管理Leader 选举、 分布式锁和队列 等功能

基本概念

集群角色

 一般的,在分布式系统中,构成集群的每一台机器都有自己的角色,最为典型的集群模式就是 Master / Slave 主备模式。在该模式中,我们把能够处理所有写操作的机器称为 Master 节点,并把所有通过异步复制方式获取最新数据、提供读服务的机器称为 Slave 节点

Zookeeper 参数详解及原理与优化

 而 Zookeeper 中,则是引入了 领导者(Leader)跟随者(Follower)观察者(Observer)三种角色 和 领导(Leading)跟随(Following)观察(Observing)寻找(Looking) 等相应的状态。在 Zookeeper 集群中的通过一种 Leader 选举的过程,来选定某个节点作为 Leader 节点,该节点为客户端提供服务。而 Follower 和 Observer 节点,则都能提供服务,唯一的区别在于,Observer 机器不参与 Leader 选举过程 和 写操作"过半写成功"策略,Observer只会被告知已经 commit 的 proposal。因此 Observer 可以在不影响写性能的情况下提升集群的读性能(详见下文 “性能优化 - 优化策略 - Observer 模式” 部分)

Zookeeper 参数详解及原理与优化

会话

 Session 指客户端会话。在 Zookeeper 中,一个客户端会话是指 客户端服务器之间的一个 TCP 长连接。客户端启动的时候,会与服务端建立一个 TCP 连接,客户端会话的生命周期,则是从第一次连接建立开始算起。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,并向 Zookeeper 服务器发送请求并接收响应,以及接收来自服务端的 Watch 事件通知

 Session 的 sessionTimeout 参数,用来控制一个客户端会话的超时时间。当服务器压力太大 或者是网络故障等各种原因导致客户端连接断开时,Client 会自动从 Zookeeper 地址列表中逐一尝试重连(重试策略可使用 Curator 来实现)。只要在 sessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。如果,在 sessionTimeout 时间外重连了,就会因为 Session 已经被清除了,而被告知 SESSION_EXPIRED,此时需要程序去恢复临时数据;还有一种 Session 重建后的在新节点上的数据,被之前节点上因网络延迟晚来的写请求所覆盖的情况,在 ZOOKEEPER-417 中被提出,并在该 JIRA 中新加入的 SessionMovedException,使得 用同一个 sessionld/sessionPasswd 重建 Session 的客户端能感知到,但是这个问题到 ZOOKEEPER-2219 仍然没有得到很好的解决

Zookeeper 参数详解及原理与优化

数据模型

 在 Zookeeper 中,节点分为两类,第一类是指 构成集群的机器,称之为机器节点;第二类则是指 数据模型中的数据单元,称之为数据节点 ZNode。Zookeeper 将所有数据存储在内存中,数据模型的结构类似于树(ZNode Tree),由斜杠(/)进行分割的路径,就是一个 ZNode,例如 /foo/path1。每个 ZNode 上都会保存自己的数据内容 和 一系列属性信息

 ZNode 可以分为持久节点(PERSISTENT)临时节点(EPHEMERAL)两类。所谓持久节点是指一旦这个 ZNode 被创建了,除非主动进行移除操作,否则这个节点将一直保存在 Zookeeper 上。而临时节点的生命周期,是与客户端会话绑定的,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。在 HBase 中,集群则是通过 **/hbase/rs/* 和 /hbase/master 两个临时节点,来监控 HRegionServer 进程的加入和宕机 和 HMaster 进程的 Active 状态**

 另外,Zookeeper 还有一种 顺序节点(SEQUENTIAL)。该节点被创建的时候,Zookeeper 会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀(上限:Integer.MAX_VALUE)。该节点的特性,还可以应用到 持久 / 临时节点 上,组合成 持久顺序节点(PERSISTENT_SEQUENTIAL) 和 临时顺序节点(EPHEMERAL_SEQUENTIAL)

Zookeeper 参数详解及原理与优化

版本

 Zookeeper 的每个 ZNode 上都会存储数据,对应于每个 ZNode,Zookeeper 都会为其维护一个叫做 Stat 的数据结构,Stat 中记录了这个 ZNode 的三个数据版本,分别是 version(当前 ZNode 数据内容的版本),cversion(当前 ZNode 子节点的版本)和 aversion(当前 ZNode 的 ACL 变更版本)。这里的版本起到了控制 Zookeeper 操作原子性的作用(详见下文 “源码分析 - 落脚点 - Zookeeper 乐观锁” 部分)

 如果想要让写入数据的操作支持 CAS,则可以借助 Versionable#withVersion 方法,在 setData()的同时指定当前数据的 verison。如果写入成功,则说明在当前数据写入的过程中,没有其他用户对该 ZNode 节点的内容进行过修改;否则,会抛出一个 KeeperException.BadVersionException,以此可以判断本次 CAS 写入是失败的。而这样做的好处就是,可以避免 “并发局部更新 ZNode 节点内容” 时,发生相互覆盖的问题

Watcher

 Watcher(事件监听器)是 Zookeeper 提供的一种 发布/订阅的机制。Zookeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,Zookeeper 服务端会将事件通知给订阅的客户端。该机制是 Zookeeper 实现分布式协调的重要特性

Zookeeper 参数详解及原理与优化

ACL

 类似于 Unix 文件系统,Zookeeper 采用 ACL(Access Control Lists)策略来进行权限控制(使用方式,详见下文 “常用命令 - 执行脚本 - zkCli - 节点操作” 部分;代码实现,详见 PrepRequestProcessor#checkACL)

常用的权限控制

CommandComment
CREATE (c)创建子节点的权限
READ (r)获取节点数据和子节点列表的权限
WRITE (w)更新节点数据的权限
DELETE (d)删除当前节点的权限
ADMIN (a)管理权限,可以设置当前节点的 permission
SchemeIDComment
worldanyoneZookeeper 中对所有人有权限的结点就是属于 world:anyone
auth不需要 id通过 authentication 的 user 都有权限
(Zookeeper 支持通过 kerberos 来进行 authencation,也支持 username/password形式的 authentication)
digestusername:BASE64 (SHA1(password))需要先通过 username:password 形式的 authentication
ipid 为客户机的 IP 地址(或者 IP 地址段)ip:192.168.1.0/14,表示匹配前 14 个 bit 的 IP 段
super对应的 id 拥有超级权限(CRWDA)

IP

编码

@Before
public void init() throws Exception {zoo &#61; new ZooKeeper(HOST.concat(":" &#43; CLIENT_PORT), TIME_OUT_MILLISECOND, null);acls &#61; new ArrayList<>();acls.add(new ACL(ZooDefs.Perms.ALL, new Id(IP, "10.24.40.178")));acls.add(new ACL(ZooDefs.Perms.ALL, new Id(IP, "127.0.0.1")));aclsNoAuth &#61; new ArrayList<>();aclsNoAuth.add(new ACL(ZooDefs.Perms.ALL, new Id(IP, "127.0.0.1")));
}
&#64;Test
public void ipAcl() throws Exception {if (zoo.exists(IP_PATH, null) !&#61; null) zoo.delete(IP_PATH, -1);if (zoo.exists(IP_PATH_NO_AUTH, null) !&#61; null) zoo.delete(IP_PATH_NO_AUTH, -1);zoo.create(IP_PATH, IP.getBytes(), acls, CreateMode.PERSISTENT);assertEquals(IP, new String(zoo.getData(IP_PATH, false, null)));zoo.create(IP_PATH_NO_AUTH, IP.getBytes(), aclsNoAuth, CreateMode.PERSISTENT);try {zoo.getData(IP_PATH_NO_AUTH, false, null);} catch (KeeperException.NoAuthException e) {assertEquals("KeeperErrorCode &#61; NoAuth for ".concat(IP_PATH_NO_AUTH), e.getMessage());}
}

Tips: Full code is here.

命令行

$ zkCli.sh -server localhost:2181[zk: localhost:2181(CONNECTED) 16] ls /[leader, election, zookeeper, origin, ip, auth_test, benchmark][zk: localhost:2181(CONNECTED) 17] ls /ipAuthentication is not valid : /ip[zk: localhost:2181(CONNECTED) 18] getAcl /ip&#39;ip,&#39;10.24.40.178: cdrwa&#39;ip,&#39;127.0.0.1: cdrwa
$ zkCli.sh -server 127.0.0.1:2181[zk: 127.0.0.1:2181(CONNECTED) 1] ls /ip[][zk: 127.0.0.1:2181(CONNECTED) 2] get /ipipcZxid &#61; 0x10000c43bctime &#61; Tue Aug 22 16:50:37 CST 2017mZxid &#61; 0x10000c43bmtime &#61; Tue Aug 22 16:50:37 CST 2017pZxid &#61; 0x10000c43bcversion &#61; 0dataVersion &#61; 0aclVersion &#61; 0ephemeralOwner &#61; 0x0dataLength &#61; 2numChildren &#61; 0

优缺点

 简单易用&#xff0c;直接在物理层面&#xff0c;对用户进行权限隔离&#xff1b;但是&#xff0c;如果不将 127.0.0.1 放入到 IP Acl 列表里&#xff0c;会给服务端的运维带来麻烦

Digest

编码

&#64;Before
public void init() throws Exception {zoo &#61; new ZooKeeper(HOST.concat(":" &#43; CLIENT_PORT), TIME_OUT_MILLISECOND, null);zoo.addAuthInfo("digest", "yuzhouwan:com".getBytes());zooNoAuth &#61; new ZooKeeper(HOST.concat(":" &#43; CLIENT_PORT), TIME_OUT_MILLISECOND, null);
}
&#64;Test
public void digestAcl() throws Exception {if (zoo.exists(AUTH_PATH_CHILD, null) !&#61; null) zoo.delete(AUTH_PATH_CHILD, -1);if (zoo.exists(AUTH_PATH, null) !&#61; null) zoo.delete(AUTH_PATH, -1);zoo.create(AUTH_PATH, bytes, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);try {zooNoAuth.create(AUTH_PATH_CHILD, bytes, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);} catch (KeeperException.InvalidACLException e) {assertEquals("KeeperErrorCode &#61; InvalidACL for /auth_test/child", e.getMessage());}zoo.create(AUTH_PATH_CHILD, bytes, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);try {zooNoAuth.delete(AUTH_PATH_CHILD, -1);} catch (KeeperException.NoAuthException e) {assertEquals("KeeperErrorCode &#61; NoAuth for /auth_test/child", e.getMessage());}assertEquals(AUTH_PATH, new String(zoo.getData(AUTH_PATH, false, null)));
}

Tips: Full code is here.

命令行

$ zkCli.sh -server localhost:2181[zk: localhost:2181(CONNECTED) 5] ls /[leader, auth_test, election, zookeeper, benchmark, origin][zk: localhost:2181(CONNECTED) 6] ls /auth_testAuthentication is not valid : /auth_test[zk: localhost:2181(CONNECTED) 7] get /auth_testAuthentication is not valid : /auth_test[zk: localhost:2181(CONNECTED) 8] getAcl /auth_test&#39;digest,&#39;yuzhouwan:h/j&#43;/wDlblTtA48jnbq8snP1glA&#61;: cdrwa[zk: localhost:2181(CONNECTED) 9] addauth digest yuzhouwan:true[zk: localhost:2181(CONNECTED) 10] get /auth_test/auth_testcZxid &#61; 0x10000c31ectime &#61; Tue Aug 22 15:26:27 CST 2017mZxid &#61; 0x10000c31emtime &#61; Tue Aug 22 15:26:27 CST 2017pZxid &#61; 0x10000c31ecversion &#61; 0dataVersion &#61; 0aclVersion &#61; 0ephemeralOwner &#61; 0x0dataLength &#61; 10numChildren &#61; 0

优缺点

 可以建立角色&#xff0c;按照用户名、密码进行权限控制&#xff1b;但是&#xff0c;想要修改某个用户的密码&#xff0c;需要对所有的 ACLs 做更改

SASL & Kerberos

环境搭建

单机版

安装

$ cd ~/install/
$ wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
$ wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz.md5
# 校验 MD5
$ head -n 1 zookeeper-3.4.10.tar.gz.md5e4cf1b1593ca870bf1c7a75188f09678 zookeeper-3.4.10.tar.gz
$ md5sum zookeeper-3.4.10.tar.gze4cf1b1593ca870bf1c7a75188f09678 *zookeeper-3.4.10.tar.gz
# 对比 MD5 码一致后进行解压安装
$ tar zxvf zookeeper-3.4.10.tar.gz -C ~/software/
$ cd ~/software
$ ln -s zookeeper-3.4.10 zookeeper

配置

cd zookeeper
$ mkdir tmp
$ cp conf/zoo_sample.cfg conf/zoo.cfg
$ mkdir -p /home/zookeeper/data/zookeeper
$ mkdir -p /home/zookeeper/logs/zookeeper
# 更多配置&#xff0c;详见下文 “常用配置” 部分
$ vim conf/zoo.cfgtickTime&#61;2000initLimit&#61;10syncLimit&#61;5dataDir&#61;/home/zookeeper/data/zookeeperdataLogDir&#61;/home/zookeeper/logs/zookeeperclientPort&#61;2181

启动

$ bin/zkServer.sh start
$ bin/zkServer.sh statusZooKeeper JMX enabled by defaultUsing config: /home/zookeeper/software/zookeeper/bin/../conf/zoo.cfgMode: standalone
$ bin/zkCli.sh

分布式

更多配置&#xff0c;详见下文 “常用配置” 部分

$ vim conf/zoo.cfgtickTime&#61;2000initLimit&#61;10syncLimit&#61;5dataDir&#61;/home/zookeeper/data/zookeeperdataLogDir&#61;/home/zookeeper/logs/zookeeperclientPort&#61;2181server.1&#61;yuzhouwan01:2281:2282server.2&#61;yuzhouwan02:2281:2282server.3&#61;yuzhouwan03:2281:2282
# 在各个节点的 dataDir下创建 myid 文件&#xff0c;并对应 zoo.cfg中配置的 id
[zookeeper&#64;yuzhouwan01 ~] echo "1" > /home/zookeeper/data/zookeeper/myid
[zookeeper&#64;yuzhouwan02 ~] echo "2" > /home/zookeeper/data/zookeeper/myid
[zookeeper&#64;yuzhouwan03 ~] echo "3" > /home/zookeeper/data/zookeeper/myid

常用命令

四字命令

CommandComment
conf输出相关服务配置的详细信息
cons列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息 (包括“接受 / 发送” 的包数量、会话 id 、操作延迟、最后的操作执行等等信息)
envi输出关于服务环境的详细信息 (区别于 conf 命令)
dump列出未经处理的会话和临时节点
stat查看哪个节点被选择作为 Follower 或者 Leader
ruok测试是否启动了该 Server&#xff0c;若回复 imok 表示已经启动
mntr输出一些运行时信息&#xff08;latency / packets / alive_connections / outstanding_requests / server_state / znode &#43; watch &#43; ephemerals count …&#xff09;
reqs列出未经处理的请求
wchs列出服务器 watch 的简要信息
wchc通过 session 列出服务器 watch 的详细信息&#xff08;输出是一个与 watch 相关的会话的列表&#xff09;
wchp通过路径列出服务器 watch 的详细信息&#xff08;输出一个与 session 相关的路径&#xff09;
srvr输出服务的所有信息&#xff08;可以用来检查当前节点同步完毕集群数据&#xff0c;处于 Follower 状态&#xff09;
srst重置服务器统计信息
kill关掉 Server

Tips: 部分加粗命令对资源消耗比较大&#xff0c;生产环境慎用!

使用方式

安装 Netcat

# online
$ yum install nc
# offline
$ uname -aLinux yuzhouwan 2.6.32-279.el6_sn.7.x86_64 #1 SMP Fri May 27 18:04:25 CST 2016 x86_64 x86_64 x86_64 GNU/Linux
# 搜索rpm包 https://rpmfind.net/linux/rpm2html/search.php?query&#61;nc&submit&#61;Search&#43;...&system&#61;&arch&#61;x86_64
$ wget ftp://rpmfind.net/linux/centos/6.9/os/x86_64/Packages/nc-1.84-24.el6.x86_64.rpm
$ rpm -ivh nc-1.84-24.el6.x86_64.rpm

Netcat 执行

$ echo | nc 127.0.0.1 2181

DOS ***

避免 wchp / wchc 四字命令被 DOS ***利用

$ vim zoo.cfg# 4lw.commands.whitelist&#61;*4lw.commands.whitelist&#61;stat, ruok, conf, isro

产生的日志

可以看到 zk.out 文件中出现 0:0:0:0:0:0:0:1&#xff08;IPv6 的回送地址&#xff0c;相当于 IPv4 的 127.0.0.1&#xff09;和 Processing xxxx command 相应的日志

2017-06-13 23:05:01,998 [myid:5] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory&#64;197] - Accepted socket connection from /0:0:0:0:0:0:0:1:40986
2017-06-13 23:05:01,998 [myid:5] - INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn&#64;827] - Processing srvr command from /0:0:0:0:0:0:0:1:40986
2017-06-13 23:05:02,000 [myid:5] - INFO [Thread-64778:NIOServerCnxn&#64;1007] - Closed socket connection for client /0:0:0:0:0:0:0:1:40986 (no session established for client)

执行脚本

zkServer

启动
启动

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

排查问题
可以通过增加 start-foreground 参数来排查失败原因

$ bin/zkServer.sh start-foregroundZooKeeper JMX enabled by defaultUsing config: /home/eagle/software/zookeeper/bin/../conf/zoo.cfgError: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain
# /home/eagle/software/zookeeper/zookeeper-3.4.10.jar 的问题&#xff0c;重新下载&#xff0c;校验 md5 正确后&#xff0c;再次安装即可

zkCli

启动

$ cd $ZOOKEEPER_HOME
$ bin/zkCli -server :2181,:2181,:2181

节点操作
CommandExampleComment
create创建一个节点
ls查看当前节点数据
ls2查看当前节点数据&#xff0c;并能看到更新次数等信息
set修改节点
get得到一个节点&#xff0c;包含数据更新次数等信息
delete删除一个节点
rmr递归删除
history列出最近的历史命令
redo redo 1重做第 n 步命令
stat打印节点状态
close关闭当前连接
connect :connect localhost:2181当 close 当前连接或者意外退出后&#xff0c;可在 zkCli命令模式中重连
quit退出当前连接
setAcl  setAcl /zk world:anyone:cdrw设置节点权限策略&#xff08;详见上文 “基本概念 - ACL” 部分&#xff09;
getAcl 获取节点权限策略
addauth  addauth digest username:password节点权限认证
setquota -n-b val 
listquota listquota /zookeeper查看节点的配额
count&#61;5, bytes&#61;-1/zookeeper 节点个数限额为 5&#xff0c;长度无限额
delquota [-n or -b]&#96;&#96;
sync 强制同步
&#xff08;由于 “过半原则”&#xff0c;导致某些 Zookeeper Server 上的数据是旧的&#xff0c;用 sync 命令可强制同步所有的更新操作&#xff09;
printwatches onoff
常见组合&#xff08;for Kafka&#xff09;
CommandComment
get /consumers//owners查看 Topic 实时消费的 Group ID
get /consumers//offsets//查看 Offset 情况&#xff08;ctime&#xff1a;创建时间&#xff1b;mtime&#xff1a;修改时间&#xff09;

常用配置

dataDir

 Zookeeper 保存服务器存储快照文件的目录&#xff0c;默认情况&#xff0c;Zookeeper 将 写数据的日志文件也保存在这个目录里&#xff08;default&#xff1a;/tmp/zookeeper&#xff09;

dataLogDir

 用来存储服务器事务日志

clientPort

 客户端连接 Zookeeper 服务器的端口&#xff0c;Zookeeper 会监听这个端口&#xff0c;接受客户端的访问请求&#xff08;default&#xff1a;2181&#xff09;

tickTime&#xff08;SS / CS&#xff09;

 用来指示 服务器之间或客户端服务器之间维护心跳机制的 最小时间单元&#xff0c;Session 最小过期时间默认为两倍的 tickTime&#xff08;default&#xff1a;2000ms&#xff09;

initLimit&#xff08;LF&#xff09;

 集群中的 Leader 节点和 Follower 节点之间初始连接时能容忍的最多心跳数&#xff08;default&#xff1a;5 tickTime&#xff09;

syncLimit&#xff08;LF&#xff09;

 集群中的 Leader 节点和 Follower 节点之间请求和应答时能容忍的最多心跳数&#xff08;default&#xff1a;2 tickTime&#xff09;

minSessionTimeout & maxSessionTimeout

 默认分别是 2 tickTime ~ 20 tickTime&#xff0c;来用控制 客户端设置的 Session 超时时间。如果超出或者小于&#xff0c;将自动被服务端强制设置为 最大或者最小

集群节点

 配置 Zookeeper 集群中的服务器节点格式&#xff1a;&#96;server.&#96;&#61;&#96;<服务器地址>&#96;:&#96;&#96;:&#96;<选举端口>&#96;样例&#xff1a;&#96;server.1&#61;yuzhouwan:2888:3888&#96;

动态配置

$ vim zoo_replicated1.cfgtickTime&#61;2000dataDir&#61;/zookeeper/data/zookeeper1initLimit&#61;5syncLimit&#61;2dynamicConfigFile&#61;/zookeeper/conf/zoo_replicated1.cfg.dynamic
$ vim zoo_replicated1.cfg.dynamicserver.1&#61;125.23.63.23:2780:2783:participant;2791server.2&#61;125.23.63.24:2781:2784:participant;2792server.3&#61;125.23.63.25:2782:2785:participant;2793

监控

采集方式

JMX

远程连接

 Zookeeper 默认支持 JMX 连接&#xff0c;但是只支持本地连接

开启远程 JMX

$ vim bin/zkServer.sh# ZOOMAIN&#61;"-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only&#61;$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain"ZOOMAIN&#61;"-Dcom.sun.management.jmxremote.port&#61;8888 -Dcom.sun.management.jmxremote.ssl&#61;false -Dcom.sun.management.jmxremote.authenticate&#61;false org.apache.zookeeper.server.quorum.QuorumPeerMain"

Four-letter command

TCP Dump

使用 tcpdump 命令&#xff0c;需要在 root 权限下执行

$ sudo tcpdump tcp port 2181 and host ! 127.0.0.1# 下面抓包到的信息&#xff0c;是 Curator 远程连接&#xff0c;并在 /children 命名空间下&#xff0c;创建临时节点 /yuzhouwan&#xff0c;最终断开 TCP 连接的过程14:50:16.192736 IP 10.10.10.10.56342 > yuzhouwan01.eforward: Flags [S], seq 818611125, win 8192, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 014:50:16.192765 IP yuzhouwan01.eforward > 10.10.10.10.56342: Flags [S.], seq 3867146147, ack 818611126, win 14600, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 014:50:16.193502 IP 10.10.10.10.56342 > yuzhouwan01.eforward: Flags [.], ack 1, win 256, length 014:50:16.196755 IP 10.10.10.10.56342 > yuzhouwan01.eforward: Flags [P.], seq 1:50, ack 1, win 256, length 4914:50:16.196768 IP yuzhouwan01.eforward > 10.10.10.10.56342: Flags [.], ack 50, win 115, length 014:50:16.198618 IP yuzhouwan01.eforward > 10.10.10.10.56342: Flags [P.], seq 1:42, ack 50, win 115, length 4114:50:16.214597 IP 10.10.10.10.56342 > yuzhouwan01.eforward: Flags [P.], seq 50:76, ack 42, win 256, length 2614:50:16.215109 IP yuzhouwan01.eforward > 10.10.10.10.56342: Flags [P.], seq 42:62, ack 76, win 115, length 20

Tips: 比较关心的一个问题是&#xff0c;tcpdump 是否会对性能造成影响&#xff1f;答案是&#xff0c;会的。当过滤上千的 IP 时&#xff0c;已经会影响到服务器性能。主要瓶颈在 BPF Filter&#xff0c;这是一个 O(n)O(n)  线性时间复杂度的算法&#xff0c;可以考虑 HiPAC 多维树匹配 替代

指标

Zookeeper 运行状态&#xff08;mntr&#xff09;

MetricsCommentThreshold
zk_version版本
zk_avg_latency平均 响应延迟> 50ms&#xff0c;比上次统计增长超过 20ms&#xff0c;且上一次延迟不为 0
zk_max_latency最大 响应延迟
zk_min_latency最小 响应延迟
zk_packets_received收包数
zk_packets_sent发包数
zk_num_alive_connections活跃连接数> 3000
zk_outstanding_requests堆积请求数连续两次大于 5&#xff08;粒度&#xff1a;1min&#xff09;
zk_server_state主从状态由 Leader 变为 Follower 或 由 Follower 变为 Leader
zk_znode_countznode 数> 40000
zk_watch_countwatch 数> 50000
zk_ephemerals_count临时节点数
zk_approximate_data_size近似数据总和大小
zk_open_file_descriptor_count打开 文件描述符 数
zk_max_file_descriptor_count最大 文件描述符 数
zk_followersFollower 数
zk_synced_followers已同步的 Follower 数连续两次检测到未同步的 Follower 节点 (粒度&#xff1a;1min)
zk_pending_syncs阻塞中的 sync 操作

Tips: 加粗指标&#xff0c;只有 Leader 节点才会有

实时预警

numenta / nupic

 NuPIC&#xff08;Numenta Platform for Intelligent Computing&#xff0c;Numenta智能计算平台&#xff09; 是一个与众不同的开源人工智能平台&#xff0c;它基于一种脑皮质学习算法&#xff0c;即 “层级实时记忆”&#xff08;Hierarchical Temporal Memory&#xff0c;HTM&#xff09;。该算法旨在模拟新大脑皮层的工作原理&#xff0c;将复杂的问题转化为模式匹配与预测&#xff0c;而传统的 AI 算法大多是针对特定的任务目标而设计的
 NuPIC 聚焦于分析实时数据流&#xff0c;可以通过学习数据之间基于时间的状态变化&#xff08;而非阀值设置&#xff09;&#xff0c;对未知数据进行预测&#xff0c;并揭示其中的非常规特性。详见我的另一篇博客&#xff1a;人工智能

性能调优

Benchmark&#xff08;Test First&#xff09;

 brownsys / zookeeper-benchmark &#xff08;很难找到合适的开源项目&#xff0c;需自己编写 Benchmark 工具&#xff09;

优化策略

部署

日志目录
  • 快照目录 dataDir 和 事务日志目录 dataLogDir 分离
  • 写事务日志的目录&#xff0c;需要保证目录空间足够大&#xff0c;并挂载到单独的磁盘上&#xff08;为了保证数据的一致性&#xff0c; ZooKeeper 在返回客户端事务请求响应之前&#xff0c; 必须要将此次请求对应的事务日志刷入到磁盘中 [forceSync 参数控制&#xff0c;default&#xff1a;yes]&#xff0c;所以事务日志的写入速度&#xff0c;直接决定了 Zookeeper 的吞吐率&#xff09;
自动日志清理
autopurge.purgeInterval

 指定清理频率&#xff0c;单位为小时&#xff08;default&#xff1a;0 表示不开启自动清理&#xff09;

autopurge.snapRetainCount

 和上面 purgeInterval 参数配合使用&#xff0c;指定需要保留的文件数目&#xff08;default&#xff1a;3&#xff09;

$ vim conf/zoo.cfgautopurge.snapRetainCount&#61;3autopurge.purgeInterval&#61;1
# 注意&#xff1a;Zookeeper 重启会自动清除 zookeeper.out 日志&#xff0c;如果有排错需要&#xff0c;则应先备份好日志文件
# 如果发现单事务日志量过大&#xff0c;导致定时清理无法及时处理&#xff0c;可以使用 zkCleanup.sh 进行手动清除
$ cd ~/software/zookeeper1
$ zookeeper1/bin/zkCleanup.sh /home/zookeeper/logs/zookeeper1/version-2/ 3Removing file: Aug 9, 2017 12:08:49 PM /home/zookeeper/logs/zookeeper1/version-2/log.1c00000001Removing file: Aug 9, 2017 02:03:33 PM /home/zookeeper/data/zookeeper1/version-2/snapshot.1c0000ab90

Log4j 滚动日志

$ cd $ZOOKEEPER_HOME
$ vim conf/log4j.propertieszookeeper.root.logger&#61;INFO, CONSOLEzookeeper.console.threshold&#61;INFOzookeeper.log.dir&#61;.zookeeper.log.file&#61;zookeeper.logzookeeper.log.threshold&#61;DEBUGzookeeper.tracelog.dir&#61;.zookeeper.tracelog.file&#61;zookeeper_trace.log# 可以调整为 DaliyRollingFileAppender&#xff0c;每天滚动创建新的日志文件log4j.appender.ROLLINGFILE&#61;org.apache.log4j.RollingFileAppenderlog4j.appender.ROLLINGFILE.Threshold&#61;${zookeeper.log.threshold}log4j.appender.ROLLINGFILE.File&#61;${zookeeper.log.dir}/${zookeeper.log.file}
$ vim bin/zkServer.sh# 增加 ZOO_LOG_DIR 配置ZOO_LOG_DIR&#61;$ZOOBINDIR/../log4j
$ vim bin/zkEnv.sh# if [ "x${ZOO_LOG4J_PROP}" &#61; "x" ]# then# ZOO_LOG4J_PROP&#61;"INFO,CONSOLE"# fiif [ "x${ZOO_LOG4J_PROP}" &#61; "x" ]thenZOO_LOG4J_PROP&#61;"INFO,ROLLINGFILE"fi

Observer 模式

作用
对读请求进行扩展

 通过增加更多的 Observer&#xff0c;可以接收更多的读请求流量&#xff0c;却不会牺牲写操作的吞吐量&#xff08;写操作的吞吐量取决于 quorum 法定人数的个数&#xff09;
 如果增加更多的 Server 进行投票&#xff0c;Quorum 会变大&#xff0c;这会降低写操作的吞吐量
 然而增加 Observer 并不会完全没有损耗&#xff0c;新的 Observer 在提交一个事务后收到一条额外的 INFORM 消息。这个损耗比加入 Follower 进行投票来说会小很多

Zookeeper 参数详解及原理与优化

&#xff08;图片来源&#xff1a;Observers: core functionality&#xff09;

跨数据中心部署

 把 participant 分散到多个数据中心&#xff0c;可能会因为数据中心之间的网络延迟&#xff0c;导致系统被拖慢
 使用 Observer 的话&#xff0c;更新操作都在单独的数据中心来处理&#xff0c;再发送到其他数据中心&#xff0c;让 Client 消费数据&#xff08;分布式数据库 [中美异地机房] 同步系统 Otter 就使用该模式&#xff09;

Zookeeper 参数详解及原理与优化

设置

$ vim conf/zoo.cfgpeerType&#61;observerserver.1:localhost:2181:3181:observer # 其他需要扩展成 Observer 的 Server 都需要加上 &#96;:observer&#96; 后缀

INFORM 消息

 因为 Observer 不参与到 ZAB 选举中&#xff0c;所以 Leader 节点不会发送 proposal 给 Observer&#xff0c;只会发送一条包含已经通过选举的 zxid 的 INFORM 消息。这里&#xff0c;参与 ZAB 选举的 Leader、Follower 节点称之为 PARTICIPANT Server&#xff0c;而 Observer 则属于 OBSERVER Server

配置

JVM 相关
swappiness

$ cd $ZOOKEEEPER_HOME
# 常驻进程&#xff0c;需要避免 swapping 损害性能
# 临时生效
$ echo 0 > /proc/sys/vm/swappiness
# 永久生效
$ vim /etc/sysctl.confvm.swappiness&#61;0 # memory first
# 设置 &#96;-XX:&#43;AlwaysPreTouch&#96; 参数&#xff0c;在进程启动的时候&#xff0c;让 jvm 通过 demand-zeroed 方式将内存一次分配到位&#xff08;ES #16937 / ZK #301&#xff09;
# 使用 CMS 垃圾回收器&#xff08;“jdk7 &#43; 内存使用不多” 的缘故&#xff0c;可以暂不考虑 G1GC&#xff09;
$ vim conf/java.envexport JVMFLAGS&#61;"-Xms3G -Xmx3G -Xmn1G -XX:&#43;AlwaysPreTouch -XX:CMSInitiatingOccupancyFraction&#61;70 -XX:&#43;UseParNewGC -XX:&#43;UseConcMarkSweepGC"# 如果需要打印 GC 日志&#xff0c;则多增加一些 flagexport JVMFLAGS&#61;"-Xms3G -Xmx3G -Xmn1G -XX:&#43;AlwaysPreTouch -XX:CMSInitiatingOccupancyFraction&#61;70 -XX:&#43;UseParNewGC -XX:&#43;UseConcMarkSweepGC -XX:&#43;PrintGCDetails -XX:-PrintGCTimeStamps -Xloggc:/home/zookeeper/logs/zookeeper_&#96;date &#39;&#43;%Y%m%d%H%M%S&#39;&#96;.gc -XX:-UseGCLogFileRotation -XX:NumberOfGCLogFiles&#61;10 -XX:GCLogFileSize&#61;64M"# 需要注意的是&#xff0c;如果不希望 zkCli 等命令创建 gc 日志文件&#xff0c;需要把 JVMFLAGS 改成 SERVER_JVMFLAGS
# 更进一步&#xff0c;如果有四字命令在做监控&#xff0c;则建议&#xff0c;直接修改 zkServer.sh&#xff0c;否则因为 zookeeper_&#96;date &#39;&#43;%Y%m%d%H%M%S&#39;&#96;.gc 的存在&#xff0c;导致每次四字命令执行&#xff0c;会有很多小日志被创建&#xff08;ZK#302 已解决&#xff0c;待分析&#xff09;
$ vim bin/zkServer.shstart)# ...START_SERVER_JVMFLAGS&#61;"-Xms3G -Xmx3G -Xmn1G -XX:&#43;AlwaysPreTouch -XX:CMSInitiatingOccupancyFraction&#61;70 -XX:&#43;UseParNewGC -XX:&#43;UseConcMarkSweepGC -XX:&#43;PrintGCDetails -XX:-PrintGCTimeStamps -Xloggc:/home/zookeeper/logs/zookeeper_&#96;date &#39;&#43;%Y%m%d%H%M%S&#39;&#96;.gc -XX:-UseGCLogFileRotation -XX:NumberOfGCLogFiles&#61;10 -XX:GCLogFileSize&#61;64M"nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir&#61;${ZOO_LOG_DIR}" \"-Dzookeeper.log.file&#61;${ZOO_LOG_FILE}" "-Dzookeeper.root.logger&#61;${ZOO_LOG4J_PROP}" \-XX:&#43;HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError&#61;&#39;kill -9 %p&#39; \-cp "$CLASSPATH" $JVMFLAGS $START_SERVER_JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 # 堆大小的最终确定&#xff0c;需要在 benchmark 结果的基础之上&#xff0c;再做调整
# 另外&#xff0c;一旦创建完该文件&#xff0c;Zookeeper 进程会自动加载&#xff0c;因此&#xff0c;需要确保无误之后&#xff0c;再建立 java.env 文件

升级 JDK8

 为何建议升级 JDK8 呢&#xff1f;因为 Zookeeper 里面很多关键的功能点&#xff0c;都用到了 Atomic 类&#xff0c;而该类在 JDK8 中做了一次升级&#xff0c;性能提升了 6x 倍&#xff08;JDK8 中加入了 Unsafe.getUnsafe().getAnd[Add|Set][Int|Long|Object] 一系列方法对 Atomic 类做了增强&#xff0c;由于无法看到 Oracle JDK 里 Unsafe 的相关实现&#xff0c;有兴趣可以参考 OpenJDK 源码。目前&#xff0c;存在一种比较靠谱的猜测是&#xff0c;compare-and-swap 被替换成系统底层的 fetch-and-add&#xff0c;后者用 lock xadd 替代了 lock cmpxchg 来实现原子操作。其中 指令前缀 lock 用来锁定指令涉及的存储区域&#xff0c;xadd 指令作用是 交换两个操作数的值&#xff0c;再进行加法操作&#xff0c;cmpxchg比较交换指令&#xff0c;第一操作数先和 AL/AX/EAX 比较&#xff0c;如果相等 ZF 置 1&#xff0c;第二操作数赋给第一操作数&#xff0c;否则 ZF 清 0&#xff0c;第一操作数赋给 AL/AX/EAX。由此可见&#xff0c;xadd 指令实现的 FAA 和 cmpxchg 指令实现的 CAS 相比&#xff0c;并没有自旋&#xff0c;因此不用担心循环时间过长之后 CPU 资源消耗过大&#xff0c;并且也没有了 CAS 中 ABA 之类的问题 [该问题在 AtomicStampedReference 中&#xff0c;通过增加版本号解决了]&#xff09;


原文地址&#xff1a;https://blog.csdn.net/oASiDuoFu/article/details/80525870

转:https://blog.51cto.com/zhangyc/2341478



推荐阅读
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 基于Web的Kafka管理工具Kafkamanager首次访问Web界面的详细配置指南(附图解)
    首次访问Kafkamanager Web界面时,需要对Kafka集群进行配置。这一过程相对简单,用户只需依次点击【Cluster】>【Add Cluster】,按照提示完成相关设置即可。本文将通过图文并茂的方式,详细介绍每一步的配置步骤,帮助用户快速上手Kafkamanager。 ... [详细]
  • 利用REM实现移动端布局的高效适配技巧
    在移动设备上实现高效布局适配时,使用rem单位已成为一种流行且有效的技术。本文将分享过去一年中使用rem进行布局适配的经验和心得。rem作为一种相对单位,能够根据根元素的字体大小动态调整,从而确保不同屏幕尺寸下的布局一致性。通过合理设置根元素的字体大小,开发者可以轻松实现响应式设计,提高用户体验。此外,文章还将探讨一些常见的问题和解决方案,帮助开发者更好地掌握这一技术。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 在本文中,我们将探讨如何在Docker环境中高效地管理和利用数据库。首先,需要安装Docker Desktop以确保本地环境准备就绪。接下来,可以从Docker Hub中选择合适的数据库镜像,并通过简单的命令将其拉取到本地。此外,我们还将介绍如何配置和优化这些数据库容器,以实现最佳性能和安全性。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 利用 Python Socket 实现 ICMP 协议下的网络通信
    在计算机网络课程的2.1实验中,学生需要通过Python Socket编程实现一种基于ICMP协议的网络通信功能。与操作系统自带的Ping命令类似,该实验要求学生开发一个简化的、非标准的ICMP通信程序,以加深对ICMP协议及其在网络通信中的应用的理解。通过这一实验,学生将掌握如何使用Python Socket库来构建和解析ICMP数据包,并实现基本的网络探测功能。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
author-avatar
思路
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有