5.3 表设计与二级索引实战


文档摘要

5.3 表设计与二级索引实战:订单表与画像表 本节摘要:用两张真实生产表把 5.1、5.2 的决策串成完整 Schema,并解决 HBase 没有二级索引带来的"一表难敌多查询"问题——双写冗余表、协处理器索引、索引表、搜索引擎四种方案的实现与取舍。 订单表:主体加时间的标准解 需求:日增 5000 万单,保存 2 年;查询以"按用户查订单列表(近 3 个月优先)"为绝对主力(95%),另有按订单号点查(4%)、按商户对账(1%)。 RowKey 推演(按 5.1 的清单法):主查询是"主体 + 时间",选反转散列 + 倒排时间: 三段各自的理由:反转用户号把首字节打散(落点均匀,3.1 节预分区的分界按反转后空间切);

5.3 表设计与二级索引实战:订单表与画像表

本节摘要:用两张真实生产表把 5.1、5.2 的决策串成完整 Schema,并解决 HBase 没有二级索引带来的"一表难敌多查询"问题——双写冗余表、协处理器索引、索引表、搜索引擎四种方案的实现与取舍。

订单表:主体加时间的标准解

需求:日增 5000 万单,保存 2 年;查询以"按用户查订单列表(近 3 个月优先)"为绝对主力(95%),另有按订单号点查(4%)、按商户对账(1%)。

RowKey 推演(按 5.1 的清单法):主查询是"主体 + 时间",选反转散列 + 倒排时间:

rowkey = 反转(用户ID 二进制倒序) + (MAX_LONG - 下单时间戳毫秒) + 订单号后4位 长度约 8 + 8 + 4 = 20 字节

三段各自的理由:反转用户号把首字节打散(落点均匀,3.1 节预分区的分界按反转后空间切);倒排时间让最新订单排在扫描头部,"最近 3 个月"查询 LIMIT 100 通常扫几十行即止(5.1 节倒排时间戳);订单号后缀兜底唯一性。

按订单号点查怎么办?订单号不是行键前缀,直接查等于全表扫描。答案是双表:写订单的同时写一张 orders_by_oid 索引表,行键就是订单号,value 只存指向主表的完整行键:

主表: rev(u1001) + inv(ts) + 5678 → cf:status, cf:amount ... 索引表: ORD20240819005678 → f:rk = rev(u1001)+inv(ts)+5678

查询路径:索引表点查拿到主表行键 → 主表 get,两跳完成。写入端多一次 RPC,一致性由写入方保证(先写主表后写索引,失败则补偿重试)。这就是应用层维护的二级索引,最朴素也最可控。

对账查询:按商户 1% 频率、跑批型,不值得为之改行键——直接全表扫描(低峰、限流)或导出到分析引擎(第 6 章生态集成)。

参数(沿用 5.2 的决策):单列族 cf,VERSIONS=1,TTL=63072000(2 年),SNAPPY,ROW 布隆,块 64 KB。建表预分区分界按反转用户号空间均匀切 32 份。

画像表:宽表现势

需求:1 亿用户,每人 300–2000 个标签;查询以"取某人全部标签"(点查)为主,另有"某标签下有哪些人"(反查,周级运营批任务)。

正向表一张:行键 md5(用户ID) 前4字节 + 用户ID(哈希前缀模式,5.1 表格第一行场景),单列族 tag,每个标签一个列限定符(动态列的天然舞台,1.2 节),value 就是标签值或空:

a3f2... | u1001 | tag:age_seg=25_30 tag:city=hz tag:rfm=high ...

三千个标签也只是一行内的三千列,读取一次 get 全带回。VERSIONS=1、TTL 永久、SNAPPY。列限定符本身占存储(2.3 节 KeyValue 编码),超长标签名要编码缩短(如 age_sega1,映射表放业务侧)。

反查(标签 → 人群):正向表无法反查,建一张倒排表:行键 = 标签ID + 分桶号,列限定符 = 用户哈希,value 空。人群圈选用 scan 遍历该标签的所有分桶。倒排表通常由离线任务(Spark 批计算)重建而非实时双写——画像数据天生的最终一致性容忍度,让"离线倒排"比"实时双写"省一半复杂度。

二级索引四方案对比

方案 一致性 开发量 适用
应用双写(本文订单表) 最终一致,可控 索引少、写入方集中
索引协处理器 较强(同 Region 事务界内) 不想改写入方,第 6 章展开
离线重建(画像倒排) 小时级延迟 反查容忍滞后
外部搜索引擎 准实时 多条件组合查询

选型的一条经验:索引数量与一致性要求成反比地推高复杂度。双写两个索引还能人工兜底,双写十个索引的补偿逻辑没人能维护——那种场景说明需求已经越出 HBase 的舒适区,考虑搜索引擎或宽表引擎。

上线前的验算清单

Schema 定稿前过一遍:

  1. 落点验算:用生产样本键跑 locate_region,确认分布均匀(5.1 的热点实验流程);
  2. 扫描宽度验算:主查询在样本数据上的 LIMIT 100 命中行数,超过几百行说明倒排/前缀设计有漏洞;
  3. 容量验算:行数 × 平均行大小 ×(1 + 列族数 × 0.1 索引开销)× 3 副本,对比磁盘预算;
  4. 增长验算:两年后的 Region 数(数据量 / 10 GB),是否超过单 RegionServer 合理 Region 数(经验值数百);
  5. 回退方案:快照已打、双写已验证、切读开关在手(迁移流程见第 7 章)。

⚠️ 常见坑:双写索引表与主表用不同预分区策略,索引表自己先热点了。两张表的行键散列逻辑要一起设计——它们共享同一份写入流量。

💡 关键直觉:HBase 的 Schema 设计是"为查询清单做仲裁",每张好表都是对 95% 查询的偏袒。想一碗水端平的表,最后通常是全表扫描的慢表。

本节要点回顾

  • 订单表范式:反转主体 + 倒排时间 + 唯一后缀,配订单号双表索引,对账走离线;
  • 画像表范式:哈希前缀 + 单行宽列,反查靠离线倒排表,标签名编码缩短;
  • 二级索引四方案:双写、协处理器、离线重建、搜索引擎,按一致性与复杂度递进;
  • 双表同散热:索引表与主表共享写入流量,预分区必须一起设计;
  • 五项验算:落点、扫描宽度、容量、Region 增长、回退,上线前逐项过。

Schema 齐备,下一章看 HBase 的三个高级武器——协处理器、布隆过滤器、读缓存与生态集成——它们都是对前五章机制的"再加工"。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U