系统设计是大型科技公司软件工程师最重要的几轮面试之一。工程师应该了解很多概念,数据库分片就是其中之一。每当任何应用程序开始接收大量并发请求并且看到网站上的用户显着增长时,它最终都需要扩展以处理网站上不断增加的数据或流量。网站未来的增长很难预测,我们也无法预测一个网站的人气和增长能维持多久。所以我们需要动态扩展我们的数据库,数据库分片是可以完成这项工作的技术。让我们详细了解这个概念。
什么是分片或数据分区?
以比萨为例(是的!!!你最喜欢的食物)。你得到不同切片的比萨饼,然后与朋友分享这些切片。分片也称为数据分区,与共享 Pizza 切片的概念相同。它基本上是一种数据库架构模式,我们将大型数据集拆分为较小的块(逻辑分片),并将这些块存储/分布在不同的机器/数据库节点(物理分片)中。每个组块/分区被称为“碎片”和每个碎片具有相同的数据库模式与原始数据库。我们以每一行恰好出现在一个分片中的方式分布数据。这是提高应用程序可伸缩性的一个很好的机制。
Database shards are autonomous; they don’t share any of the same data or computing resources. In some cases, though, it may make sense to replicate certain tables into each shard to serve as reference tables.
分片的优势
- 解决可扩展性问题:使用单一数据库服务器架构,任何应用程序 当用户开始在该应用程序上增长时体验性能下降。读写查询变慢,网络带宽开始饱和。在某些时候,您将耗尽磁盘空间。数据库分片通过跨多台机器对数据进行分区来解决所有这些问题。
- 高可用性:单服务器架构的一个问题是,如果发生中断,那么整个应用程序将不可用,这对用户数量较多的网站不利。分片数据库不是这种情况。如果分片架构发生中断,那么只有一些特定的分片会宕机。所有其他分片将继续运行,并且整个应用程序不会对用户不可用。
- 加快查询响应时间:当您在具有大型单体数据库且没有分片架构的应用程序中提交查询时,查找结果需要更多时间。它必须搜索表中的每一行,这会减慢您给出的查询的响应时间。这不会发生在分片架构中。在分片数据库中,查询必须通过更少的行,并且您可以在更短的时间内收到响应。
- 更多写入带宽:对于许多应用程序,写入是一个主要瓶颈。没有主数据库序列化写入分片架构允许您并行写入并提高写入吞吐量。
- 向外扩展:分片数据库便于水平缩放,被称为向外扩展。在水平扩展中,您可以在网络中添加更多机器并在这些机器上分配负载以实现更快的处理和响应。这有很多优点。您可以同时完成更多工作,并且可以处理来自用户的大量请求,尤其是在写入数据时,因为系统中存在并行路径。您还可以对通过不同网络路径访问分片的 Web 服务器进行负载平衡,这些分片由不同的 CPU 处理,并使用单独的 RAM 缓存或磁盘 IO 路径来处理工作。
分片的缺点
- 增加系统的复杂性:在应用程序中实现适当的分片数据库架构时需要小心。这是一项复杂的任务,如果没有正确实施,您可能会丢失数据或数据库中的表损坏。您还需要管理来自多个分片位置的数据,而不是从单个入口点管理和访问数据。这可能会影响您团队的工作流程,这可能会对某些团队造成潜在的破坏。
- 重新平衡数据:在分片数据库架构中,有时分片会变得不平衡(当 一个分片超过其他分片)。考虑一个示例,您有一个数据库的两个分片。一个分片存储客户名称以字母 A 到 M 开头。另一个分片存储客户名称以字母 N 到 Z 开头。如果有这么多用户使用字母 L,那么分片将比分片拥有更多数据二。这将影响应用程序的性能(变慢),并且会拖延您的大部分用户。 AM 分片将变得不平衡,它将被称为数据库热点。为了克服这个问题并重新平衡数据,您需要为均匀的数据分布进行重新分片。将数据从一个分片移动到另一个分片并不是一个好主意,因为它需要大量的停机时间。
- 连接来自多个分片的数据成本高昂:在单个数据库中,可以轻松执行连接以实现任何功能。但是在分片架构中,您需要从不同的分片中提取数据,并且需要跨多个联网的服务器执行连接。您无法提交单个查询来从各个分片中获取数据。您需要为每个分片提交多个查询,提取数据,并通过网络连接数据。这将是一个非常昂贵和耗时的过程。它会增加系统的延迟。
- 无本机支持:并非每个数据库引擎都本机支持分片。例如,PostgreSQL 不包括自动分片功能,因此您必须进行手动分片。您需要遵循“自己动手”的方法。在执行分片过程中,您将很难找到有关分片的提示或文档并进行故障排除。
分片架构
1. 基于密钥的分片
这种技术也称为基于哈希的分片。在这里,我们采用实体的值,例如客户 ID、客户电子邮件、客户的 IP 地址、邮政编码等,并将此值用作哈希函数的输入。此过程会生成一个哈希值,用于确定我们需要使用哪个分片来存储数据。我们需要记住,输入散列函数的值应该都来自同一列(分片键),以确保数据以正确的顺序和一致的方式放置。基本上,分片键的作用类似于主键或单个行的唯一标识符。
考虑一个示例,您有 3 个数据库服务器,每个请求都有一个应用程序 ID,每次注册新应用程序时该 ID 递增 1。为了确定应该将数据放在哪个服务器上,我们对这些应用程序 id 的数字为 3 执行模运算。然后余数用于标识服务器来存储我们的数据。
这种方法的缺点是弹性负载平衡,这意味着如果您尝试动态添加或删除数据库服务器,这将是一个困难且昂贵的过程。例如,在上面的一个中,如果您要再添加 5 个服务器,那么您需要为附加条目添加更多相应的哈希值。此外,大多数现有密钥需要重新映射到它们新的、正确的哈希值,然后迁移到新服务器。散列函数需要从模 3 更改为模 8。当数据迁移有效时,新旧散列函数都将无效。在迁移期间,您的应用程序将无法为大量请求提供服务,并且在迁移完成之前,您的应用程序将遇到停机时间。
注意:分片不应包含可能随时间变化的值。它应该始终是静态的,否则会降低性能。
2. 水平或基于范围的分片
在这种方法中,我们根据每个实体固有的给定值的范围拆分数据。假设您有一个在线客户姓名和电子邮件信息的数据库。您可以将此信息拆分为两个分片。在一个分片中,您可以保留名字以 AP 开头的客户的信息,在另一个分片中,保留其余客户的信息。
基于范围的分片是最简单的分片方法。每个分片保存一组不同的数据,但它们都具有与原始数据库相同的架构。在这种方法中,您只需要识别您的数据属于哪个范围,然后您就可以将条目存储到相应的分片中。此方法最适合存储非静态数据(例如:存储大学学生的联系信息。)
这种方法的缺点是数据可能不会均匀地分布在分片上。在上面的示例中,您可能有很多名称属于 AP 类别的客户。在这种情况下,第一个分片将不得不比第二个分片承担更多的负载,这可能会成为系统瓶颈。
3. 垂直分片
在这种方法中,我们从表中拆分整个列,并将这些列放入新的不同表中。数据完全独立于一个分区到另一个分区。此外,每个分区都包含不同的行和列。以 Twitter 功能为例。我们可以在不同机器上的不同分片中拆分实体的不同特征。在 Twitter 上,用户可能有个人资料、关注者数量和他/她自己发布的一些推文。我们可以将用户配置文件放在一个分片上,将关注者放在第二个分片上,将推文放在第三个分片上。
在这种方法中,您可以单独分离和处理数据的关键部分(例如用户配置文件)和非关键部分(例如博客文章),并围绕它构建不同的复制和一致性模型。这是这种方法的主要优点之一。
这种方案的主要缺点是,要回答一些查询,您可能必须组合来自不同分片的数据,这会不必要地增加系统的开发和操作复杂性。此外,如果您的应用程序稍后会增长并且您在其中添加更多功能,那么您将不得不在多个服务器之间进一步分片特定于功能的数据库。
4. 基于目录的分片
在这种方法中,我们为原始数据库创建和维护查找服务或查找表。基本上,我们使用分片键来查找表,并为数据库中存在的每个实体进行映射。通过这种方式,我们可以跟踪哪些数据库分片保存了哪些数据。
查找表包含一组关于可以找到特定数据的静态信息。在上图中,您可以看到我们将交付区域用作分片键。首先,客户端应用程序查询查找服务以找出放置数据的分片(数据库分区)。当查找服务返回分片时,它会查询/更新该分片。
基于目录的分片比基于范围和基于键的分片灵活得多。在基于范围的分片中,您必须指定值的范围。在基于键的情况下,您必须使用固定的哈希函数,以后很难更改。在这种方法中,您可以自由使用要分配给分片的数据条目的任何算法。此外,在这种方法中动态添加分片很容易。
这种方法的主要缺点是查找表的单点故障。如果它将被损坏或失败,那么它将影响写入新数据或访问表中的现有数据。
结论
当您的应用程序的单个数据库无法处理/存储大量增长的数据时,分片是一个很好的解决方案。分片有助于扩展数据库并提高应用程序的性能。但是,它也给您的系统增加了一些复杂性。上述方法和架构已经清楚地展示了每种分片技术的优缺点。因此,在您决定选择任何分片方法之前,请确保比较每一种方法,并根据存储在数据库中的信息类型,选择分片或任何一种分片技术。
从链接阅读有关系统设计的更多信息如何在面试中破解系统设计回合?