ZooKeeper 避坑实践:SnapCount 设置不合理导致磁盘爆满,服务不可用

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 本篇通过深入解读 ZooKeeper 数据文件生成机制,以及 ZooKeeper 中和数据文件生成相关的参数,探究一下 解决 ZooKeeper 磁盘问题的最佳实践。

作者:子葵


背景


在 ZooKeeper 的日常使用过程中,一个令人头疼的问题就是节点的磁盘容量问题,如果由于过大的 TPS 或者不适当的清理策略会导致集群中数据文件,日志文件的堆积,最终导致磁盘爆满,Server 宕机。近期就在线上发现某用户的一个集群在一个时间段内的 TPS 暴增。


1.png


导致磁盘中 snapshot 和 transaction log 文件非常多。


2.png


最终导致磁盘被写满,节点服务不可用。


3.png


本篇通过深入解读 ZooKeeper 数据文件生成机制,以及 ZooKeeper 中和数据文件生成相关的参数,探究一下 解决 ZooKeeper 磁盘问题的最佳实践。


分析


ZooKeeper 中生成的数据文件有哪些?


首先我们需要探究一下  ZooKeeper 对数据进行持久化的基本原理,ZooKeeper 为了保证所有的数据变更不丢失,采用状态机来进行数据的记录和恢复,简单来讲,ZooKeeper 中有一个大 Map 存储所有 Znode,key 就是 Znode 的 Path,value 就是 Znode 中的数据,acl,状态等信息,ZooKeeper 通过在某一时间点对内存中的大 Map 进行序列化得到这一时间点内存中数据的一份快照,同时通过另一个文件,存储在此时间节点之后对这份快照中数据状态的修改操作。


4.png


当 ZooKeeper 节点重启的时候,会通过现有的 snapshot 和 transaction log 进行数据恢复。


5.png

采用这种做法能够很好的保证内存中已变更的数据不会丢失,同时写性能不会有太多损失,在遇到节点宕机之后,能够完整的恢复数据。


从此看来,ZooKeeper 产生的数据文件主要有两类:内存中数据的快照文件,以及存储变更的事务日志文件,这两类文件分别通过配置文件中的 dataDir 和 dataLogDir 进行指定,这也是 ZooKeeper 中占用磁盘空间比较大的两类文件。


当 zk 中数据存储过多或者数据变更非常频繁的情况下,将内存中的存储的 snapshot 序列化到文件中,以及数据变更产生的事务日志文件就会很多很大,如果没有配置合适数据清理策略和参数,磁盘问题将会导致集群节点宕机,甚至服务不可用。


public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
    ...
    public void takeSnapshot(boolean syncSnap) {
        long start = Time.currentElapsedTime();
        try {
            txnLogFactory.save(zkDb.getDataTree(), zkDb.getSessionWithTimeOuts(), syncSnap);
        } catch (IOException e) {
            LOG.error("Severe unrecoverable error, exiting", e);
            // This is a severe error that we cannot recover from,
            // so we need to exit
            ServiceUtils.requestSystemExit(ExitCode.TXNLOG_ERROR_TAKING_SNAPSHOT.getValue());
        }
            ...
    }
    ...
}


当 Server 尝试将内存中的数据写入磁盘的时候,就会产生异常,Server 进程会直接退出。


对于这些问题,ZooKeeper 官方提供一些参数,通过合理的配置参数能够有效的减缓磁盘压力,接下来深入探究一下相关参数。


  • autopurge.snapRetainCount : (No Java system property) New in 3.4.0
  • autopurge.purgeInterval : (No Java system property) New in 3.4.0


首先 ZooKeeper 官方是支持定时清理数据文件的能力的,通过 autopurge.snapRetainCount  和 autopurge.purgeInterval 指定清理的间隔和清理时需要保留的数据文件的个数,这里需要注意的是,ZooKeeper 中开启此能力需要将 autopurge.purgeInterval 设置为一个大于 0 的值,此值代表清理任务运行的间隔(单位是小时)。一般情况下,配置这两个参数开启定时清理能力之后能够很大程度减轻磁盘的容量压力。但是定时清理任务的最小间隔是 1 小时,这在一些特殊场景下无法避免磁盘爆满的问题。


当在两次磁盘的清理间隔中,有大量的数据变更请求时,会产生大量的 transaction log 文件和 snapshot 文件,由于没有达到清理的事件间隔,数据累计最终在下一次磁盘清理之前把磁盘写满。为了更好了理解其他参数,我们先探究一下 ZooKeeper 会在什么时候产生快照文件和事务日志文件。


ZooKeeper 在什么时间生成这些数据文件


通过在代码中方法引用 (ZooKeeperServer.takeSnapshot),发现在以下情况下会触发新的快照文件的生成


  • 节点启动,加载完数据文件之后
  • 集群中产生新 leader
  • SyncRequestProcessor 中达到一定条件(shouldSnapshot 方法指定)


前两种情况都是非高频的,我们看一下第三种情况,在 SyncRequestProcessor 的 run 方法中调用了 takeSnapshot 方法,在此之前调用了 shouldSnapshot 进行了判断:


private boolean shouldSnapshot() {
    int logCount = zks.getZKDatabase().getTxnCount();
    long logSize = zks.getZKDatabase().getTxnSize();
    return (logCount > (snapCount / 2 + randRoll))
        || (snapSizeInBytes > 0 && logSize > (snapSizeInBytes / 2 + randSize));
}


