Dec 10, 2024 No Comments 理解数据库分片 ## 介绍 任何应用程序或网站,如果出现大幅增长,最终都需要进行扩展,以适应流量的增加。对于数据驱动型应用程序和网站来说,在进行扩展时必须确保数据的安全性和完整性。很难预测一个网站或应用程序会变得多受欢迎,或者它的受欢迎程度会维持多久,这就是为什么一些组织会选择一种允许他们动态扩展数据库的数据库架构。 在这篇概念性文章中,我们将讨论这样一种数据库架构:分片数据库。近年来,分片数据库受到了广泛关注,但很多人并不清楚什么是分片数据库,也不知道在哪些情况下分片数据库才有意义。我们将介绍什么是分片、分片的一些主要优点和缺点,以及几种常见的分片方法。 ## 什么是分片? 分片是一种与水平分区相关的数据库架构模式,即把一个表的行分成多个不同的表,称为分区。每个分区都有相同的模式和列,但也有完全不同的行。同样,每个分区中的数据都是唯一的,与其他分区中的数据无关。 从水平分区与垂直分区的关系角度来思考水平分区可能会有所帮助。在垂直分区表中,整个列都被分离出来并放入新的、不同的表中。一个垂直分区中的数据独立于所有其他分区中的数据,每个分区都有不同的行和列。下图说明了如何对表格进行水平和垂直分区: ![水平分区与垂直分区](https://www.diguage.com/images/databases/sharding-1.png) 图 1. 水平分区与垂直分区 分片是指将数据分割成两个或多个较小的块,称为逻辑分片。然后,逻辑分片分布在不同的数据库节点上,称为物理分片,物理分片可容纳多个逻辑分片。尽管如此,所有分片中保存的数据共同代表了一个完整的逻辑数据集。 数据库分片是无共享架构的典范。这意味着分片是独立的,它们不共享任何相同的数据或计算资源。不过,在某些情况下,将某些表复制到每个分片中作为参考表是有意义的。例如,假设有一个应用程序的数据库依赖于重量测量的固定转换率。通过将包含必要转换率数据的表复制到每个分片中,有助于确保每个分片中都包含查询所需的所有数据。 通常,分片是在应用程序级实现的,这意味着应用程序包含定义向哪个分片传输读写的代码。不过,有些数据库管理系统内置了分片功能,允许你直接在数据库级实施分片。 鉴于以上对分片的概述,让我们来看看这种数据库架构的一些优点和缺点。 ## 分片的优点 对数据库进行分片的主要吸引力在于,它有助于促进水平扩展,也称为向外扩展,横向扩展。水平扩展是指在现有堆栈中添加更多机器,以分散负载,允许更多流量和更快处理。这通常与垂直扩展(也称向上扩展)形成对比,后者涉及升级现有服务器的硬件,通常是增加更多内存或 CPU。 在一台机器上运行一个关系数据库,并根据需要通过升级其计算资源来扩大其规模相对简单。但归根结底,任何非分布式数据库在存储和计算能力方面都是有限的,因此可以自由横向扩展,会让你的设置更加灵活。 一些人选择分片数据库架构的另一个原因是为了加快查询响应速度。在未分片的数据库上提交查询时,数据库可能需要搜索查询表中的每一行,然后才能找到所需的结果集。对于使用大型单体数据库的应用程序来说,查询速度会慢得令人望而却步。不过,通过将一个表分片成多个表后,查询需要处理的行数就会减少,返回结果集的速度也会快得多。 分片还可以减轻中断造成的影响,从而提高应用程序的可靠性。如果您的应用程序或网站依赖的是未分片的数据库,中断有可能导致整个应用程序不可用。 而使用分片数据库时,故障可能只影响单个分片。尽管这可能会导致部分用户无法使用应用程序或网站的某些部分,但总体影响仍小于整个数据库崩溃的影响。 ## 分片的缺点 虽然分片可以使数据库的扩展更容易并提高性能,但它也会带来一些限制。在此,我们将讨论其中的一些限制,以及为什么要避免使用分片。 人们在使用分片时遇到的第一个困难是正确实施分片数据库架构的复杂性。如果操作不当,分片过程很有可能导致数据丢失或表损坏。即使操作正确,分片也可能对团队的工作流程产生重大影响。用户必须跨多个分片位置管理数据,而不是从一个入口点访问和管理数据,这可能会对某些团队造成干扰。 用户在对数据库进行分片后有时会遇到一个问题,那就是分片最终会变得不平衡。举例来说,假设你的数据库有两个独立的分片,一个用于存储姓氏以字母 A 至 M 开头的客户,另一个用于存储姓氏以字母 N 至 Z 开头的客户。然而,你的应用程序为大量姓氏以字母 G 开头的人提供服务。 A-M 分区已成为所谓的数据库热点。在这种情况下,分片给数据库带来的任何好处都会被速度变慢和崩溃所抵消。数据库很可能需要修复和重新分片,以使数据分布更均匀。 另一个主要缺点是,一旦数据库被分片,就很难将其恢复到未分片的架构。数据库分片前的任何备份都不包括分片后写入的数据。 因此,要重建未分片的原始架构,就需要将新的分片数据与旧的备份合并,或者将分片后的数据库变回单一数据库,这两种方法都会耗费大量成本和时间。 最后一个需要考虑的缺点是,并非每个数据库引擎都支持分片。例如,PostgreSQL 不包括自动分片功能,但可以手动分片 PostgreSQL 数据库。 有一些 Postgres 变种确实包含自动分片功能,但它们往往落后于最新的 PostgreSQL 版本,而且缺乏某些其他功能。一些专门的数据库技术(如 MySQL Cluster 或某些数据库即服务产品(如 MongoDB Atlas))确实包含自动分片功能,但这些数据库管理系统的普通版本并不包含。因此,分片通常需要“自己开发”。这意味着通常很难找到分片文档或故障排除技巧。 当然,这些只是分片前需要考虑的一些一般性问题。根据其用例,对数据库进行分片可能会有更多潜在的缺点。 现在,我们已经介绍了分片的一些缺点和优点,下面将介绍几种不同的分片数据库架构。 ## 分片架构 一旦决定对数据库进行分片,接下来需要考虑的就是如何分片。在运行查询或将输入数据分发到分片表或数据库时,将数据分发到正确的分片至关重要。否则,可能会导致数据丢失或查询缓慢。在本节中,我们将介绍几种常见的分片架构,每种架构都使用略有不同的流程在分片间分发数据。 ### 基于键的分片 基于密钥的分片,也称为基于散列的分片,涉及使用从新写入的数据中提取的值,例如客户的 ID 编号、客户端应用程序的 IP 地址、邮政编码等并将其输入散列函数,以确定数据应进入哪个分片。散列函数是一种输入数据(如客户电子邮件)并输出离散值(即散列值)的函数。在分片的情况下,散列值是一个分片 ID,用于确定输入的数据将存储在哪个分片上。整个过程如下: ![基于键的分片](https://www.diguage.com/images/databases/sharding-2.png) 图 2. 基于键的分片 为确保条目以一致的方式放置于正确的分片,输入散列函数的值都应来自同一列。此列被称为分片键。简单来说,分片键与主键类似,都是用于为单个行建立唯一标识符的列。从广义上讲,分片键应该是静态的,也就是说,它不应该包含可能会随时间变化的值。否则,会增加更新操作的工作量,并可能降低性能。 虽然基于键的分片是一种相当常见的分片架构,但在试图动态添加或删除数据库中的其他服务器时,它可能会让事情变得棘手。在添加服务器时,每个服务器都需要一个相应的散列值,许多现有条目(如果不是全部的话)都需要重新映射到新的、正确的散列值,然后迁移到相应的服务器上。在开始重新平衡数据时,新旧散列函数都将失效。因此,在迁移过程中,您的服务器将无法写入任何新数据,您的应用程序可能会出现停机。 这种策略的主要吸引力在于,它可用于均匀分布数据,以防止出现热点。此外,由于它是通过算法来分配数据的,因此无需维护所有数据的位置地图,而基于范围或目录的分片等其他策略则需要这样做。 ### 基于范围的分片 基于范围的分片是指根据给定值的范围对数据进行分片。举例说明,假设您有一个数据库,其中存储了零售商目录中所有产品的信息。您可以创建几个不同的分片,并根据每个产品的价格范围来划分它们的信息,如下所示: ![基于范围的分片](https://www.diguage.com/images/databases/sharding-3.png) 图 3. 基于范围的分片 基于范围的分片的主要优点是实施起来相对简单。每个分片都保存着不同的数据集,但它们的模式以及原始数据库的模式都完全相同。应用程序代码读取数据属于哪个范围,并将其写入相应的分片。 另一方面,基于范围的分片并不能防止数据分布不均,从而导致上述数据库热点问题。从示例图来看,即使每个分区都容纳相同数量的数据,特定产品也会比其他产品受到更多关注。反过来,它们各自的分片也会获得不成比例的读取次数。 ## 基于目录的分片 要实现基于目录的分片,必须创建并维护一个查询表,该表使用分片键来跟踪哪个分片保存哪个数据。查找表是一个保存特定数据静态信息集的表,这些信息是关于可以在哪里找到特定数据的信息。下图展示了一个基于目录的分片的简单示例: ![基于目录的分片](https://www.diguage.com/images/databases/sharding-4.png) 图 4. 基于目录的分片 在这里,`Delivery Zone` 列被定义为分区键。分片键的数据与每行应写入的分片一起写入查找表。这与基于范围的分片类似,但每个键都绑定到自己的特定分片,而不是确定分片键数据属于哪个范围。与基于范围的分片相比,基于目录的分片是一种不错的选择,因为如果分片密钥的卡入度较低,也就是可能的值较少,那么分片存储一系列密钥就没有意义了。需要注意的是,它与基于密钥的分片也有区别,因为它不通过散列函数处理分片密钥;它只是根据查找表检查密钥,以确定需要写入数据的位置。 基于目录的分片的主要吸引力在于它的灵活性。基于范围的分片架构只能指定值的范围,而基于键的分片架构只能使用固定的散列函数,如前所述,这种散列函数很难在日后更改。另一方面,基于目录的分片允许你使用任何系统或算法将数据条目分配给分片,而且使用这种方法动态添加分片也相对容易。 虽然基于目录的分片是本文讨论的分片方法中最灵活的一种,但每次查询或写入之前都需要连接到查找表会对应用程序的性能产生不利影响。此外,查找表还可能成为单点故障:如果查找表损坏或出现其他故障,就会影响用户写入新数据或访问现有数据的能力。 ## 应该分片吗? 是否应该实施分片数据库架构几乎总是一个争论不休的问题。一些人认为分片是数据库达到一定规模后的必然结果,而另一些人则认为分片会增加操作复杂性,因此除非绝对必要,否则应避免分片。 由于这种复杂性的增加,通常只有在处理非常大量的数据时才会进行分片。以下是一些常见的场景,在这些场景中,对数据库进行分片可能是有益的: + 应用程序数据量的增长超出了单个数据库节点的存储容量。 + 对数据库的写入或读取量超出了单个节点或其读取副本所能处理的范围,导致响应时间变慢或超时。 + 应用程序所需的网络带宽超出了单个数据库节点和任何读取副本的可用带宽,导致响应时间变慢或超时。 在分片之前,您应该用尽所有其他优化数据库的方法。可能需要考虑的一些优化方法包括: + **建立远程数据库。**如果您使用的是单体应用程序,其所有组件都位于同一台服务器上,则可以将数据库转移到专门的机器上,从而提高数据库的性能。这不会像分片那样增加复杂性,因为数据库的表保持不变。不过,它仍然可以让你的数据库与基础架构的其他部分分开进行垂直扩展。 + **实施缓存。**如果应用程序的读取性能给您带来了麻烦,那么缓存就是一种可以帮助改善读取性能的策略。缓存是指将已请求的数据暂时存储在内存中,以便以后更快地访问这些数据。 + **创建一个或多个读取副本。**另一种有助于提高读取性能的策略是将数据从一台数据库服务器(主服务器)复制到一台或多台从服务器上。这样,每一次新的写入都会先写入主服务器,然后再复制到从服务器,而读取则只在从服务器上进行。这样分配读取和写入,可以避免任何一台机器承担过多的负载,从而有助于防止速度变慢和崩溃。需要注意的是,创建读副本需要更多的计算资源,因此成本更高,这对某些人来说可能是一个很大的限制。 + **升级到更大的服务器。**在大多数情况下,将数据库服务器升级到拥有更多资源的机器比分片更省事。与创建读副本一样,升级到资源更多的服务器可能需要花费更多的钱。因此,只有当调整服务器大小确实是最佳选择时,您才应该这样做。 请记住,如果您的应用程序或网站发展到一定程度,这些策略都不足以单独提高性能。在这种情况下,分片可能确实是最好的选择。 ## 总结 对于那些希望横向扩展数据库的人来说,分片是一个很好的解决方案。不过,它也会增加大量复杂性,并为应用程序带来更多潜在故障点。对于某些人来说,分片可能是必要的,但对于其他人来说,创建和维护分片架构所需的时间和资源可能会超过它带来的好处。 通过阅读这篇概念性文章,您应该对分片的利弊有了更清晰的认识。在今后的工作中,您可以利用这些见解,就分片数据库架构是否适合您的应用程序做出更明智的决定。 最后更新于 2024-12-10 21:39:40 并被添加「数据库 分片」标签,已有 185 位童鞋阅读过。 本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
此处评论已关闭