前言
HBase是当下流行的一款海量数据存储的分布式数据库。往往海量数据存储会涉及到一个成本问题,如何降低成本。常见的方案就是通过冷热分离来治理数据。冷数据可以用更高的压缩比算法(ZSTD),更低副本数算法(ErasureCoding),更便宜存储设备(HDD,高密集型存储机型)。
HBase冷热分离常见解决方案
1.主备集群
备(冷)集群用更廉价的硬件,主集群设置TTL,这样当数据热度退去,冷数据自然只在冷集群有。
优点:方案简单,现成内核版本都能搞
缺点:维护开销大,冷集群CPU存在浪费
1.x版本的HBase在不改内核情况下,基本只能有这种方案。
2.HDFSArchivalStorage+HBaseCF-levelStoragePolicy
需要在2.x之后的版本才能使用。结合HDFS分层存储能力+在Table层面指定数据存储策略,实现同集群下,不同表数据的冷热分离。
优点:同一集群冷热分离,维护开销少,更灵活的配置不同业务表的策略
缺点:磁盘配比是个很大的问题,不同业务冷热配比是不一样的,比较难整合在一起,一旦业务变动,集群硬件配置是没法跟着变的。
云HBase冷热分离解决方案
上述2套方案都不是最好的方案,对于云上来说。第一套方案就不说了,客户搞2个集群,对于数据量不大的客户其实根本降不了成本。第二套方案,云上客户千千万,业务各有各样,磁盘配置是很难定制到合适的状态。
云上要做cloudnative的方案,必须满足同集群下,极致的弹性伸缩,才能真正意义上做到产品化。云上低成本,弹性存储,只有OSS了。所以很自然的想到如下架构:
实现这样的架构,最直接的想法是直接改HBase内核:1)增加冷表数据标记2)根据标记增加写OSS的IO路径。
这样做的缺陷非常明显,你的外部系统(如:备份恢复,数据导入导出)很难兼容这些改动,他们需要感知哪些是冷文件得去OSS哪个位置读,哪些是热文件得去部署在云盘上的HDFS上读。这些本质上都是一些重复的工作,所以从架构设计角度来看必须抽象出一层。这一层能读写HDFS文件,读写OSS文件,感知冷热文件。这一层也就是我最后设计出的ApsaraDBFileSystem,实现了HadoopFileSystemAPI。对于HBase,备份恢复,数据导入导出等系统只要替换原先FileSystem的实现即可获得冷热分离的功能。
下面将详细阐述,这套FileSystem设计的细节与难点。
ApsaraDBFileSystem设计
核心难点A
1.OSS并非文件系统
OSS并不是一个真正意义上的文件系统,它仅仅是两级映射bucket/object,所以它是对象存储。你在OSS上看到类似这样一个文件:
/root/user/gzh/file
。你会以为有3层目录+1个文件。实际上只有一个对象,这个对象的key包含了
/
字符罢了。
这么带来的一个问题是,你要想在其上模拟出文件系统,你必须先能创建目录。很自然想到的是用
/
结尾的特殊对象代表目录对象。Hadoop社区开源的OssFileSystem就是这么搞的。有了这个方法,就能判断到底存不存在某个目录,能不能创建文件,不然会凭空创建出一个文件,而这个文件没有父目录。
当然你这么做依然会有问题。除了开销比较大(创建深层目录多次HTTP请求OSS),最严重的是正确性的问题。试想一下下面这个场景:
把目录
/root/user/source
rename成
/root/user/target
。这个过程除了该目录,它底下的子目录,子目录里的子文件都会跟着变。类似这样:
/root/user/source/file=/root/user/target/file
。这很好理解,文件系统就是一颗树,你rename目录,实际是把某颗子树移动到另一个节点下。这个在NameNode里的实现也很简单,改变下树结构即可。
但是如果是在OSS上,你要做rename,那你不得不递归遍历
/root/user/source
把其下所有目录对象,文件对象都rename。因为你没法通过移动子树这样一个简单操作一步到位。这里带来的问题就是,假设你递归遍历到一半,挂了。那么就可能会出现一半目录或文件到了目标位置,一半没过去。这样rename这个操作就不是原子的了,本来你要么rename成功,整个目录下的内容到新的地方,要么没成功就在原地。所以正确性会存在问题,像HBase这样依赖rename操作将临时数据目录移动到正式目录来做数据