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



推荐阅读
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 本文总结了淘淘商城项目的功能和架构,并介绍了传统架构中遇到的session共享问题及解决方法。淘淘商城是一个综合性的B2C平台,类似京东商城、天猫商城,会员可以在商城浏览商品、下订单,管理员、运营可以在平台后台管理系统中管理商品、订单、会员等。商城的架构包括后台管理系统、前台系统、会员系统、订单系统、搜索系统和单点登录系统。在传统架构中,可以采用tomcat集群解决并发量高的问题,但由于session共享的限制,集群数量有限。本文探讨了如何解决session共享的问题。 ... [详细]
  • JSP内置对象之application的作用范围和获取方式
    本文介绍了JSP内置对象之application的作用时间范围、可以在不同浏览器获取的特点,以及获取application对象的方法。通过示例代码展示了在JSP中设置和在servlet中获取application对象的步骤。对于学习JSP内置对象的读者来说,本文具有一定的参考价值。摘要长度为163字。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 如何在php文件中添加图片?
    本文详细解答了如何在php文件中添加图片的问题,包括插入图片的代码、使用PHPword在载入模板中插入图片的方法,以及使用gd库生成不同类型的图像文件的示例。同时还介绍了如何生成一个正方形文件的步骤。希望对大家有所帮助。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
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社区 版权所有