什么是分片?

分片是一种通过将数据库的数据分区存储在多个服务器上而非单一大型服务器上的扩展策略。每个数据分区被称为一个分片。如果将数据库拆分成多个分片,可以帮助减少数据库上的负载,从而提高性能。
本文将帮助你深入了解什么是数据库分片,通过解释它的工作原理、如何实现你自己的分片数据库,以及一些有用的工具(特别是针对 MySQL 和 Postgres 的工具)。


用分片扩展关系型数据库

场景:你刚刚在本季度第三次扩容你的 MySQL RDS 实例了,而你的 CFO 刚在日程表上给你安排了 30 分钟的会面,内容为“聊聊预算”。或许是时候考虑扩展而不是扩容了!虽然 RDS 的读取副本看起来足够简单,但读取数据仅仅是问题的一半。开发者陷入瓶颈怎么办?
分片——很可能源于电子游戏领域的术语——是扩展关系型数据库的一种方法。你可能已经见过类似表格,展示分片如何帮助你将单个服务器上存储的用户表:

user_idfirst_namelast_nameemail
ZpaDr20TTD4ZL7WmaPeterGibbonspeter@initech.net
bI32htQ1PsEQioC7GBillLumberghbill@initech.net
99J3x257SGP7J4IkFMiltonWaddamsstapler@initech.net
0SH0pyi9bO5RM4I03Lawrence
two@onetime.com

转变成分布在两个(或 1,000 个)服务器上的用户表:

user_idfirst_namelast_nameemailServer
ZpaDr20TTD4ZL7WmaPeterGibbonspeter@initech.netServer A
bI32htQ1PsEQioC7GBillLumberghbill@initech.netServer B
99J3x257SGP7J4IkFMiltonWaddamsstapler@initech.netServer B
0SH0pyi9bO5RM4I03Lawrence
two@onetime.comServer A

但这仅是一种分片类型(行级或水平分片)。还有许多不同的方法可以根据业务和数据模型的需求将数据拆分到多个服务器上以最佳匹配。例如,垂直分片 是指在架构或表级别对数据进行拆分。
分区(Partitioning)作为提升查询速度的机制,尤其是在 OLAP 设置中,已经存在很长时间。分片继承了这一概念并将其应用于分布式系统:除了将数据拆分成逻辑组,还将这些组分布到多个相互通信的服务器上,就连 Oracle 也那么做!
关系型数据库自诞生以来就设计为运行在单一服务器上。由于这一点,以及物理定律的限制,要正确地实现分片并不容易。


数据库分片的工作原理

为了对数据库进行分片,你需要执行以下操作:

  • 决定分片方案:哪些数据需要拆分?如何组织?
  • 配置目标基础设施:你需要分片到多少台服务器?每台服务器上将存储多少数据?
  • 创建路由层:你的应用程序如何知道在哪里存储新数据以及查询现有数据?
  • 规划和执行迁移:如何以最小化停机时间的方式从单数据库迁移到多个数据库?

没有固定的执行方案;每个公司的数据模型和业务约束都不同。以下将逐步深入分析。


分片方案和算法

如何决定将数据拆分为多个分片,也称为分区策略,应直接反映你的业务运行模式以及查询负载的集中区域。对于一个 B2B SaaS 公司来说,其中每位用户都属于一个组织层级,分片时拆分组织级的数据可能很合理。如果是消费者应用公司,则可能基于随机哈希值进行分片更适合。Notion 手动对其 Postgres 数据库进行分片,只是简单地在 Team ID 上拆分。这意味着分片可以非常简单,也可以很复杂,取决于如何设计。
以下是几种常见的分片算法,用来决定哪些行存储在一起以及在哪些服务器:

  • 基于哈希的分片(Hash-based Sharding):从行中取一个值,将其哈希,并将哈希桶发送到同一服务器。选择的哈希列即是你的分片键。
  • 基于范围的分片(Range-based Sharding):选择一列,创建范围,并根据这些范围分配分片。对于某种程度上随机或均匀分布的数值列,这是最有用的。
  • 基于目录的分片(Directory-based Sharding):选择一列,手动分配分片,并维护一个查找表以确定每行存储的位置。

如果你的分片方案不是随机的(例如基于哈希),你会发现对查询负载分析和理解负载分布非常有用。
比如 Amazon,如果需要对存储客户订单的 MySQL 数据库进行分片。表面上似乎没有明显的聚类特性:尽管一些客户订单量大,但这些订单的读操作和关联的负载基本上是随机的。因此,使用基于哈希的分片可能更合理,选择订单 ID 作为分片键。
分片方案的重要组成部分之一是考虑哪些表需要存储在一起。跨分布式系统中不同数据库的 JOIN 操作非常困难且成本高昂,因此理想情况下回答特定查询所需的所有数据都应该存储在同一物理机器上。对于 Amazon 的示例,这意味着 orders 表和包含 orders 表中产品信息的 products 表需要物理上共置。这还需要增量维护:如果客户提交新订单,该订单的产品数据需要包含到新分片中以便之后快速读取。
分片维护是扩展关系型数据库时容易被低估的部分。根据分区策略,你可能会遇到热点问题,即集群中某台服务器存储了过多数据或处理了过多请求。在 Amazon 的示例中,可能会因为一家大型企业开始大量订购商品,导致所有数据都汇集到一台服务器。管理这些热点问题、重新分配数据和负载,以及重新定义分区策略以防止未来出现问题,是分片过程中不可避免的一环。


