你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

数据分区建议

适用于此 Azure Well-Architected 框架可靠性清单建议:

RE:06 在应用程序、数据和基础结构级别实施及时可靠的缩放策略。

相关指南:缩放

本指南介绍为部署的数据库和数据存储技术设计数据分区策略的建议。 此策略可帮助你提高数据资产的可靠性。

关键设计策略

在许多大规模解决方案 中,分区 用于划分数据,以便可以单独管理和访问数据。 对数据进行分区可提高可伸缩性、减少争用并优化性能。 实现数据分区以按使用模式划分数据。 例如,可以将较旧的数据存档在廉价的数据存储中。 请谨慎选择分区策略,以最大程度地提高优势并最大程度地减少不利影响。

注意

在本文中,术语“分区”是指以物理方式将数据分割成独立数据存储的过程。 它不同于SQL Server表分区。

为何要将数据分区?

  • 提高缩放性。 纵向扩展单一数据库系统时,数据库最终会达到物理硬件限制。 如果跨多个分区划分数据,每个分区托管在单独的服务器上,则几乎可以无限期地横向扩展系统。

  • 提高性能。 在每个分区中,与未分区的数据相比,对较小的数据量执行数据访问操作。 对数据进行分区,使系统更高效。 影响多个分区的操作可以同时运行。

  • 提高安全性。 在某些情况下,可以将敏感和非敏感数据分为不同的分区,并将不同的安全控制应用于敏感数据。

  • 提供操作灵活性。 可以对数据进行分区以微调操作、最大限度地提高管理效率并最大程度地降低成本。 例如,可以根据每个分区中数据的重要性定义管理、监视、备份和还原以及其他管理任务的策略。

  • 将数据存储和使用模式相匹配。 可以根据数据存储提供的成本和内置功能,将每个分区部署在不同类型的数据存储上。 例如,可以将大型二进制数据存储在 Blob 存储中,并将结构化数据存储在文档数据库中。 有关详细信息,请参阅 了解数据存储模型

  • 提高可用性。 若要避免单一故障点,可以跨多个服务器分隔数据。 如果一个实例发生故障,只有该分区中的数据不可用。 操作在其他分区中继续。 此注意事项与托管平台即服务 (PaaS) 数据存储不太相关,因为它们具有内置冗余。

设计分区

数据分区有三个典型策略:

  • 水平分区\(通常称为分片)。 在此策略中,每个分区都是独立的数据存储,但所有分区具有相同的架构。 每个分区称为 分片 ,包含一部分数据,例如一组客户订单。

  • 垂直分区。 在此策略中,每个分区在数据存储中保存项字段的子集。 这些字段已根据其使用模式进行分割。 例如,将经常访问的字段放在一个垂直分区,将较不经常访问的字段放在另一个垂直分区。

  • 功能分区。 在此策略中,根据系统中每个边界上下文使用数据的方式聚合数据。 例如,电子商务系统可能在一个分区中存储发票数据,在另一个分区中存储产品库存数据。

设计分区方案时,请考虑合并这些策略。 例如,可以将数据分割成分片,然后使用垂直分区进一步细分每个分片中的数据。

水平分区(分片)

下图显示了水平分区或分片的示例。 此示例将产品清单数据划分为基于产品密钥的分片。 每个分片保存分区键(A-G 和 H-Z)的连续范围数据,根据字母顺序排列。 执行分片时,它会将负载分散到更多计算机上,从而减少争用并提高性能。

显示如何根据产品密钥将数据水平分区为分片的关系图。

最重要的因素是所选的分片键。 系统运行之后,就很难更改该键。 键必须确保在进行数据分区时,工作负荷能够尽量跨分片平均分配。

分片不需大小一致。 请求数的平衡更为重要。 某些分片可能很大,但分片中的每个项的访问操作数较少。 其他分片可能较小,但访问分片中的每个项的频率更高。 此外,确保单个分片不会超出数据存储的容量和处理资源的规模限制,这一点也很重要。

避免创建可能影响性能和可用性的 分区。 例如,如果使用客户姓名的第一个字母,则可能会造成分布不均衡,因为有些字母比其他字母更常见。 请改用客户标识符哈希在分区之间均匀分布数据。