其中 logCount 的值是当前事务日志文件的大小以及事务日志的数量,snapCount,snapSizeInBytes 是通过 Java SystemProperty 配置的值,randRoll 是一个随机数(0 < randRoll < snapCount / 2),randSize 也是一个随机数(0 < randSize < snapSizeInBytes / 2),因此这个判断条件的逻辑可以总结为下:


当当前事务日志文件中的事务数量大于运行时产生的和 snapCount 相关的一个随机值(snapCount/2 < value < snapCount)或者当前的事务日志文件的大小大于一个运行是产生的和 snapSizeInBytes 相关的随机值(snapSizeInBytes/2 < value < snapSizeInBytes)就会进行一次 snapshot 的文件写入,并且可以从代码中看到,写入snapshot会将现在的事务日志文件刷入磁盘,并新建一个事务日志文件。


public void run() {
    if (shouldSnapshot()) {
        resetSnapshotStats();
        // 滚动事务日志文件
        zks.getZKDatabase().rollLog();
        // take a snapshot
        if (!snapThreadMutex.tryAcquire()) {
            LOG.warn("Too busy to snap, skipping");
        } else {
            new ZooKeeperThread("Snapshot Thread") {
                public void run() {
                    try {
                        zks.takeSnapshot();
                    } catch (Exception e) {
                        LOG.warn("Unexpected exception", e);
                    } finally {
                        snapThreadMutex.release();
                    }
                }
            }.start();
        }
    }
}


snapCount,snapSizeInBytes 这两个变量可以通过 ZooKeeper 的配置文件中指定。


  • snapCount : (Java system property: zookeeper.snapCount)
  • snapSizeLimitInKb : (Java system property: zookeeper.snapSizeLimitInKb)


由此可知,可以通过在配置文件中配置 snapCount 和 snapSizeLimitInKb 来控制 snapshot 文件产生的频率。


建议


通过以上分析可知,可以通过 4 个参数对 ZooKeeper 的数据文件生成和清理进行配置。


  • autopurge.snapRetainCount : (No Java system property) New in 3.4.0
  • autopurge.purgeInterval : (No Java system property) New in 3.4.0
  • snapCount : (Java system property: zookeeper.snapCount)
  • snapSizeLimitInKb : (Java system property: zookeeper.snapSizeLimitInKb)


前两个配置项指定 ZooKeeper 的定时清理策略,后两个参数配置ZooKeeper生成快照文件的频率。


根据前面分析,可以指通过将 snapCount 和 snapSizeLimitInKb 调整大可以减小 snapshot 的生成频率,但是如果设置的过大,会导致在节点重启时,加载数据缓慢,延长服务的恢复时间,增大业务风险。


autopurge.purgeInterval 最小只能指定为 1,这将清理间隔硬限制到 1 小时,针对高频写入情景无法降低风险。


MSE ZooKeeper 针对以上分析的 ZooKeeper 的磁盘问题,设置了合适的参数,并且用户可以方便更改相关参数实现业务场景适配,并且 MSE ZooKeeper 在 ZooKeeper 自身的数据清理机制外,提供额外保障手段,保障集群免受磁盘问题影响。


6.png


运营活动


重磅推出 MSE 专业版,更具性价比,可直接从基础版一键平滑升级到专业版!


7.png


点击此处,前往微服务引擎 MSE 官网查看更多~

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
26天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
39 2
|
1天前
|
存储 大数据 Apache
深入理解ZooKeeper:分布式协调服务的核心与实践
【5月更文挑战第7天】ZooKeeper是Apache的分布式协调服务,确保大规模分布式系统中的数据一致性与高可用性。其特点包括强一致性、高可用性、可靠性、顺序性和实时性。使用ZooKeeper涉及安装配置、启动服务、客户端连接及执行操作。实际应用中,面临性能瓶颈、不可伸缩性和单点故障等问题,可通过水平扩展、集成其他服务和多集群备份来解决。理解ZooKeeper原理和实践,有助于构建高效分布式系统。
|
21天前
|
存储 Linux 数据库
ZooKeeper【搭建 01】apache-zookeeper-3.6.2 单机版安装+配置+添加到service服务+开机启动配置+验证+chkconfig配置(一篇入门zookeeper)
【4月更文挑战第8天】ZooKeeper【搭建 01】apache-zookeeper-3.6.2 单机版安装+配置+添加到service服务+开机启动配置+验证+chkconfig配置(一篇入门zookeeper)
37 0
|
3月前
|
Java Linux Spring
Zookeeper实现分布式服务配置中心
Zookeeper实现分布式服务配置中心
49 0
|
4月前
|
Dubbo Java 应用服务中间件
Dubbo 3.x结合Zookeeper实现远程服务基本调用
ZooKeeper和Dubbo是两个在分布式系统中常用的开源框架,它们可以协同工作,提供服务注册与发现、分布式协调等功能。
|
4月前
|
存储 API
Zookeeper分布式协调服务
Zookeeper分布式协调服务
|
5月前
|
消息中间件 Kafka Shell
Linux【脚本 02】shell脚本离线安装配置Zookeeper及Kafka并添加service服务和开机启动(脚本分析)
Linux【脚本 02】shell脚本离线安装配置Zookeeper及Kafka并添加service服务和开机启动(脚本分析)
48 0
|
4月前
|
消息中间件 Java 网络安全
JAVAEE分布式技术之Zookeeper的第一次课
JAVAEE分布式技术之Zookeeper的第一次课
70 0
|
2月前
|
监控 NoSQL Java
Zookeeper分布式锁
Zookeeper分布式锁
90 1
|
4月前
|
监控 Dubbo Java
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
63 0

相关产品

  • 微服务引擎