HBase存储占用过大如何优化?小对象存储场景缩减方案咨询
我之前在处理IoT场景下的小数据对象存储时,遇到过和你几乎一模一样的问题——单条原始数据才400字节左右(20个字段×20字节),但HBase存下来直接翻了5倍,用了FAST_DIFF编码也只能压到3倍左右。后来试了几个组合方案,终于把存储比例降到了1.8倍左右,分享给你参考:
批量打包小对象,摊平KeyValue元数据开销
这是最立竿见影的优化手段。HBase的每个KeyValue条目都要携带rowkey、列族名、列限定符、时间戳这些固定元数据,大概占40-60字节(取决于rowkey长度),对于400字节的小对象来说,这个元数据的占比实在太高了。你可以把多个小对象(比如10-50个)用Protobuf或者自定义序列化方式打包成一个大字节数组,存在同一个单元格里。这样N个小对象只需要一份KeyValue元数据,平摊下来每个小对象的元数据开销直接降到原来的1/N。我当时把20个小对象打包成一个,直接把存储占比从5倍压到了2.2倍。缩短RowKey、列族和列限定符的长度
这些字段是每个KeyValue都要携带的,能短则短:- RowKey如果是UUID这类长字符串,改成雪花ID(16字节)或者紧凑的数字编码;如果是业务ID,尽量用二进制而非字符串存储,能省不少字节。我之前把32字节的UUID换成16字节的雪花ID,每个
KeyValue直接省了16字节,积少成多效果很明显。 - 列族名和列限定符别用长名称,比如把列族
data改成d,列限定符full_object改成f,虽然单个看起来省得不多,但量大了之后总开销能降不少。另外尽量只用一个列族,多列族会生成单独的HFile,增加额外管理开销。
- RowKey如果是UUID这类长字符串,改成雪花ID(16字节)或者紧凑的数字编码;如果是业务ID,尽量用二进制而非字符串存储,能省不少字节。我之前把32字节的UUID换成16字节的雪花ID,每个
配合压缩算法,和DATA_BLOCK_ENCODING形成互补
FAST_DIFF是对数据块内的KeyValue做前缀共享编码,在此基础上还可以开启HBase的压缩算法,推荐SNAPPY或者LZ4——这两个兼顾压缩比和读写性能,非常适合小对象场景。两者配合后,数据块先经过FAST_DIFF编码,再用压缩算法压缩,能进一步降低存储空间。我当时开启SNAPPY后,又把存储占比降了0.4倍左右。清理无效存储,减少冗余
- 如果你的数据不需要多版本,把表的
VERSIONS参数设置为1(默认是3),避免旧版本占用空间; - 给数据设置合理的TTL,让HBase自动清理过期数据,减少无效存储的占比。
- 如果你的数据不需要多版本,把表的
调整HFile块大小,平衡存储与性能
默认的HFile块大小是64KB,对于小对象来说,这个块里能容纳的KeyValue数量不多,块索引的开销占比会比较高。可以把块大小调小到16KB或32KB,这样块索引的开销会降低,同时压缩效率也会更高(块内数据更紧凑)。不过要注意,块太小会增加IO次数,需要根据你的读写性能要求做平衡。
这些方案组合起来,应该能帮你把存储比例降到2倍以内,甚至接近1.5倍。你可以根据自己的业务场景(比如读写频率、数据生命周期)调整优先级,先试打包和缩短元数据这两个最有效的手段。
内容的提问来源于stack exchange,提问作者Tien Dat