选择可最大程度地减少将来拆分大型分片、将小分片合并为较大分区或更改架构的分片键。 这些操作非常耗时,可能需要使一个或多个分片脱机。

如果复制了分片,则可以使某些副本保持联机状态,而其他副本则进行拆分、合并或重新配置。 但是,系统可能会限制在重新配置期间可以执行的操作。 例如,可以将副本中的数据标记为只读,避免出现数据不一致的情况。

有关详细信息,请参阅分片模式

垂直分区

垂直分区最常见的用途是降低与提取经常访问的项相关的 I/O 和性能成本。 下图显示了垂直分区的示例。 在此示例中,项的不同属性存储在不同的分区中。 一个分区包含更频繁访问的数据,包括产品名称、说明和价格。 另一个分区保存库存数据,包括库存计数和上次订购日期。

显示如何按使用模式对数据进行垂直分区的关系图。

在此示例中,应用程序在向客户显示产品详细信息时定期查询产品名称、说明和价格。 库存计数和上次订购日期位于单独的分区中,因为这两项通常一起使用。

请参阅垂直分区的以下优势:

  • 可以将相对缓慢移动的数据 (产品名称、说明和价格) 与更动态的数据分开 (库存水平和上次订购日期) 。 慢速移动数据是应用程序在内存中缓存的一个很好的候选项。

  • 可以通过添加安全控制将敏感数据存储在单独的分区中。

  • 垂直分区可以减少必需的并发访问数量。

垂直分区在数据存储中的实体级运行,会部分规范化某个实体,以将它从项分割成一组项。 它非常适合用于面向列的数据存储,例如 HBase 和 Cassandra。 如果列集合中的数据不太可能更改,请考虑使用SQL Server中的列存储。

功能分区

当可以为应用程序中的每个不同业务领域标识边界上下文时,功能分区可以提高隔离和数据访问性能。 功能分区的另一种常见用途是将读写数据与只读数据隔离。 下图概述了将库存数据与客户数据分开的功能分区。

显示如何按上下文或子域对绑定的数据进行功能分区的示意图。

此分区策略可帮助减少跨系统中不同部件的数据访问争用。

设计可伸缩性的分区

考虑每个分区的大小和工作负荷至关重要。 平衡它们,以便分发数据以实现最大的可伸缩性。 但是,还必须对数据进行分区,使其不会超过单个分区存储的缩放限制。

设计可伸缩性分区时,请按照以下步骤操作:

  1. 分析应用程序以了解数据访问模式,例如每个查询返回的结果集的大小、访问频率、固有延迟和服务器端计算处理要求。 在许多情况下,一些主要实体需要大部分处理资源。

  2. 使用此分析来确定当前和未来的可伸缩性目标,例如数据大小和工作负载。 然后将数据跨分区分布以符合缩放性目标。 对于水平分区,请选择正确的分片键以确保均匀分布。 有关详细信息,请参阅分片模式

  3. 确保每个分区有足够的资源来处理数据大小和吞吐量方面的可伸缩性要求。 根据数据存储,每个分区的存储空间量、处理能力或网络带宽都有限制。 如果要求可能超过这些限制,则可能需要优化分区策略或进一步拆分数据。 可能需要合并两个或多个策略。

  4. 对系统进行监视,以验证数据是否按预期分配,以及分区是否可以处理负载。 实际使用情况并不总是与分析预测的一致。 可能需要重新平衡分区或重新设计系统的某些部分,以获得所需的余额。

某些云环境根据基础结构边界分配资源。 确保所选边界的限制为数据量、数据存储、处理能力和带宽的预期增长提供足够的空间。

例如,如果使用 Azure 表存储,则单个分区在特定时间段内可以处理的请求量有限制。 有关详细信息,请参阅标准存储帐户的可伸缩性和性能目标。 繁忙的分片所需的资源可能会超出单个分区的处理能力。 可能需要对分片进行重新分区以分散负载。 如果这些表的总大小或吞吐量超过存储帐户的容量,则可能需要创建更多存储帐户,并将表分散在这些帐户中。

