Java玩转大数据

Zookeeper 3.6.3+ 兼容老版本 rmr 命令的方法

2022-12-22  本文已影响0人  AlienPaul

背景

大数据软件栈中Zookeeper版本从3.4.14升级到3.6.3,其他组件版本暂时未升级。经过试用发现部分组件工作不正常。其中一个原因是Zookeeper 3.6.3版本移除了rmr命令,取而代之的是deleteall命令,存在不兼容的情况。考虑到软件栈其他组件的升级需要时间,决定先为Zookeeper添加回已经废弃的rmr命令,保持对老版本使用方式的兼容性。

本篇为大家带来Zookeeper 3.6.3添加rmr命令的方法。

操作步骤

首先我们需要下载Zookeeper 3.6.3的源代码。执行:

git clone https://github.com/apache/zookeeper.git

然后切换分支到tag release-3.6.3

分支切换完成之后打开ZookeeperMain这个类,找到static代码块。如下所示:

static {
    commandMap.put("connect", "host:port");
    commandMap.put("history", "");
    commandMap.put("redo", "cmdno");
    commandMap.put("printwatches", "on|off");
    commandMap.put("quit", "");

    new CloseCommand().addToMap(commandMapCli);
    new CreateCommand().addToMap(commandMapCli);
    new DeleteCommand().addToMap(commandMapCli);
    new DeleteAllCommand().addToMap(commandMapCli);
    new SetCommand().addToMap(commandMapCli);
    new GetCommand().addToMap(commandMapCli);
    new LsCommand().addToMap(commandMapCli);
    new GetAclCommand().addToMap(commandMapCli);
    new SetAclCommand().addToMap(commandMapCli);
    new StatCommand().addToMap(commandMapCli);
    new SyncCommand().addToMap(commandMapCli);
    new SetQuotaCommand().addToMap(commandMapCli);
    new ListQuotaCommand().addToMap(commandMapCli);
    new DelQuotaCommand().addToMap(commandMapCli);
    new AddAuthCommand().addToMap(commandMapCli);
    new ReconfigCommand().addToMap(commandMapCli);
    new GetConfigCommand().addToMap(commandMapCli);
    new RemoveWatchesCommand().addToMap(commandMapCli);
    new GetEphemeralsCommand().addToMap(commandMapCli);
    new GetAllChildrenNumberCommand().addToMap(commandMapCli);
    new VersionCommand().addToMap(commandMapCli);
    new AddWatchCommand().addToMap(commandMapCli);

    // add all to commandMap
    for (Entry<String, CliCommand> entry : commandMapCli.entrySet()) {
        commandMap.put(entry.getKey(), entry.getValue().getOptionStr());
    }
}

很明显可以看到,这个方法注册了一系列ZkCli中可以使用的命令。我们找到这一行new DeleteAllCommand().addToMap(commandMapCli);。这一行注册了deleteall命令。接下来的事情就非常明确了:由于rmr命令和deleteall命令逻辑相同,我们根据DeleteAllCommand“改造”出一个用于rmr命令的类就能够满足要求。我们查看DeleteAllCommand这个类的代码。代码关键部分如下所示:

// 无参构造方法
public DeleteAllCommand() {
    // 这个方法中传入的是命令字符串,这里是关键
    this("deleteall");
}

public DeleteAllCommand(String cmdStr) {
    super(cmdStr, "path [-b batch size]");
}

// deleteall命令执行的时候具体需要做什么,在这个方法中体现
@Override
public boolean exec() throws CliException {
    int batchSize;
    try {
        batchSize = cl.hasOption("b") ? Integer.parseInt(cl.getOptionValue("b")) : 1000;
    } catch (NumberFormatException e) {
        throw new MalformedCommandException("-b argument must be an int value");
    }

    String path = args[1];
    try {
        // 使用ZkUtil级联删除path和其下所有的znode
        boolean success = ZKUtil.deleteRecursive(zk, path, batchSize);
        if (!success) {
            err.println("Failed to delete some node(s) in the subtree!");
        }
    } catch (IllegalArgumentException ex) {
        throw new MalformedPathException(ex.getMessage());
    } catch (KeeperException | InterruptedException ex) {
        throw new CliWrapperException(ex);
    }
    return false;
}

通过上面的代码分析我们不难发现,执行哪一条命令会调用到DeleteAllCommand是在这个类的构造方法中定义的。

分析到这里我们有了修改思路:

首先我们复制DeleteAllCommand这个类,命名为RmrCommand,修改构造函数名为新的类名。然后修改无参构造函数为如下内容:

public RmrCommand() {
    this("rmr");
}

接下来修改ZookeeperMainstatic代码块,加入这一行:

new RmrCommand().addToMap(commandMapCli);

到这里为止代码修改完毕。最后我们需要重新编译Zookeeper。参考源代码根目录的README_packaging.md。进入源代码根目录执行:

mvn clean install -DskipTests

编译完成的二进制软件包位于:

zookeeper-assembly/target/apache-zookeeper-<version>-bin.tar.gz

验证下新编译出来Zookeeper的rmr命令和deleteall命令是否可用,确保修改生效。

后记

升级须谨慎。大数据各组件之间的版本有依赖关系,形成了一个软件栈。如果对某个组件进行升级,一定要提前了解清楚如下内容:

  1. 组件数据存储格式和数据组织形式是否有变化。
  2. 对外接口是否有变化。支持的操作方式是否有变化。
  3. 部署形式是否有变化。环境和资源要求是否有变化。
  4. 该组件的配置项是否有变化。
  5. 依赖该组件的其他大数据组件有哪些,它们是用什么方式和该组件进行交互。这决定了其他组件是否需要同步修改。
  6. 该组件对其他组件的依赖关系是否有变化。该组件依赖其他组件的版本是否有变化。

本博客为作者原创,欢迎大家参与讨论和批评指正。如需转载请注明出处。

上一篇 下一篇

猜你喜欢

热点阅读