在分片数据库系统中进行分区以提高性能

导航到

本文最初发表在InfoWorld上,并经许可在此重发。

分区可以为分片系统提供许多好处,包括更快的查询执行速度。让我们看看它是如何工作的。

在之前的文章中,我介绍了一种用于扩展查询和摄入工作负载吞吐量和性能的分区系统。在这篇文章中,我将介绍另一种常见的技巧——分区,它为分区数据库提供了更多的性能和管理优势。我还会描述如何有效地处理查询和摄入工作负载的分区,以及如何管理冷(旧)分区,这些分区的读取需求与热(最近)分区有很大的不同。

分区与分片

分片是将数据分割在分布式数据库系统中的一种方式。每个分片中的数据不必共享资源,如CPU或内存,并且可以并行读取或写入。

图1是一个分片数据库的示例。一个国家的50个州的销售额数据被分为四个分片,每个分片包含12个或13个州的销售额数据。通过为每个分片分配一个查询节点,可以并行地在这些四个节点之间分配读取所有50个州的任务,与一个节点读取所有50个州相比,性能将提高四倍。有关分片及其对摄入和查询工作负载的影响的更多信息,请参阅我之前的文章《通过分片扩展吞吐量和性能》

partitioning-effects

图1:销售额数据被分为四个分片,每个分片分配给一个查询节点。

分区是将每个分片中的数据分割成不重叠的分区以进行进一步并行处理的一种方式。这减少了读取不必要的数,并允许高效地实施数据保留策略。

图2中,每个分片的数据按销售日进行分区。如果我们需要创建一个关于2022年5月1日特定一天销售额的报告,查询节点只需要读取2022.05.01对应的分区数据。

Figure 2- Sales data of each shard is further split into non-overlapped day partitions

图2:每个分片的销售额数据进一步分为不重叠的日分区。

本文的其余部分将专注于分区的影响。我们将了解如何高效地管理查询和摄入工作负载的热数据和冷数据的分区。

分区影响

数据分区最常见的三个好处是数据剪枝、节点内并行性和快速删除。

数据剪枝

数据库系统可能包含几年的数据,但大多数查询只需要读取最近的数据(例如,“过去三天内下了多少订单?”)。如图2所示,将数据分割成不重叠的分区可以轻松跳过整个超出范围的分区,并只读取和加工相关的非常小的数据集以快速返回结果。

节点内并行性

多线程处理和流数据在数据库系统中至关重要,可以充分利用CPU和内存,并获得最佳性能。将数据分割成小分区使得实现每个分区一个线程的多线程引擎变得容易。对于每个分区,可以产生更多线程来处理该分区内的数据。了解分区统计信息,如大小和行数,将有助于为特定分区分配最佳数量的CPU和内存。

快速数据删除

许多组织只保留最近的数据(例如,过去三个月的数据),并希望尽快删除旧数据。通过在非重叠的时间窗口上对数据进行分区,删除旧分区变得像删除文件一样简单,无需重新组织数据或中断其他查询或摄入活动。如果必须保留所有数据,本文后面将描述如何不同地管理最近和旧数据,以确保系统在所有情况下都提供出色的性能。

存储和管理分区

优化查询工作负载

分区已经包含了一小部分数据,所以我们不希望将分区存储在许多更小的文件中(或在内存数据库的情况下,是块)。分区应只包含一个或几个文件。

将分区中的文件数量最小化有两个重要的好处。它既减少了在执行查询时读取数据所需的I/O操作,又提高了数据编码/压缩。提高编码反过来降低了存储成本,更重要的是,通过读取较少的数据提高了查询执行速度。

针对摄取工作负载进行优化

原始摄取。为了保持分区中的数据在文件中以便获得上述读取优化的好处,每次摄取一组数据时,必须将其解析并拆分为正确的分区,然后将其合并到其对应分区的现有文件中,如图3所示。

将新数据与现有数据合并的过程通常需要时间,因为昂贵的I/O以及混合和编码分区数据成本很高。这将导致数据成功摄取后对客户端响应的延迟变长,以及新摄取数据的查询,因为数据不会立即在存储中可用。

