热门标签 | 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



推荐阅读
  • 题目概述:Sereja 拥有一个由 n 个整数组成的数组 a1, a2, ..., an。他计划执行 m 项操作,这些操作包括更新数组中的特定元素、增加数组中所有元素的值,以及查询数组中的特定元素。 ... [详细]
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
  • D17:C#设计模式之十六观察者模式(Observer Pattern)【行为型】
    一、引言今天是2017年11月份的最后一天,也就是2017年11月30日,利用今天再写一个模式,争取下个月(也就是12月份& ... [详细]
  • 本文介绍了如何使用Node.js通过两种不同的方法连接MongoDB数据库,包括使用MongoClient对象和连接字符串的方法。每种方法都有其特点和适用场景,适合不同需求的开发者。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 本文详细介绍了如何正确设置Shadowsocks公共代理,包括调整超时设置、检查系统限制、防止滥用及遵守DMCA法规等关键步骤。 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • 本文详细介绍了Elasticsearch中的分页查询机制,包括基本的分页查询流程、'from-size'浅分页与'scroll'深分页的区别及应用场景,以及两者在性能上的对比。 ... [详细]
  • 本文探讨了 Java 中 net.minecraft.client.multiplayer.PlayerControllerMP 类下的 getCurrentGameType() 方法的详细使用方法,并提供了多个实际应用的代码示例。 ... [详细]
  • 本文探讨了Java中线程的多种终止方式及其状态转换,提供了关于如何安全有效地终止线程的指导。 ... [详细]
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社区 版权所有