针对查询性能设计分区

可以通过使用小型数据集和运行并行查询来提高查询性能。 每个分区应包含整个数据集的一小部分。 这种数量缩减可以提高查询性能。 但是,分区不是适当的数据库设计和配置的替代方法。 确保实现必要的索引。

设计查询性能分区时,请按照以下步骤操作:

  1. 检查应用程序要求和性能。

    • 根据业务要求来确定必须始终快速执行的重要查询。

    • 监视系统以识别执行速度缓慢的查询。

    • 确定执行频率最高的查询。 即使单个查询的成本最低,累积资源消耗也可能会很大。

  2. 对导致性能降低的数据进行分区。

    • 限制每个分区的大小,使查询响应时间在目标范围内。

    • 如果使用水平分区,请设计分片键,以便应用程序可以轻松选择适当的分区。 此规范可防止查询扫描每个分区。

    • 考虑分区的位置。 尝试将数据保存在地理上靠近访问数据的应用程序和用户的分区中。

  3. 如果实体具有吞吐量和查询性能要求,请使用基于该实体的功能分区。 如果此分配仍不满足要求,可以添加水平分区。 单分区策略通常已足够,但在某些情况下,合并这两种策略会更有效。

  4. 跨分区并行运行查询以提高性能。

设计可用性分区

对数据进行分区以提高应用程序的可用性。 分区可确保整个数据集没有单一故障点,并且可以独立管理数据集的各个子集。

请注意以下会影响可用性的因素:

确定数据的关键性。 确定关键业务数据(例如事务)和不太关键的操作数据(如日志文件)。

  • 将关键数据存储在高度可用的分区中,并创建适当的备份计划。

  • 为不同的数据集建立单独的管理和监视过程。

  • 将具有相同严重性级别的数据置于同一分区中,以便以相同的频率备份数据。 例如,可能需要备份保存事务数据的分区,而不是保存日志记录或跟踪信息的分区。

管理单个分区。 设计分区以支持独立管理和维护。 这种做法提供了几个优点,例如:

  • 如果分区故障,可以独立恢复该分区,不需使用在其他分区中访问数据的应用程序。

  • 按地理区域将数据分区允许在每个位置的非高峰时段执行计划性维护任务。 确保分区不会太大,以免在此期间完成计划内维护。

跨分区复制关键数据。 此策略可提高可用性和性能,但也可能导致一致性问题。 在每个副本中同步所做的更改需要时间。 在同步期间,不同的分区包含不同的数据值。

应用程序设计注意事项

分区会增大系统设计和开发的复杂性。 将数据分区作为系统设计的基本部分,即使系统最初只包含单个分区也是如此。 如果事后考虑分区,这很具有挑战性,因为你已经有一个要维护的实时系统。 你可能会:

  • 必须修改数据访问逻辑。

  • 必须迁移大量现有数据才能跨分区分发数据。

  • 遇到挑战,因为用户希望在迁移期间继续使用系统。

在某些情况下,分区并不重要,因为初始数据集很小,单个服务器可以轻松处理它。 某些工作负载可以不使用分区,但许多商业系统需要随着用户数量的增加而扩展。

一些小型数据存储也受益于分区。 例如,数百个并发客户端可能会访问小型数据存储。 如果在这种情况下对数据进行分区,则有助于减少争用并提高吞吐量。

在设计数据分区方案时,请注意以下几点:

尽量减少跨分区数据访问操作。 尝试将最常见的数据库操作的数据一起保存在分区中,以最大程度地减少跨分区数据访问操作。 跨分区进行查询比在单个分区中进行查询更耗时。 但是,优化一组查询的分区可能会对其他查询集产生负面影响。 如果必须跨分区查询,则应通过运行并行查询并在应用程序中聚合结果来尽量减少查询时间。 在某些情况下,不能使用此方法,例如,如果在下一个查询中使用了一个查询的结果。