Figure 3- Naive ingestion in which new data is merged into the same file as existing data immediately

图3:原始摄取,其中新数据立即与现有数据合并到同一文件中。

低延迟摄取。为了保持每次摄取的延迟低,我们可以将过程分为两个步骤:摄取和压缩。

摄取

在摄取步骤中,摄取数据被拆分并写入其自己的文件,如图4所示。它不会与分区中的现有数据合并。一旦摄取数据成功持久化,摄取客户端将收到成功信号,新摄取的文件将可用于查询。

如果摄取速率很高,分区中会积累许多小文件,如图5所示。在这个阶段,需要从分区读取数据的查询必须读取该分区的所有文件。这当然不利于查询性能。以下描述的压缩步骤将最大限度地减少这种文件积累。

Figure 4- Newly ingested data is written into a new file

图4:新摄取的数据写入到新文件中。

Figure 5- Under a high ingest workload a partition will accumulate many files

图5:在高摄取负载下,分区将积累许多文件。

压缩

压缩是将分区的文件合并为一个或几个文件的过程,以实现更好的查询性能和压缩。例如,图6显示了分区2022.05.01中的所有文件合并为一个文件,分区2022.05.02的所有文件合并为两个文件,每个文件的大小小于100MB。

关于如何决定压缩频率和压缩文件的最大大小,对于不同的系统会有所不同,但共同的目标是通过减少I/O(即文件数量)并使文件足够大以有效地压缩,来保持高查询性能。

Figure 6- Compacting several files of a partition into one or few files

图6:将分区中的几个文件压缩为一个或几个文件。

热分区与冷分区

经常被查询的分区被认为是热分区,而很少被读取的分区被称为冷分区。在数据库中,热分区通常是包含最近数据(如最近的销售日期)的分区。冷分区通常包含旧数据,不太可能被读取。

此外,当数据变旧时,它通常以较大的块进行查询,如按月甚至按年查询。以下是一些例子,明确地将数据从热分区分类到冷分区

  • 热:本周的数据。
  • 较不热:本月之前几周的数据。
  • 冷数据:上个月的数据,但属于当前年份。
  • 更多冷数据:去年及更早的数据。

为了减少热数据和冷数据之间的歧义,我们需要回答两个问题。首先,我们需要量化热、较热、冷、更冷,甚至可能还有更更冷的数据。其次,我们需要考虑在读取冷数据时如何减少I/O操作。我们不想读取365个文件,每个文件代表一天的数据分区,仅仅是为了获取去年的销售收入。

分层分区

分层分区,如图7所示,为上述两个问题提供了答案。当前周每天的数据存储在自己的分区中。当前月之前周的数据按周分区。当前年内之前月的数据按月分区。更早的数据按年分区。

可以通过定义一个活动分区来放松该模型,以替代当前的日期分区。所有在活动分区之后到达的数据将按日期分区,而活动分区之前的数据将按周、月和年分区。这允许系统根据需要保留尽可能多的近期小分区。尽管本文中的所有示例都是按时间分区数据,但只要你能够定义分区及其层次结构的表达式,非时间分区的工作方式也将相似。

Hierarchical-partitioning

图7:分层分区。

分层分区减少了系统中的分区数量,使其更容易管理,并且在查询更大和更旧的数据块时减少了需要读取的分区数量。

分层分区的查询过程与非分层分区相同,因为它将应用相同的剪枝策略,只读取相关的分区。摄入和压缩过程将稍微复杂一些,因为更难以组织定义好的分层分区。

聚合分区

许多组织不希望保留旧数据,而是更喜欢保留每月每个产品的订单数量和总销售额等汇总数据。这可以通过按月汇总数据并按月分区来实现。然而,由于聚合分区存储汇总数据,它们的模式将与非聚合分区不同,这将导致在摄入和查询时需要额外的工作。管理这种冷数据和聚合数据的方法有很多,但它们是适合未来文章的大型主题。