分片设计不应从表出发

分片设计不应从表出发

💡 原文英文,约1700词,阅读约需6分钟。
📝

内容提要

文章指出,分片设计应以查询为出发点而非表。Neki通过“分片组”将共享同一分片键的表置于同一分片,使连接和事务本地化,避免跨分片提交失去原子性。查找表可设为引用表,每个分片保存完整副本。不同业务可使用不同分片组,并支持SQL表达式、范围与取模索引。无分片键的查询可使用全局二级索引。MoveTables和Reshard工作流可迁移数据、更改分片键或分片数。

🔎

延伸解读

分片组:以查询为中心的数据共置

文章强调分片设计应从查询出发,而非表结构。Neki 的“分片组”将共享同一分片键的表放在同一分片,使连接和事务本地化。例如,将 orders 按 customer_id 分片,与 customers 的 id 哈希方式一致,则同一客户的所有订单、地址等都在一个分片,单客户查询无需跨分片。这不仅能提升性能,还能保持完整的事务语义:跨分片事务无法原子提交,也没有共享快照。

引用表与全局二级索引:应对非分片键查询

对于国家、货币等查找表,可声明为引用表,每个分片保存完整副本,路由器将写操作同步到所有副本,使连接不跨分片。对于无分片键的查询(如按订单 ID 查订单),可使用全局二级索引(GSI)。GSI 维护一张查找表,将订单 ID 映射到分片键 customer_id,查询变为两次单分片读取。GSI 的查找行与订单行在同一请求中写入,已有数据需先回填再启用。

分片策略的灵活性与权衡

Neki 支持多种分片索引类型:推荐的 xxhash 可均匀分布;range 适合按整数范围路由;modulo 虽可预测,但修改模数会移动几乎所有行,因此不建议大规模使用。分片索引还支持 SQL 表达式,如 lower(sku) 或 left(order_id,4),以处理大小写或编码场景。不同业务可使用不同分片组,并独立调整分片数量。MoveTables 和 Reshard 工作流可迁移数据、更改分片键或分片数,使分片方案能随查询演变而调整。

❓

Q&A

分片设计为什么应该从查询出发而不是从表出发?

因为分片的目标是让大多数查询只访问单个分片,避免路由器跨分片收集和聚合结果。从查询出发可以找到最重要的查询和事务共享的键,把携带该键的所有表放在同一个分片组,使连接和事务本地化。

Neki 中的分片组是什么,它如何让关联表的数据放在同一个分片?

分片组是 Neki 中数据共置的单位。当两个表属于同一个分片组并且以相同方式哈希分片键时,具有相同键值的行总是落在同一个分片上。例如,customers 表用 id 作为分片键,orders 等表用 customer_id 作为分片键,通过继承默认索引并指定不同列,使同一客户的所有订单、商品和地址都在一个分片上。

什么是引用表,它解决了什么问题?

引用表是出现在许多查询中但不属于特定客户的表,如国家、州、货币和税率。Neki 允许将这些表声明为引用表,每个分片保存完整副本。路由器将每次插入、更新和删除发送到所有副本以保持同步,这样分片表与引用表之间的连接永远不会离开分片。

Neki 支持哪些分片索引类型?各自有什么特点?

Neki 支持三种分片索引类型:xxhash(推荐,均匀分布到64位键空间)、range(将整数键范围直接路由到分片)和 modulo(将整数键映射到固定数量的桶,但更改模数会移动几乎所有行,不推荐大规模使用)。此外,分片索引还支持 SQL 表达式,如 lower(sku) 或 left(order_id, 4)。

没有分片键的查询(例如按订单 ID 查询)如何处理?

Neki 通过全局二级索引(GSI)支持这种查询。GSI 是一个查找表,将表的一个或多个列映射到该表的分片键。例如,为 orders 表的 id 列创建 GSI,查询 id = 84213 时先读取查找表获得 customer_id,再读取 orders 表获取实际行,总共两次单分片读取。

如何更改表的分片键或分片数量?

可以使用 Neki 的 Reshard 工作流更改表的分片键或分片数量。MoveTables 工作流用于将外部 Postgres 数据库导入 Neki 并在过程中进行分片。这些工作流使得分片组设计不是永久的,可以随着查询演变而调整。

🏷️

标签

➡️

继续阅读