复制静态引用数据。 如果查询使用相对静态的引用数据(如邮政编码表或产品列表),请考虑在所有分区中复制此数据,以减少不同分区中的单独查找操作。 此方法还可以降低引用数据成为 数据集的可能性,该数据集包含来自整个系统的大量流量。 将更改同步到引用数据会产生额外的费用。

尽量减少跨分区联接。 尽量减少跨垂直和功能分区的引用完整性的要求。 在这些方案中,应用程序负责维护跨分区的引用完整性。 跨多个分区联接数据的查询效率低下,因为应用程序通常执行基于键和外键的连续查询。 建议复制或取消规范化相关的数据。 如果需要进行跨分区联接,请对各分区运行并行查询,并在应用程序内部联接数据。

实现最终一致性。 评估是否要求强一致性。 分布式系统中的一种常见方法是实施最终一致性。 每个分区中的数据单独更新,应用程序逻辑可确保更新成功完成。 应用程序逻辑还处理在运行最终一致的操作时查询数据引起的不一致问题。

考虑查询如何查找正确的分区。 如果查询必须扫描所有分区才能找到所需的数据,则即使运行多个并行查询,也会显著影响性能。 使用垂直分区和功能分区,查询可以指定分区。 另一方面,水平分区可能会使查找项变得困难,因为每个分片都具有相同的架构。 典型的解决方案是维护用于查找项的分片位置的映射。 在应用程序的分片逻辑中实现此映射。 如果数据存储支持透明分片,也可以由数据存储进行维护。

定期重新平衡分片。 使用水平分区,重新均衡分片有助于按大小和工作负载均匀分布数据。 重新平衡分片以最大程度地减少热点,最大限度地提高查询性能,并解决物理存储限制。 此任务很复杂,通常需要自定义工具或流程。

复制分区。 复制每个分区以针对故障提供额外的保护。 如果单个副本 (replica) 失败,查询将定向到工作副本。

将可伸缩性扩展到不同的级别。 如果达到了分区策略的物理限制,可能需要将缩放性扩展到其他级别。 例如,如果分区位于数据库级别,则可能需要在多个数据库中查找或复制分区。 如果分区已在数据库级别进行,并且存在物理限制,则可能需要在多个托管帐户中查找或复制分区。

避免执行在多个分区中访问数据的事务。 某些数据存储为修改数据的操作实现事务一致性和完整性,但前提是数据位于单个分区中。 如果需要跨多个分区的事务支持,请将其作为应用程序逻辑的一部分实现,因为大多数分区系统不提供本机支持。

所有数据存储都需要某种操作管理和监视活动。 这些任务包括加载数据、备份和还原数据、重新组织数据,以及确保系统正确高效地执行。

请注意以下会影响操作管理的因素:

  • 对数据进行分区时,实施适当的管理和操作任务。 这些任务可能包括备份与还原、存档数据,监视系统及其他管理任务。 例如,在备份和还原操作期间保持逻辑一致性可能很困难。

  • 将数据加载到多个分区中,并添加来自其他源的新数据。 某些工具和实用程序可能不支持分片数据操作,例如将数据加载到正确的分区中。

  • 定期存档和删除数据。 为了防止分区过度增长,请每月存档和删除数据。 可能需要转换数据以匹配不同的存档架构。

  • 查找数据完整性问题。 请考虑运行定期进程来查找数据完整性问题,例如一个分区中的数据引用另一个分区中缺少的信息。 该过程可以自动尝试解决这些问题,也可以生成报告以供手动查看。

重新平衡分区

随着系统成熟,可能需要调整分区方案。 例如,单个分区可能会开始接收不成比例的流量并变得热,从而导致过度争用。 或者,你可能低估了某些分区中的数据量,这会导致分区接近容量限制。

某些数据存储(例如 Azure Cosmos DB)可能会自动对分区进行重新均衡。 在其他情况下,可以分两个阶段重新平衡分区:

  1. 确定新的分区策略。

    • 需要拆分或合并哪些分区?

    • 新的分区键是什么?

  2. 将数据从旧的分区方案迁移到一组新的分区。

重新定位数据时,可能需要使分区不可用,这称为 脱机迁移。 根据数据存储,在使用分区时,可以在分区之间迁移数据。 此方法称为 联机迁移

