title | date |
---|---|
记一次Zookeeper数据找回 |
2017-11-03 02:25:22 -0700 |
ZooKeeper
是可用于维护配置信息,命名,提供分布式同步分组服务的集中式服务。了解更多,请查看 官网
Zookeeper
在我们这的用途,主要是提供分布式配置管理服务。并且我们有一套UI可以管理这些配置。
某一天,某个误操作,导致把一个System(配置是树形结构的,system下面包含有多个具体的key,每个key对应的value才是具体给某个app的配置)全部删除了。由于该System很庞大,我们很难采取手工方式恢复。
考虑到数据存储在 Zookeeper
中,那么是否 Zookeeper
有相关的日志机制,可以恢复呢?
由于配置读取后,会缓存在应用中,只要应用不重启,所以短时间内还不会受到配置丢失的影响,这也是为什么在短时间内,并没有影响具体业务。
由于配置不会经常变,所以就算日志备份不够及时,基本上也是可接受的
首先,我们先确认了 Zookeeper
是否有日志备份机制。很幸运,Zookeeper
在默认配置下运行是有进行定期快照和日志备份的。这也就为恢复提供了极大的可能性。
接着,我们从 ${dataDir}/version-2/
下找到了很多 snapshot.{hash}
的快照文件。
拷贝其中最新的快照(如果判断最新?看创建时间)出来,等待测试。
通过查阅资料,我们在Zookeeper源代码中打开 cmd
, 执行如下命令:
我下载的Zookeeper是3.4.9,所以以此版本为例
java -cp dist-maven/zookeeper-3.4.9.jar;lib/log4j-1.2.16.jar;lib/slf4j-log4j12-1.6.1.jar;lib/slf4j-api-1.6.1.jar org.apache.zookeeper.server.SnapshotFormatter snapshot.4115cad8bf
注意:其中需要的jar文件,都可以在 zookeeper source 下找到。最后一个是具体的快照文件路径
执行之后,控制台刷出一堆数据,欣喜,似乎有戏。
But,仅仅是看起来很好,发现只有Path信息,并没有具体的数据。
别慌,除了快照文件,我们还发现有日志文件,而且单个体积都比快照大(极大可能性有数据)。
接着,我们从 ${dataLogDir}/version-2/
下找到最新的日志文件,通过执行以下命令查看:
java -cp dist-maven/zookeeper-3.4.9.jar;lib/log4j-1.2.16.jar;lib/slf4j-log4j12-1.6.1.jar;lib/slf4j-api-1.6.1.jar org.apache.zookeeper.server.LogFormatter log.4115cad8c1
通过观察控制台,确实发现有相关数据。
But,数据长这样:
session 0x15f5889137c260d cxid 0x3a3 zxid 0x4115caed1f setData '/cloudtask_v2/WORKER-0c6aaa48-8938-4249-8e12-99b71c06b616,#7b2274797065223a322c2
2686f73746e616d65223a224531315745423138222c226c6f636174696f6e223a224531315f45435f584d4c4d616b65725f575757222c226f73223a2277696e646f7773222c22706c6174666f726d223a22616d643634222c22697061646472223a223137322e31362e3134302e323138222c22706964223a313536342c2273696e67696e223a747275652c2274696d657374616d70223a313530393434303732312c22617474616368223a2265794a4b62324a4e5958684462335675644349364d48304b227da,921
看起来很难从这里解析出数据。
继续翻资料,发现Zookeeper启动时可以从日志和快照中自动加载数据。
有路就要尝试,把快照和日志拷贝到对应的目录下,然后重启Zookeeper。
如何重启?
进入Zookeeper目录,执行 "bin/zkServr.cmd"
看起来有戏,应该加载没有报错。
该如何验证呢?
此时,我们尝试使用 Node
编写代码,来读取这个Zookeeper的数据。
const zookeeper = require('node-zookeeper-client');
const client = zookeeper.createClient('localhost:2181');
const listChildren = (client, path) => {
client.getChildren(path, event => {
// listChildren(client, path);
}, (error, children, stat) => {
if (error) {
console.log('Failed to list children of %s due to: %s.', path, error);
return;
}
// 打印出所有的子节点
console.log('Children of %s are: %j.', path, children);
});
};
client.once('connected', function () {
console.log('Connected to the server.');
listChildren(client, '/');
});
client.connect();
发现确实能查询到正确的数据,接着通过操作该实例,读取到丢失节点的数据,恢复到了产线环境。
- 我们在用
Zookeeper
的时候,因为差不多是业界标准,所以直接就上了。并没有进行深入研究,导致出了问题再去查,有一定的时间(万一解决得慢)风险 - 没有预演过程,有较高的不可预测风险
- 对于这种危险操作,在PRD环境,仅仅是有二次提示,误操作的可能性较高
- 没有相关的重要数据备份机制,完全依靠了Zookeeper自身的日志(要是Zookeeper没有日志备份,那就麻烦了)