如何高效全表扫描 Apache Phoenix 的表
前段时间有个需求,需要从 Phoenix 里全量导出一个大表到 Hive 用于后续的查询和分析。经过一番调研和对比,最终用 Python 实现了一版直接从 HBase 并行扫描导出的程序。全表大约 230 亿行记录,同步程序峰值导出速度大约 12 万行每秒,整个同步过程历时 55 个小时。
数据表介绍
Apache Phoenix 是一个基于 Apache HBase 的 OLTP 和业务数据分析引擎,数据存储在 HBase,对外提供标准 SQL 和 JDBC API. 我们目前用 Phoenix/HBase 存储了几百 TB 的爬虫数据,日常的读写都是通过 QueryServer 调用 SQL 实现。Phoenix 支持二级索引,但我们在使用的时候出现过导致 HBase RegionServer 挂掉的情况(有可能是表太大或者使用方式不对),因此实际上基本没用二级索引
前面提到的大表是个评论内容表(后文简称 comment 表),当前的表结构大致如下:
CREATE TABLE COMMENT
(
OBJECT_ID BIGINT NOT NULL, -- 评论的对象 ID,可理解为电商的商品 ID,论坛的贴子 ID 等
COMMENT_TIME TIMESTAMP NOT NULL, -- 评论的时间
COMMENT_ID BIGINT NOT NULL, -- 本条评论记录的 ID
UPDATE_TIME TIMESTAMP, -- 插入时间
ORIGIN_DATA VARBINARY, -- 原始数据,是个用 snappy 压缩过的 JSON 对象
CONSTRAINT PK PRIMARY KEY (OBJECT_ID, COMMENT_TIME, COMMENT_ID) -- 联合主键
) DATA_BLOCK_ENCODING='FAST_DIFF', COMPRESSION = 'GZ';
其中 COMMENT_ID
是事实上的唯一主键,但由于查询条件主要是基于 OBJECT_ID
和 COMMENT_TIME
,因此在建表的时候就用了 OBJECT_ID, COMMENT_TIME, COMMENT_ID
作为联合主键。OBJECT_ID
是评论对象的 ID,取值范围大,分布非常稀疏(10^6 ~ 10^12)。另外由于不同对象的热度差异也很大,从 OBJECT_ID
的维度看存在数据倾斜,有的 OBJECT_ID
可能只有几条评论,有的却几千万。ORIGIN_DATA
是个用 snappy 压缩过的 JSON 对象,内部包含评论的所有详情信息,其中有个属性记录了评论对象的标签(后文称 tag
)。