脱机迁移

脱机迁移可减少发生争用的可能性。 若要执行脱机迁移,请执行以下操作:

  1. 将分区标记为脱机。 可以将分区标记为只读,以便应用程序在移动数据时仍可读取数据。

  2. 拆分/合并数据,并将其转移到新分区。

  3. 验证数据。

  4. 使新分区联机。

  5. 删除旧分区。

联机迁移

与脱机迁移相比,联机迁移更为复杂,但中断更少。 此过程类似于脱机迁移,但不会将原始分区标记为脱机。 根据迁移过程的粒度(例如逐项与按分片),客户端应用程序中的数据访问代码可能需要读取和写入两个位置(原始分区和新分区)中的数据。

Azure 便利化

以下部分介绍对 Azure 服务中存储的数据进行分区的建议。

Azure SQL 数据库中的分区

单个 SQL 数据库对其包含的数据列施加了限制。 吞吐量受体系结构因素及数据库支持的并发连接数的约束。

弹性池支持对 SQL 数据库进行水平缩放。 使用弹性池将数据分区到分布在多个 SQL 数据库的分片中。 还可以在数据量增长和收缩时添加或删除分片。 使用弹性池还有助于在数据库之间分散负载,减少争用。

每个分片将作为 SQL 数据库实施。 一个分片可以保存多个数据集。 每个数据集称为 shardlet。 每个数据库都有描述其包含的 shardlet 的元数据。 shardlet 可以是单个数据项,也可以是共享同一 shardlet 键的一组项。 例如,在多租户应用程序中,shardlet 密钥可以是租户 ID,租户的所有数据都可以位于同一 shardlet 中。

应用程序负责将数据集与 shardlet 密钥相关联。 独立的 SQL 数据库将充当全局分片映射管理器。 此数据库有一个列表,其中包含系统中的所有分片和 shardlet。 应用程序在连接到分片映射管理器数据库后,可以获取分片映射的副本。 它会在本地缓存分片映射,并使用映射将数据请求路由到相应的分片。 此功能隐藏在一系列 API 后面,这些 API 包含在 SQL 数据库 的弹性数据库功能的客户端库中,适用于 Java 和 .NET。

有关弹性池的详细信息,请参阅使用SQL 数据库进行横向扩展

若要减少延迟并提高可用性,可以复制全局分片映射管理器数据库。 使用高级定价层,可以配置活动异地复制,以将数据持续复制到不同区域中的数据库。

或者,使用SQL 数据同步SQL 数据库Azure 数据工厂跨区域复制分片映射管理器数据库。 这种形式的复制会定期运行,如果分片映射不经常更改且不需要高级层,则更适合。

弹性数据库提供了两种方案用于将数据映射到 shardlet 并将 shardlet 存储在分片中:

  • 列表分片映射将单个键与 shardlet 相关联。 例如,在多租户系统中,每个租户的数据可与唯一的键相关联,并存储在自身的 shardlet 中。 为了保证隔离,可将每个 shardlet 都保存在自身的分片中。

    显示其自己的分片中保留的 shardlet 的示意图。

    下载此图的 Visio 文件

  • 范围分片映射将一组连续键值与 shardlet 相关联。 例如,可以在同一 shardlet 中对一组租户的数据进行分组,每个租户都有自己的密钥。 此方案比列表分片映射便宜,因为租户共享数据存储,但隔离程度较低。

    显示同一 shardlet 中的租户集的关系图。

    下载此示意图的 Visio 文件

单个分片可以包含多个 shardlet 的数据。 例如,可以使用列表 shardlet 将不同非连续租户的数据存储在同一分片中。 还可以在同一分片中混合使用范围 shardlet 和列出 shardlet,但随后会通过不同的映射进行寻址。 下图显示了此方式:

显示同一分片中通过不同映射寻址的 shardlet 的关系图。

下载此图的 Visio 文件

使用弹性池,可以随着数据量的增长和收缩添加和删除分片。 客户端应用程序可以动态和透明地创建和删除分片映射管理器。 但删除分片是破坏性操作,还需要删除该分片中的所有数据。