决定使用哪些服务器

分片方案确定后,接下来需要决定存储数据的服务器数量以及每台机器的大小。这里没有固定公式;这一决定取决于你的预算、数据库负载的未来预测、云提供商等因素。
一种常见的方式是最大限度地提高灵活性。可以从少量主机开始,随着需要添加更多主机。为了在扩展时在服务器之间保持分片的均匀分布,每次增加主机都需要重新平衡。这也就是为什么公司倾向于选择分片数量尽量可被较多较小的数字整除,以实现逐步扩展服务器时保持平滑、均匀分布。


将分片查询路由到正确的数据库

当你的数据分布到多个数据库(假设是 20 个数据库)时,你的应用程序如何知道查询哪一个?必须构建某种路由层来决定。但如何构建?
对于从头构建分片的开发者来说,最常见的答案在应用层里。你需要将逻辑写入应用程序代码中,根据查询中的数据以及分片方案决定连接哪一个数据库(以及架构)。逻辑可能类似于:

if data.sharding_key in database_1.sharding_keys:
    connect_to_database_1()
elif data.sharding_key in database_2.sharding_keys:
    connect_to_database_2()

根据数据分片的方式及物理机器/数据库数量,这些逻辑可以相对简单,比如存储在 JSON 文件、配置文件中等。更常见的是,团队会使用某种键值存储或者数据库中的查找表。关键是要将数据与其目标目的地的关联信息编码到某处,使你的应用程序知道查询的地址。
首次构建路由层实际上并不困难;长时间运行的操作性维护问题才是难点。如果你需要在数据库之间移动分片、重新平衡、添加新的机器、移除机器、更改数据库属性……那么你需要更新应用逻辑以适应这些变化。虽然 ProxySQL 并不是完整的解决方案,但它可以被归类为粗略的“分片路由”服务。


规划和执行迁移到分片解决方案

完成以上步骤之后,你已经拥有运行中且空的数据库服务器,应用逻辑中的路由计划,现在面临的就是如何迁移而尽量减少停机时间这一传统难题。与单一新数据库提供商的潜在更简单迁移相比,迁移到分片解决方案带来了更多可能出错的地方。
Notion 的工程团队建议了一种实用的迁移框架,他们详细介绍了如何实现分片:

  • 双写(Double-write):将新写入同时应用到旧数据库和新数据库。
  • 回填(Backfill):在开始双写之后,将旧数据迁移到新数据库。
  • 验证(Verification):确保新数据库中的数据完整性。
  • 切换(Switch-over):实际切换到新数据库。这可以逐步完成,例如开启双读操作,然后迁移所有读操作。

虽然每一步都会带来潜在停机的风险,但这是这种规模的变更必须付出的代价。


分片框架和工具

尽管许多团队确实从头开始为他们的数据库构建分片,有一些工具生态系统可以加速这一过程——尽管它们可能比它们所基于的数据库软件本身还不那么成熟。

Vitess

Vitess 是 YouTube 在需要为 MySQL 分片时构建的,现在已对外开源。它基本上是 MySQL 之上的一个层,提供分片以及许多与大型工作负载相关的功能:连接池、动态分片和平衡、监控工具等。关于 Vitess 如何改进原生 MySQL 的技术概述,可以参考他们的比较文档。
目前而言,Vitess 是最成熟且最流行的关系型数据库开源分片层。它为 YouTube 处理了多年的数据库流量,并已在 Slack、GitHub、NewRelic、Pinterest、Square 等公司投入生产使用。

Citus

Citus 是 Vitess 在 Postgres 上的对应版本。它开放源代码,设计为 Postgres 扩展,可以运行在单节点或多节点部署中。它已在 Algolia、Heap、Cisco 和其他几家公司投入生产使用。它的文档提供了不少关于选择分片策略的通用建议(无论是否使用 Citus)。
如果你对 NVMe 支持的超快实例感兴趣但不需要分片,可以查看 PlanetScale 对 Postgres 的支持。

无服务器数据库浪潮

更根本的疑问可能是:为什么不使用本身支持分片的数据库?过去几年里,所谓“无服务器”(Serverless)数据库赢得了更多关注。从著名的 Spanner 论文开始,许多人一直在思考运行分布式系统是否应该原生存在于数据库中,其中最突出的例子是 CockroachDB。你甚至可以在 GCP 上运行 Spanner 云服务。
你正在 PlanetScale 的网站上阅读这篇博客。他们提供基于 MySQL 和 Vitess 的原生分片数据库。我并不是 PlanetScale 的员工,但我对他们所做的事情表示充分支持,尤其是他们将数据库的重点从基础设施维护转移到开发者体验上这一点。
问题开始转变为:如果你已经付费给 AWS 等公司运行你的数据库,为什么还要忙于研究如何扩展数据库?我认为这是主要云提供商应该问自己的一个值得思考的问题。



什么是数据库分片及其工作原理插图

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://choupangxia.com/2025/09/13/sharding-and-how-does-it-work/