选 Zookeeper 作为注册中心我们还要注意些什么

Zookeeper是一个分布式协调框架,而在它的基本用法在上一节讲过了,很多同学可能会Zookeeper这么好,直接做微服务的注册中心也没啥问题的,其实关于这样点社区里也喋喋不休,几乎在dubbo的每届大会中有大篇幅的讲解。接下来将针对大牛在大厂大集群的实践中去探讨一些坑:

1.注册中心是CP还是AP

在之前的章节分享过关于Consul、zooKeeper、etcd、eureka作为注册中心的选型,对此中间件小哥是这么讲的:

  • 首先ZooKeeper诞生晚于内部注册中心ConfigServer
  • 当时无法解决多机房的问题(ZooKeeper后续版本可以部署observer解决)
  • 他们认为整体设计更应该偏向 AP,而非 CP
  • ZooKeeper 的复杂度难以掌握

笔者观点是,这些今天看来未必是问题,引用大牛的话:

Google的Chubby的设计开发者Burrows曾经说过:“所有一致性协议本质上要么是Paxos要么是其变体”

2.客户端与服务端超时时间

Zookeeper的Client与Zookeeper之间维持的是长连接,并且保持心跳,Client会与Zookeeper之间协商出一个Session超时时间出来(其实就是Zookeeper Server里配置了最小值,最大值,如果client的值在这两个值之间则采用client的,小于最小值就是最小值,大于最大值就用最大值),如果在Session超时时间内没有收到心跳,则该Session过期(关注后续SessionExpired 事件)。

3.复杂的状态机及异常

掌握 ZooKeeper Client/Session 的状态机要并不简单,看完下图你可能依然觉得很懵逼

 

没关系,那我们就关注重要的事件及异常吧

Disconnected 事件(ConnectionLossException)

发生这个异常的原因有很多,例如应用机器与ZooKeeper节点之间网络闪断,ZooKeeper节点宕机,服务端Full GC时间超长,甚至你的应用进程Hang死,应用进程 Full GC 时间超长之后恢复都有可能。很多时候,客户端请求到服务端响应中,当它们之间的长连接闪断的时候,客户端感知到这个闪断事件的时候,会处在一个比较尴尬的境地,Server端到底收到这个请求了么?那我该做什么呢?重试(Retry)?

这完全需要应用开发者自己根据业务语义去评估和处理,必须知晓一点业务请求在Server端服务处理上对于”仅处理一次” “最多处理一次” “最少处理一次”语义要有选择和预期。

SessionExpired 事件(SessionExpiredException )

Session 超时是一个不可恢复的异常,这是指应用Catch到这个异常的时候,应用不可能在同一个Session中恢复应用状态,必须要重新建立新Session,老Session关联的临时节点也可能已经失效,拥有的锁可能已经失效。

4. 网络抖动问题

Zookeeper主要是提供分布式环境的一致性,对于网络隔离的极度敏感,一旦出现网络隔离,zookeeper就要发起选举流程。zookeeper的选举流程通常耗时30到120秒,期间zookeeper由于没有master,都是不可用的。Zookeeper如果出现分区,少数派是不能提供任何服务的,读都不可以。

关于选举这块,重点关注源码的QuorumCnxManager类里的Listener

解决方案:

服务发现其实是不需要严格的一致性的,我们可以缓存server list,当Zookeeper出现问题的时候已然可以正常工作,而etcd要做的更好一些,少数派仍然可以提供读服务。

5.惊群

如果你watch了一些配置,但这个配置发生变更时:

  1. Zookeeper会广播给所有的watcher,广播的内容是zooKeeper事件(非常简短的内容)
  2. 所有Client都来拉取,瞬间造成非常大的网络流量,引起所谓的『惊群』

其实这是zk的问题,据一个工商银行的架构师反馈,他们部署的dubbot集群近万台,除了上面的问题外,注册信息的数据占用应用很高内存,watch时网络消耗非常大,甚至是导致业务的应用系统有性能问题乃至不可用。

一般解决方案:

  • 注册中心的数据那么大,需要思考存储的数据信息,dubbo最新的版本已经分离为元数据中心和注册中心
  • 更新那么频繁,可以通过延迟处理,反正getChildren()可以获取到最新的数据

6.内存占用高,全量同步易超时

zookeeper集群中leader和follower同步数据的极限值是500M,这500M的数据,加载到内存中,大约占用3个G的内存。数据过大,在每次选举之后,需要从server同步到follower,容易造成下面2个问题:

  • 网络传输超时,因为文件过大,传输超过最大超时时间,造成TimeoutException,从而引起重新选举。
  • 如果调大这个超时值,则很可能达到磁盘读写的上限

为何磁盘IO高?

zk通过心跳将事务日志频繁的写磁盘,而优化思路有:

1.将zk事务的日志放入内存中

降低对磁盘的依赖,但需要控制事务日志大小,受内存空间容量限制,它风险点是一旦机房断电会导致zookeeper中的部分数据丢失,可以通过以下步骤解决:

#zookeeper配置:
dataDir=/opt/zookeeperdata
#1.事务日志指向内存文件系统
dataLogDir=/dev/shm
#自动清理时保存在datadir里的数据快照数。最小值3
#autopurge.snapRetainCount=3
#2.关闭自动事务日志的管理(自动清理任务的间隔小时数)
#autopurge.purgeInterval=1
# 每当10000条事务日志写入时,创建snapshot文件
snapCount=10000

#清理事务日志
#!/bin/bash
source /etc/profile
 
#snapshot file dir 
dataDir=/opt/zookeeperdata/version-2
#tran log dir 
dataLogDir=/dev/shm/version-2
 
#leave transaction files
leaveTran=10
#leave snapshot files
leaveSnap=10000
 
echo ""
echo ""
echo "before purge memory:"
free -m
ls -t $dataLogDir/log.* | tail -n +$leaveTran  | xargs rm -f
ls -t $dataDir/snapshot.* | tail -n +$leaveSnap | xargs rm -f
echo "after purge memory:"
free -m

2.SSD-更强的IO

如果不允许重要的数据丢失,它可能是一个不错的方案

可行解决方案:

  • 如果你的应用强依赖zookeeper,则应该申请机器资源,单独配置zookeeper服务器,防止其他应用的影响。这是目前比较可行的解决方案。不要与那些大应用共用一个zookeeper集群,你可能会被它拖挂的。
  • 如果不需要分布式锁,你应该优先考虑不用zookeeper。
  • 不要对zookeeper频繁写入,它只应该存储控制信息和配置信息,也就是说,它更多应该用来做读操作。
  • 不要把zookeeper作为数据存储器

7.关于扩容

zk扩容主要是通过Observer完成的,Observer从3.4系统中新增的,它不负责投票选举,是同步Leader并承担客户端的连接和请求:

  • 不影响参与者选举速度
  • 不影响整体的吞吐量

除此之外,它还有一些高级玩法:

  • Observer分组,客户端流量隔离
  • 异地Observer节点,降低跨城订阅推送流量

而这一块的优化点,可以通过关闭Observer的snapshot和事务日志,来提升Observer节点的IO性能

总结

对应Zookeeper的使用,任何事情所有的未雨绸缪其实源于事前布局,因此我们一定要一些监控,比如:

  • 是否可写:一个定时任务定时的去创建节点,删节点等操作(这些操作的时候不要连接整个集群,而是直接去连接单个节点)
  • 监控watcher数和连接数,特别是这两个数据有较大波动的时候
  • 网络流量以及client ip(谁请求的) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值