【HBase运维】跨版本迁移

问题来源

目前公司运维着两个版本HBase,分别对应社区的94版本和1.1版本。从16年开始推广新版本,新版本在功能和性能上都比94好,未来方向也在新版本上,所以有些业务需要从94版本升级到新版本,如何解决业务版本升级是团队面临的一个问题?

版本升级方案比较

版本升级有两种方式,原地升级和迁移数据升级,原地升级就是直接在原来的集群从94版本升级到1.1版本,而另一种方式就是通过把数据从94版本迁移到新版本。

  • 原地升级

从94版本原地升级到1.1,需要升级HDFS和HBase,但是目前由于94版本比较低,从94升级到96的时候是没有办法滚动升级的,也就是说在升级期间业务肯定不能读写了。那么什么情况下适合原地升级?其实在双11之前,我们就采用过原地升级的方式升级推荐搜索集群。推荐搜索比较特殊,除了是主备集群之外,整个业务可以控制数据推送,以及随时切换流量的读写。所以,我们的任务就是在业务切换流量后,升级一个集群,完成之后升级另一个集群就可以。如果业务可以停止读写,那么原地升级是最简单的。但是大多数情况下,业务都不能停止读写或者长时间不读写。

  • 为什么需要跨版本实时同步数据

目前94版本是几个业务共用一个集群,而且没有主备,更要命的是有些业务要求升级,而有些不需要,因此数据迁移是唯一的方案。但是迁移数据不是简单copy数据,除了跨版本之外,还涉及迁移原来数据和实时新增数据。找到一种方案解决跨版本迁移,包括迁移原来的数据是实时迁移数据,是解决整个问题的关键。

  • 从同个版本数据迁移讲起

同个版本迁移数据的时候,我们采用snapshot + replication的方式,客户端只需要自己选择时间切换就可以了。思路大概如下:两个集群做好同步,在某一时刻,暂停同步,做snapshot,迁移数据,打开replication同步积压的数据,完成。但是在新老版本之间是没有办法做replication的,怎么解决这个问题?搞过HBase的都知道replication的原理,主集群把日志发到从集群,从集群解析日志写到主集群。那么我们只要想办法改成写到新版本就可以了,下面讲一下我的方案(馊主意):

实时跨版本replication数据

这里,我们依然需要一个备份集群,但是备份集群本身是不写数据到自己的,只是做为一个桥梁。我们通过更改写数据的方式,改成通过http服务写到新版本的rest服务,由rest直接写到新版本集群就可以。整个流程大概如下:

[图片上传失败…(image-222a07-1512708955600)])

这里涉及的代码也比较简单,主要涉及一个类——ReplicationSink:


  初始化ReplicationSink的时候,初始化rest参数

  private void initRest() throws IOException {

        //host:port;host:port

        String hostsConf = conf.get("rest.host.list");

        if (StringUtils.isEmpty(hostsConf)) {

            throw new IOException("没有配置新版本的rest服务");

        }

        LOG.info("rest.host.list Conf:" + hostsConf);

        String[] nodeArray = hostsConf.split(";");

        if (null == nodeArray || nodeArray.length == 0) {

            throw new IOException("rest.host.list 配置异常");

        }

        this.cluster = new Cluster();

        for (String node : nodeArray) {

            cluster.add(node);

        }

    }

  更改batch方法:

  try {

    table = new RemoteHTable(client, Bytes.toString(tableName));

    List<Put> putList = new ArrayList<Put>();

    List<Delete> deleteList = new ArrayList<Delete>();

    for (List<Row> rows : allRows) {

        for (Row row : rows) {

            LOG.info(row.toString());

            if (row instanceof Put) {

                putList.add((Put) row);

            } else if (row instanceof Delete) {

                deleteList.add((Delete) row);

            }

        }

        table.put(putList);

        table.delete(deleteList);

        this.metrics.appliedOpsRate.inc(rows.size());

    }  

原来数据迁移

目前尝试了一下,在没有改代码的情况下是没有办法在HBase层面上通过snapshot从老版本迁移到新版本,所以只能从HDFS层面下手。因为数据是实时写,我们只要做好同步之后,在某个时刻,暂定同步,flush数据,然后通过“暴力迁移”的方式解决:

在HDFS层面上创建快照


hdfs dfsadmin -allowSnapshot /hbase/HB_RT_WIRELESS_SAFE

hdfs dfs -createSnapshot /hbase/HB_RT_WIRELESS_SAFE  HB_RT_WIRELESS_SAFE_Snapshot

在源集群的快照位置是


/hbase/HB_RT_WIRELESS_SAFE/.snapshot/HB_RT_WIRELESS_SAFE_Snapshot

scp复制数据


hadoop distcp -update -i -delete -skipcrccheck -m 50 -strategy dynamic  h<a>ftp://老集群:50070/hbase/HB_RT_WIRELESS_SAFE/.snapshot/HB_RT_WIRELESS_SAFE_Snapshot</a> hdfs://新集群:8020/hbase/data/default/HB_RT_WIRELESS_SAFE

恢复数据,因为在新版本table的信息文件是.tabledesc,所以需要先手动搞一下


hdfs dfs -rm -r  /hbase/data/default/HB_RT_WIRELESS_SAFE/.tableinfo.0000000001

hbase hbck -fixTableOrphans  "HB_RT_WIRELESS_SAFE"

修复数据


hbase hbck -fixMeta "HB_RT_WIRELESS_SAFE"

hbase hbck -fix "HB_RT_WIRELESS_SAFE"

总结

相比于协调业务慢慢迁移,通过这种方式在DBA迁移好数据之后,业务自己选择时间验证数据之后切换客户端就可以。当然还有其他方式,例如通过Export 和 Import 跑mr的方式。

如果你有更好的方式,或者这种方式考虑不周到的,欢迎讨论。

    原文作者:曾小展
    原文地址: https://www.jianshu.com/p/990bb550be3b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