数据库分片解释


您的应用正在变得越来越好。它有更多的功能,更多的活跃用户,并且每天收集更多的数据。您的数据库现在导致应用程序的其余部分变慢。数据库分片可能是您问题的答案,但许多人不知道它是什么,最重要的是,不知道何时使用它。在本文中,我们将讨论什么是数据库分片、它是如何工作的以及使用它的最佳方式。

在我们进入这个问题之前,有必要了解为什么我们要对数据存储进行分片,以及在开始分片之前您有哪些选择。

当表达到特定大小时,人们通常会觉得分片是解决所有扩展问题的神奇方法。然而,我有数十亿行的表,并且没有看到一个令人信服的理由进行分片,因为我的使用模式很适合单个表并且没有看到任何强有力的理由(除了管理这么大的表,它在某些情况下是足够的理由)对表进行分片。

什么是分片数据库?
简单地说,分片是一种跨多台机器分布数据的方法。当没有一台机器可以处理预期的工作负载时,分片变得特别方便。
分片是水平扩展的一个例子,而垂直扩展是一个越来越大的机器来支持新工作负载的例子。

工程师们经常陷入以最复杂的方式做事,但随着应用程序的发展,尽早保持简单会使以后具有挑战性的事情变得容易得多。因此,如果通过获得具有更多资源的机器来解决您的问题,9/10,这是正确的答案。

现在我们已经讨论了潜在的服务器架构,让我们谈谈数据布局。

您还可以通过几种方式对数据进行分区并将特定表移动到它们的数据库中,这与您在微服务架构中看到的非常相似,其中应用程序的特定方面有其数据库服务器。该应用程序知道在哪里寻找每个。或者,您可以跨多个数据库节点存储同一个表的行,这带来了分片键等想法;稍后会详细介绍。


更现代的数据库,如 Cassandra 和其他数据库,将其从应用程序逻辑中抽象出来,并在数据库级别进行维护。

分片前我有哪些选择?
与任何分布式架构一样,数据库分片也需要花钱。设置分片、使每个分片上的数据保持最新以及确保将请求发送到正确的分片既费时又复杂。在开始分片之前,您可能想看看这些其他选项之一是否适合您。

选项 1:什么都不做。
我被问到分片是否是一个好主意的次数,没有任何明显的瓶颈或限制因素,比如用完可以支持工作负载的硬件。如果它没有损坏,请不要修理它。

选项 2:垂直缩放
在获得具有更多资源的机器、添加额外的 RAM、为计算繁重的工作负载添加更多 CPU 内核以及添加额外的存储之前,我们已经避开了这一点。这些都是不需要重新设计应用程序和数据库架构的选项。其他最终限制,例如带宽(网络或系统内部),也会迫使您进行分片。

选项 3:复制
如果您对数据所做的大部分工作是读取数据,复制可以提高数据的可用性并加快读取数据的速度。这可以帮助您避免数据库分片的一些复杂性。可以通过制作更多数据库副本来提高读取性能。当然,假设您已经补充了缓存。这可以通过负载平衡或根据他们在世界上的位置路由查询来完成。但是复制使得写入繁重的工作负载更难处理,因为每次写入都必须复制到每个节点。这可能因数据存储而异,其中一些是异步执行的,而另一些可能会延迟初始写入以确保其被复制。


WAL
WAL(预写日志)是磁盘上的一种额外结构,只能添加到其中。在将更改写入数据库之前,它们首先写入日志,此日志必须在持久存储上。它用于从崩溃和丢失的事务中恢复。此日志还用于支持某些数据库(如 PostgreSQL 和 MySQL)中的复制。

选项 4:专业数据库
性能不佳是由需要针对其服务的工作负载更好地设计的数据库引起的。例如,将搜索数据存储在关系数据存储中可能意义不大。将类似的东西移到 Elasticsearch 会更有效。将 blob 移动到像 S3 这样的对象存储可能是一个相当大的胜利,而不是将它们存储在你的关系存储中。外包此功能可能比尝试对整个数据库进行分片更有意义。

如果您的应用程序数据库管理大量数据,需要大量读写,和/或需要始终可用,则分片数据库可能是最佳选择。让我们来看看分片的优缺点。

必要时分片
分片可以在增加的系统吞吐量、存储容量和可用性方面为您提供几乎无限的可扩展性。有许多更小、更容易控制的系统,每个系统都可以通过各自的副本自行扩展和缩减。

