简介
ClickHouse简介
ClickHouse是由号称“俄罗斯Google”的Yandex公司开发并在2016年开源。ClickHouse是一个列存储数据库,是原生的向量化执行引擎。目前ClickHouse在OLAP领域得到了广泛的使用,其首要原因是查询速度快。
在大数据处理中,海量数据的判重和基数统计是两个绕不开的基础问题。ClickHouse的解决方案是使用RoaringBitmap,其已有丰富的bitmap操作函数支持,可以实现非常灵活方便的判重和基数统计操作。
RoaringBitmap(RBM)原理
Bitmap用位图的方式来存储id数值信息,可以实现精确地基数统计。但因为Bitmap在数值稀疏时会造成很大空间浪费,因此提出了用RoaringBitmap(RBM)对稀疏位图进行压缩,减少内存占用并提高效率。RBM的主要思路是:将32位无符号整数按照高16位分桶,即最多可能有2^16=65536个桶,又称为container。存储数据时,按照数据的高16位找到container(找不到就会新建一个),再将低16位放入container中。也就是说,一个RBM就是很多container的集合。其详细的原理可参考文章。
ClickHouse中使用RBM存在的问题
在查看了ClickHouse的文档及搜索了各公司的实践方案(如腾讯和头条)后,发现目前只能将原始明细的id数据导入到ClickHouse后,再通过创建物化视图的方式构建RBM结构进行使用。但是原始明细数据量往往非常大,这不仅给数据ETL处理造成了很大的负担,也对计算资源以及ClickHouse的集群资源要求非常高。
我们的数据ETL处理通常是基于hadoop平台的Spark计算框架进行处理,那能不能在Spark进行数据处理时就将Bitmap数据预计算存储好,这样不仅数据量会大大地减少,同时也能大大地减少对ClickHouse集群资源的要求!
RoaringBitmap(RBM)定制序列化实现
ClickHouse中RoaringBitmap的结构解析
为了在Spark数据预处理时提前计算存储好RBM,首先就需要了解ClickHouse中RBM结构的实现原理。通过在ClickHouse的源码社区进行咨询,了解到ClickHouse是利用CRoaring实现的RBM,并且其存储结构的格式是Byte(1), VarInt(SerializedSizeInBytes), ByteArray(RoaringBitmap)
。
Spark中RoaringBitmap的实现
目前CRoaring没有对应的Java语言实现库,而在Java中RBM的常用实现库是RoaringBitmap,并且其已经在Spark、Kylin和Druid等系统中得到了应用。RoaringBitmap库提供了完善的bitmap操作,对其进行封装后就可以集成到SparkSQL中进行使用。
这是我在Spark中自定义实现的bitmap相关udf函数。因此可以在Hive中定义Binary列来存储RBM计算的中间结果,这样既可以使用SparkSQL对中间结果进行再聚合统计,同时也可以将中间结果直接导入到ClickHouse中进行查询,极大地减少了导入ClickHouse的数据量。