如果应用程序需要将一个分片拆分成两个独立的分片或者将分片组合在一起,请使用拆分/合并工具。 此工具作为 Azure Web 服务运行,并在分片之间安全地迁移数据。

分区方案可能会显著影响系统的性能。 它还会影响添加或删除分片的速率,或者跨分片对数据重新分区的速率。 请考虑以下要点:

  • 对在同一分片中一起使用的数据进行分组,并避免从多个分片访问数据的操作。 分片本身是 SQL 数据库,当操作访问多个分片时,必须在客户端执行跨数据库联接。

    尽管 SQL 数据库 不支持跨数据库联接,但你可以使用弹性数据库工具来执行多分片查询。 多分片查询会将单个查询发送到每个数据库,然后将结果合并在一起。

  • 设计分片之间不具有依赖关系的系统。 一个数据库中的引用完整性约束、触发器和存储过程不能引用另一个数据库中的对象。

  • 如果有查询经常使用的引用数据,请考虑跨分片复制数据。 此方法可以消除跨数据库联接数据的需求。 理想情况下,此类数据应是静态的或缓慢移动的,以最大程度地减少复制工作并减少其过时的可能性。

  • 对属于同一分片映射的 shardlet 使用相同的架构。 SQL 数据库不会强制实施本指南,但如果每个 shardlet 具有不同的架构,则数据管理和查询会很复杂。 为了避免这种情况,请为每个架构创建单独的分配映射。 可以将属于不同 shardlet 的数据存储在同一分片中。

  • 如果业务逻辑需要执行事务,请将数据存储在同一个分片中或实现最终一致性。 事务操作仅支持分片中的数据,而不是跨分片的数据。 如果事务是同一分片的一部分,则可以跨 shardlet。

  • 将分片放置在访问这些分片中的数据的用户的附近。 此策略有助于缩短延迟。

  • 避免将高度活动分片和相对非活动分片组合在一起。 尽量跨分片平均分散负载。 可能需要对分片键进行哈希处理。 如果要对分片进行异地定位,请确保哈希键映射到分片中保存的 shardlet,这些分片存储在靠近访问该数据的用户的附近。

在 Azure Blob 存储 中分区

使用 Blob 存储,可以存储大型二进制对象。 在需要快速上传或下载大量数据的情况下使用块 Blob。 对于需要随机(而不是串行)访问部分数据的应用程序,请使用页 Blob。

每个块 Blob 或页 Blob 保存在 Azure 存储帐户的容器中。 使用容器对具有相同安全要求的相关 Blob 进行分组。 这种分组是逻辑性的,而不是物理性的。 在容器中,每个 Blob 都有唯一的名称。

Blob 的分区键是帐户名称、容器名称和 Blob 名称。 分区键用于将数据分区为范围。 这些范围跨系统进行负载均衡。 Blob 可以分布在多个服务器上,以横向扩展对它们的访问。 单个 Blob 只能由单个服务器提供服务。

如果命名方案使用时间戳或数字标识符,可能会导致一个分区的流量过多。 它阻止系统有效地进行负载均衡。 例如,如果日常操作使用具有时间戳的 Blob 对象(例如 yyyy-mm-dd),则该操作的所有流量都会流向单个分区服务器。 相反,在名称前面加上三位数哈希。 有关详细信息,请参阅 分区命名约定

写入单个块或页的操作是原子操作,但跨块、页或 Blob 的操作不是。 如果需要确保在跨块、页和 Blob 执行写入操作时保持一致性,请使用 Blob 租约删除写入锁。

注意事项

数据分区引入了一些需要考虑的挑战和复杂性。

  • 分区之间的数据同步可能会成为一项挑战。 确保对一个分区的更新或更改及时且一致地传播到其他分区。

  • 需要协调多个分区的备份和还原时,故障转移和灾难恢复过程变得复杂。 如果某些分区或其备份已损坏或不可用,则可能会出现数据完整性问题。

  • 如果需要跨分区查询,以及重新平衡分区(如果数据增长不均匀),数据分区可能会影响性能和可靠性。

可靠性清单

请参阅完整的建议集。