从这篇开始记录一下集群迁移的事情

早先因为机房没地方,就已经开始规划集群搬机房的事情,最近终于开始动手了,我会把这次不停机迁移的过程遇到的主要问题和矛盾以及各种解决方法记录下来。

集群规模说大不大,几百台,总容量30PB左右。Hadoop使用CDH 5.5.1加一些自定义patch的rpm打包编译版本。

总的方案是集群不停机,在两个机房之间架设专线,旧机房decommission,拉到新机房recommission。每天不能下线太多机器,要保证计算。

  1. 新机房提前架设90台机器,测试带宽。带宽的测试方式是比较简单粗暴的,就是在新机房拿几十台新机器搭一个集群,然后旧机房集群和新机房集群之间做distcp,带宽能打满即可。

  2. 新机房拆除小集群,合并到大集群里,机架感知按照 "/机房/机架" 这种方式划分,然后提前做一段时间balancer。

当然在这里面会发现一些问题,我记录在上一篇博客里了,这里再重复记录一下。

  1. 万兆网卡的mtu问题,新机房的新机器datanode报slow block receiver问题,调整网卡mtu从1500到9000,解决。

  2. df 命令卡死,升级systemd并重启解决

  3. 跑作业慢,打Centos 7 CPU补丁 重启

  4. 广播风暴问题,流量比较大,查看网口每机器每秒几百条ARP通告,目前无解,后续运维VLAN解决。

详情看 运维记录系列二十三 http://blog.51cto.com/slaytanic/2141665


期间还遇到了decommission速度慢的问题,调整了一下dn参数dfs.datanode.max.transfer.threads到16384,然后调整NN参数 dfs.namenode.replication.max-streams-hard-limit参数到8感觉也没快多少,然后翻看源码,在 src/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/UnderReplicatedBlocks.java 这个文件里面

public synchronized List<List<Block>> chooseUnderReplicatedBlocks(
int blocksToProcess) {
  // initialize data structure for the return value
  List<List<Block>> blocksToReplicate = new ArrayList<List<Block>>(LEVEL);
  for (int i = 0; i < LEVEL; i++) {
    blocksToReplicate.add(new ArrayList<Block>());
  }

  if (size() == 0) { // There are no blocks to collect.
    return blocksToReplicate;
  }
  int blockCount = 0;
  for (int priority = 0; priority < LEVEL; priority++) {
    // Go through all blocks that need replications with current priority.
    BlockIterator neededReplicationsIterator = iterator(priority);
    Integer replIndex = priorityToReplIdx.get(priority);
    // skip to the first unprocessed block, which is at replIndex
    for (int i = 0; i < replIndex && neededReplicationsIterator.hasNext(); i++) {
      neededReplicationsIterator.next();
    }

    blocksToProcess = Math.min(blocksToProcess, size());
    if (blockCount == blocksToProcess) {
      break;  // break if already expected blocks are obtained
    }
    // Loop through all remaining blocks in the list.
    while (blockCount < blocksToProcess
      && neededReplicationsIterator.hasNext()) {
      Block block = neededReplicationsIterator.next();
      blocksToReplicate.get(priority).add(block);
      replIndex++;
      blockCount++;
    }
    if (!neededReplicationsIterator.hasNext()
      && neededReplicationsIterator.getPriority() == LEVEL - 1) {
      // reset all priorities replication index to 0 because there is no
      // recently added blocks in any list.
      for (int i = 0; i < LEVEL; i++) {
        priorityToReplIdx.put(i, 0);
      }
      break;
    }
    priorityToReplIdx.put(priority, replIndex);
  }
  return blocksToReplicate;
}

从这里获取需要被复制的数据块的索引,我们只需要将 Integer replIndex = proorityToReplIdx.get(priority);改为 Integer replIndex = 0;即可。

但是为了改一行代码我还得重新编译,就不划算了。于是同事找了个工具叫byteman,jboss公司出品的内存修改器,可以理解成针对Java进行内存修改的金山游侠。


具体修改参考同事的github,我就不重复了。不过万一内存改崩溃了,本人不负任何责任。


https://github.com/whitelilis/whitelilis.github.io/issues/17