所有这些优势都与操作复杂性、应用程序开销和支持这种新设计的基础设施成本进行了权衡。

它是如何工作的?
在我们可以分片数据库之前,我们需要回答几个重要问题。您的计划将取决于您如何回答这些问题。

  1. 我们如何跨分片分布数据?如果数据分布不均,是否存在潜在热点?
  2. 我们运行什么查询以及表如何交互?
  3. 数据将如何增长?以后需要如何重新分配?

热点
术语热点是指节点的工作负载已超过特定资源(内存、io 等)的阈值。有一个有趣的例子叫做Bieber Bug。
在我们进入下一点之前,理解以下术语很重要。

Shard Key是主键的一部分,它告诉我们数据应该如何分布。使用分片键,您可以通过将操作路由到正确的数据库来快速查找和更改数据。
同一节点包含具有相同分片键的条目。共享相同分片键的一组数据称为逻辑分片。一个数据库节点包含多个逻辑分片,也称为物理分片。

最关键的推定也是未来最难改变的推定。逻辑分片只能跨越一个节点,因为它是一个原子存储单元。在分片对于单个节点来说太大的情况下,数据库集群实际上空间不足。

基于键的分片
算法分片数据库使用哈希函数来定位数据。这允许我们给定一个特定的分片键来找到正确的物理分片来请求数据。

数据仅通过散列函数进行分发。它不考虑有效负载的大小或空间使用情况。散列的好处是在没有合适的分区键时可以实现更均匀的分布,并且如果您有合适的分区键,则可以即时计算位置。


这种分片策略的缺点是重新分片数据可能很困难,并且在可用的同时保持一致性更难。

基于范围的分片
在基于范围的分片中,根据某个值的范围将数据分成块。

这需要一个查找表来查看数据应该存储在哪里。保持此类表格的一致性并显然在此处选择范围至关重要。

在为这种分片类型选择分片键时,必须选择一个具有高基数的分片键,因此该键的可能值的数量很多。例如,可能值为 North、South、East 和 West 的键的基数较低,因为只有 4 个。此外,理想情况下,您希望在该基数内有良好的分布。

如果一切都落在 50% 的可能值中,您的一些分片将开始出现热点。使用准确的数据将其作为实验运行很容易,只需几行代码即可完成。首先,选择一个键和范围并检查潜在分布。

基于关系的分片
这种共享机制将相关数据保存在一个物理分片上。例如,相关数据通常分布在关系数据库中的多个表中。

例如,对于像 Instagram 这样的应用程序,用户和所有相关数据将被分片到同一个物理节点,其中分别包含帖子和评论。通过将相关实体放在同一个分区中,您可以从单个分区中获得更多收益。因此,在整个物理分片和更少的跨物理分片查询中保持更强的一致性。

跨分片交易
最后,我想总结一些复杂性的细节,当您需要进行跨多个分片的交易时,这些复杂性可能会引入。无论您计划多少,足够长寿命的服务或应用程序最终都会遇到一些跨分片交易。

这实质上意味着您需要由 ACID 兼容数据库提供的事务保证,但跨分片时数据库不能确保这种合规性,因为您操作的数据不在启动它的事务范围内。

这通常被称为全局事务,其中多个子事务需要协调并成功。作为一般规则,事务打开的时间越长,争用就越多,并且可能会发生故障。

两阶段提交
两阶段提交在理论上很简单,但在实践中很难执行。

  • Leader 写入一个持久的事务记录,指示跨分片事务。
  • 参与者写下他们愿意承诺的永久记录并通知领导者。
  • 领导者在收到所有响应后通过更新持久事务记录来提交事务。(如果没有人响应,它可以中止交易。)
  • 参与者可以在领导者宣布提交决定后显示新状态。(如果领导者中止交易,他们会删除暂存状态。)协议路径中的读写放大是一个主要问题。写入放大的发生是因为您必须写入事务记录并持久地进行提交,这需要每个参与者至少进行一次写入。过多的写入可能会导致锁争用和应用程序不稳定。数据库必须额外过滤每次读取,以确保它看不到任何依赖于挂起的跨分片事务的状态,这会影响系统中的所有读取,甚至是非事务性读取。

结论
我们已经讨论了分片、何时使用它以及如何设置它。对于需要管理大量数据并使其随时可用于大量读写的应用程序,分片是一种出色的解决方案。尽管如此,它还是使操作变得更加复杂。在开始实施之前,您应该考虑收益是否值得付出代价,或者是否有更直接的解决方案。