乐趣区

关于阿里云:ZooKeeper-避坑指南-ZooKeeper-364-版本-BUG-导致的数据不一致问题

作者:子葵

背景

ZooKeeper 作为分布式系统的元数据中心,对外服务的数据一致性须要失去很好的保障,然而一些老版本的 ZooKeeper 在一些状况下可能无奈保证数据的一致性,导致依赖 ZooKeeper 的零碎出现异常。

某用户应用 3.4.6 版本 ZooKeeper 做任务调度,ZooKeeper 实例的 tps 和 qps 都比拟高,事务日志产生的速率很快,即便此用户配置了主动清理的参数,然而主动清理的最小距离还是赶不上数据产生的速度,导致磁盘爆满。

在此用户清理了旧日志之后,重启节点,局部业务机器就报出 NodeExist,NoNode 的异样,并且报错只集中在局部机器,此次异样导致用户任务调度零碎呈现工作反复调度以及工作失落问题,产生重大损失。

起因剖析

仔细检查了这些客户端发现这些客户端都连贯在同一台 ZooKeeper 节点上,通过 zkCli 手动排查节点上的数据,比照其余未清理磁盘的 ZooKeeper 节点,清理了磁盘的 ZooKeeper 节点中的数据和其余节点具备差别,此时确定此节点因为一些起因呈现了数据不统一问题,导致连贯到此节点的客户端读到了脏数据。

然而排查日志,没有发现异常日志。因为此节点之前清理过日志,并且重启过,磁盘上的数据被从新加载过,因而狐疑是 ZooKeeper 在启动加载数据的过程中呈现了一些异常情况。通过剖析 ZooKeeper 启动中加载数据的代码,持续排查具体起因。

public long restore(DataTree dt, Map<Long, Integer> sessions,
            PlayBackListener listener) throws IOException {snapLog.deserialize(dt, sessions);
        FileTxnLog txnLog = new FileTxnLog(dataDir);
        TxnIterator itr = txnLog.read(dt.lastProcessedZxid+1);
        long highestZxid = dt.lastProcessedZxid;
        TxnHeader hdr;
        try {while (true) {
        ...
                try {processTransaction(hdr,dt,sessions, itr.getTxn());
                } catch(KeeperException.NoNodeException e) {
                   throw new IOException("Failed to process transaction type:" +
                         hdr.getType() + "error:" + e.getMessage(), e);
                ...
        return highestZxid;
    }

此处是 ZooKeeper 加载磁盘数据的代码,此办法的次要作用是,首先将磁盘中的 snapshot 文件加载进内存,初始化 ZooKeeper 内存中的数据结构,之后将加载事务日志利用日志中对数据的批改,最终还原磁盘中数据的状态。

然而在 3.4.6 版本的代码中 snapLog.deserialize(dt, sessions); 这行加载 snapshot 文件的代码有一个返回值,此处没有进行返回值校验,导致在 ZooKeeper 自身找不到无效的 snapshot 文件的状况下还是会持续加载事务日志,从而导致 ZooKeeper 在空数据的状态下间接利用事务日志,最终导致此节点的数据和其余节点的数据不统一。

此问题曾经在 ZooKeeper 社区有对应的 issue,在加载 snapshot 的文件列表为空的状况下,此问题曾经失去了修复,然而因为磁盘爆满导致的 snapshot 文件不残缺的其余的一些非凡状况下,此问题仍然存在。解决此问题还须要从磁盘应用的角度解决。

issue:

https://issues.apache.org/jira/browse/ZOOKEEPER-2325

解决方案

为了防止 ZooKeeper 节点的磁盘被疾速打满,能够减少磁盘的容量,配合 ZooKeeper 自身的清理机制,能够在肯定范畴内的 tps 下防止磁盘被写满的情景,然而增大磁盘容量会带来显著的应用老本的进步,并且即便磁盘容量进步了,也可能因为 ZooKeeper 自身清理机制不及时清理,导致磁盘被打满,最终须要通过人工的形式进行磁盘清理,运维起来很简单,消耗人力物力,并且集群稳定性得不到显著晋升。

MSE ZooKeeper 提供 ZooKeeper 实例的全托管,MSE ZooKeeper 实例的磁盘应用对用户齐全通明,用户无需放心磁盘爆满问题,以及磁盘应用过程中的简单运维。MSE ZooKeeper 通过定时清理,触发应用阈值清理等伎俩保障 ZooKeeper 实例在应用过程中磁盘始终处于平安水位,防止因为磁盘问题导致的数据不统一,实例不可用等问题。

MSE ZooKeeper 默认集成 Promethus 监控,提供丰盛的指标信息,并且针对写多的场景,MSE ZooKeeper 提供 TopN 大盘,可能疾速看到业务热点数据,以及高 tps 的客户端状况,可能通过这些统计数据疾速定位业务应用过程中的问题。

退出移动版