分片数据库系统中为性能而分区
作者:Nga Tran / 产品, 用例
2022年11月18日
导航至
本文最初发表于 InfoWorld,并经许可在此转载。
分区可以为分片系统带来许多好处,包括更快的查询执行速度。让我们看看它是如何工作的。
在之前的文章中,我描述了一个分片系统,用于扩展查询和摄取工作负载的吞吐量和性能。在本文中,我将介绍另一种常用技术——分区,它为分片数据库的性能和管理提供了进一步的优势。我还将介绍如何有效地处理查询和摄取工作负载的分区,以及如何管理冷(旧)分区,其中读取要求与热(最近)分区截然不同。
分片 vs. 分区
分片是在分布式数据库系统中拆分数据的一种方法。每个分片中的数据不必共享 CPU 或内存等资源,并且可以并行读取或写入。
图 1 是一个分片数据库的示例。一个国家 50 个州的销售数据被分成四个分片,每个分片包含 12 或 13 个州的数据。通过为每个分片分配一个查询节点,读取所有 50 个州的作业可以在这四个并行运行的节点之间拆分,并且与单个节点读取所有 50 个州的设置相比,执行速度将提高四倍。有关分片及其对摄取和查询工作负载的扩展影响的更多信息,请参见我之前的文章。
分区是在每个分片内将数据拆分为不重叠分区以进行进一步并行处理的一种方法。这减少了不必要数据的读取,并允许有效地实施数据保留策略。
图 2 中,每个分片的数据按销售日分区。如果我们需要创建 2022 年 5 月 1 日等特定日期的销售报告,则查询节点只需读取其对应的 2022.05.01 分区的数据。
本文的其余部分将重点介绍分区的效果。我们将了解如何有效地管理热数据和冷数据上的查询和摄取工作负载的分区。
分区效果
数据分区的三个最常见的好处是数据修剪、节点内并行性和快速删除。
数据修剪
数据库系统可能包含数年的数据,但大多数查询只需要读取最近的数据(例如,“过去三天下了多少订单?”)。如图 2 所示,将数据分区为不重叠的分区,可以轻松跳过整个超出范围的分区,仅读取和处理相关且非常小的数据集以快速返回结果。
节点内并行性
多线程处理和流式数据在数据库系统中至关重要,可以充分利用可用的 CPU 和内存并获得最佳性能。将数据分区为小分区使实现每个分区执行一个线程的多线程引擎变得更容易。对于每个分区,可以生成更多线程来处理该分区内的数据。了解分区大小和行数等分区统计信息将有助于为特定分区分配最佳数量的 CPU 和内存。
快速数据删除
许多组织只保留最近的数据(例如,最近三个月的数据),并希望尽快删除旧数据。通过在不重叠的时间窗口上对数据进行分区,删除旧分区变得像删除文件一样简单,而无需重新组织数据和中断其他查询或摄取活动。如果必须保留所有数据,则本文后面的部分将介绍如何不同地管理最近和旧数据,以确保系统在所有情况下都提供出色的性能。
存储和管理分区
针对查询工作负载进行优化
一个分区已经包含一小部分数据,因此我们不希望将一个分区存储在许多较小的文件(或内存数据库中的块)中。一个分区应该只包含一个或几个文件。
最大限度地减少分区中的文件数量具有两个重要好处。它既减少了读取数据以执行查询时的 I/O 操作,又提高了数据编码/压缩率。改进编码反过来降低了存储成本,更重要的是,通过减少读取的数据量来提高查询执行速度。
针对摄取工作负载进行优化
简单摄取。 为了将分区的数据保存在文件中以获得上述读取优化的好处,每次摄取一组数据时,都必须对其进行解析并拆分到正确的分区中,然后合并到其对应分区的现有文件中,如图 3 所示。
由于昂贵的 I/O 以及混合和编码分区数据的成本,将新数据与现有数据合并的过程通常需要时间。这将导致客户端收到数据成功摄取的回应以及对新摄取数据的查询的延迟较长,因为它不会立即在存储中可用。
低延迟摄取。 为了保持每次摄取的低延迟,我们可以将该过程分为两个步骤:摄取和压缩。
摄取
在摄取步骤中,摄取的数据被拆分并写入其自己的文件,如图 4 所示。它不会与分区的现有数据合并。一旦摄取的数据成功持久化,摄取客户端将收到成功信号,并且新摄取的文件将可用于查询。
如果摄取率很高,则分区中会累积许多小文件,如图 5 所示。在此阶段,需要从分区获取数据的查询必须读取该分区的所有文件。这当然不利于查询性能。下面描述的压缩步骤将使文件的累积保持在最低限度。
压缩
压缩是将分区的文件合并为一个或几个文件以获得更好的查询性能和压缩率的过程。例如,图 6 显示了分区 2022.05.01 中的所有文件合并为一个文件,以及分区 2022.05.02 中的所有文件合并为两个文件,每个文件都小于 100MB。
关于压缩频率和压缩文件最大大小的决定对于不同的系统会有所不同,但共同目标是通过减少 I/O(即文件数)并使文件足够大以有效压缩来保持高查询性能。
热分区 vs. 冷分区
经常查询的分区被认为是热分区,而很少读取的分区称为冷分区。在数据库中,热分区通常是包含最近数据的分区,例如最近的销售日期。冷分区通常包含较旧的数据,这些数据不太可能被读取。
此外,当数据变旧时,通常会以较大的块(例如按月甚至按年)进行查询。以下是一些明确将数据从热数据分类为冷数据的示例
- 热数据:当前周的数据。
- 较热数据:当前月份但前几周的数据。
- 冷数据:当前年份但前几个月的数据。
- 更冷数据:去年及更早年份的数据。
为了减少热数据和冷数据之间的歧义,我们需要找到两个问题的答案。首先,我们需要量化热数据、较热数据、冷数据、更冷数据,甚至可能更冷和更冷。其次,我们需要考虑在读取冷数据的情况下如何实现更少的 I/O。我们不想读取 365 个文件(每个文件代表一天的数据分区)来获取去年的销售收入。
分层分区
如图 7 所示的分层分区为上述两个问题提供了答案。当前周每一天的数据都存储在其自己的分区中。当前月份前几周的数据按周分区。当前年份前几个月的数据按月分区。更旧的数据按年分区。
可以通过定义活动分区来代替当前日期分区来放宽此模型。活动分区之后到达的所有数据将按日期分区,而活动分区之前的数据将按周、月和年分区。这允许系统根据需要保留尽可能多的小型最近分区。即使本文中的所有示例都按时间对数据进行分区,只要您可以为分区及其层次结构定义表达式,非时间分区也将以类似的方式工作。
分层分区减少了系统中的分区数量,使其更易于管理,并减少了查询较大和较旧的块时需要读取的分区数量。
分层分区的查询过程与非分层分区相同,因为它将应用相同的修剪策略来仅读取相关分区。摄取和压缩过程将稍微复杂一些,因为将分区组织在其定义的层次结构中将更加困难。
聚合分区
许多组织不想保留旧数据,而是更喜欢保留聚合数据,例如每个月每个产品的订单数量和总销售额。这可以通过聚合数据并按月对其进行分区来支持。但是,由于聚合分区存储聚合数据,因此它们的架构将与非聚合分区不同,这将导致摄取和查询的额外工作。有不同的方法来管理这些冷数据和聚合数据,但它们是适合未来帖子的重要主题。