数据库分片如何提升性能
- Published on
目录
引言
分片(Sharding)是一种分布式数据库设计方法,旨在提升数据库性能和可扩展性。尽管分片的概念由来已久,但近期的技术创新使其成为解决大规模数据问题的有效方案之一。
数据库管理系统(DBMS)如今在企业中扮演着至关重要的角色,因为它们管理着公司最宝贵的资产——数据。30年前,数据通常存储在纸质文件、磁带或传统磁盘上。那时的数据生成和消费量相对较小,因此管理和访问数据并不困难。
然而,今天的情况截然不同。智能手机的普及以及各种应用程序的使用,使得我们生成和消费的数据量达到了前所未有的水平。这对数据库系统提出了巨大的挑战,尤其是那些需要处理数十亿次访问的顶级网站和服务。
面对如此庞大的流量,如何有效应对成为了一个关键问题。分片技术就是解决这一挑战的一种有效方法。尽管分片的概念可能听起来有些过时,但现代技术的进步(例如分布式SQL使得实现和管理分片变得容易)已经使得分片变得更加高效和易于管理。
数据库碎片化
数据库技术已经存在超过50年,虽然时间久远,但数据库碎片化(Database Sharding)却仍然是技术行业发展最快的领域之一。随着数据基础设施的复杂性不断增加,碎片化技术也不断演进。
许多现代应用程序建立在多个数据库之上,包括关系型数据库(如PostgreSQL)、内存数据库(如Redis)、自定义数据库(如时间序列数据库)以及数据仓库。不同的应用程序、部门甚至供应商可能会使用不同的数据库系统,这使得数据管理变得更加复杂。
根据DB-Engines的统计,目前存在超过350种数据库管理系统,而根据卡内基梅隆大学的"数据库之数据库"(Database of Databases),有792种不同的数据库管理系统。这种多样性表明企业在选择数据库时的需求十分广泛。
例如,金融机构可能选择关系型数据库(如SQL Server或PostgreSQL)以保证事务的ACID属性;在线游戏或需要会话管理的Web应用通常选择NoSQL数据库(如Redis);社交媒体分析公司则偏好图数据库,而物联网企业可能选择时间序列数据库以支持传感器数据。
在未来,数据库市场将变得更加碎片化,带来诸如供应商技术兼容性、遗留系统适配和更换成本等挑战。
为什么需要分片
传统数据库可能难以应对越来越多的数据和查询流量。NoSQL和NewSQL概念如今非常流行,相应地,越来越多受这些理念启发的新数据库产品正在进入市场。但仅凭这些概念并不能解决日益增长的数据问题。
分片是一种将数据分割成单独的行和列,并存储在不同数据库服务器实例上的技术,目的是分散流量负载。每个小型表被称为一个分片。一些NoSQL产品如Apache HBase或MongoDB拥有分片功能,而分片架构则内置于NewSQL系统中。
让我们看看NewSQL架构的一个特定类型:与当今OLTP(在线事务处理)问题相关的分片。
尽管有许多解决方案可以最小化数据库负载,但分片具有以下优势:
- 将数据存储分布在多台机器上
- 轻松平衡不同分片之间的流量负载
- 显著提高查询性能
- 无需额外工作即可扩展数据库
- 高效重用和升级传统DBMS
- 通过使用代理支持多租户,允许多个数据库在用户之间共享单个服务器或云计算资源
如何对数据库进行分片
以下是关于如何对数据库进行分片的基本工作流程。在讨论完设置和这项技术的基础思想之后,我们还将深入探讨一些重要的方面。
分片的最佳技术之一是将数据拆分为多个小表。这些小表也称为分区。原始表可以被分割为垂直分片或水平分片;也就是说,可以将一个或多个列存储在单独的表中(垂直分片),或者将一行或多行存储在单独的表中(水平分片)。这些表可以分别标记为“VS1”表示垂直分片和“HS1”表示水平分片。数字表示第一个表或第一个模式,然后是2、3,以此类推。当这些数据子集组合在一起时,就构成了表的原始模式。
以下是分片的两个关键概念:
分片键:一个特定的列值,指示该行存储在哪个分片中。
分片算法:一种将数据分配到一个或多个分片中的算法。
步骤 1:分析场景查询和数据分布以找到分片键和分片算法
要确定将某一行存储在哪个分片中,需要将分片算法应用于分片键。不同的分片策略适用于不同的场景。常见的策略包括:
- MOD:MOD 是模运算的缩写,它将每第 n 行或列发送到特定的分片。例如,MOD 3 算法会将第一、第四、第七行发送到第一个分片,将第二、第五、第八行发送到第二个分片,将第三、第六、第九行发送到第三个分片,以此类推。
- HASH:哈希分片会均匀且随机地将数据分布到各个分片中。每行数据会根据计算的哈希值被放置在相应的分片中。
- RANGE:RANGE 会将特定范围的行或列发送到各自的分片中。
- TAG:TAG 会将所有匹配特定值的行或列发送到相应的分片中。
例如,如果分片键是 “ID”,分片算法是 “ID 模 2” (将奇数行和偶数行分开),行将按如下方式排序:
因此,你需要设计一个适合的算法来使用分片键。分片策略将显著影响查询效率和未来的扩展性。不适当或糟糕的分片算法会在不同的分片间产生冗余数据,导致整体计算性能下降。
决定如何对数据库进行分片时,需要考虑的关键点是业务查询的特性和数据分布。每个数据库都会有独特的因素影响这个决策,但我们可以提供一些示例场景来说明一个好的分片算法如何高效地分配数据。
RANGE
例如,在对包含时间戳日志详情的表进行分片时,建议使用创建日期作为分片键的 RANGE 分片算法。原因在于,通常人们倾向于仅在特定的时间范围内查询这些详细记录。
然而,使用日期时间作为分片键时,RANGE 算法可能会引发另一个问题:历史记录通常会较少更新,而最近的记录则频繁更新和查询。这样,大多数查询将集中在包含最新记录的分片上,导致这些查询相互竞争以获取更新数据的独占权。
MOD
MOD 分片算法可以有效避免这种激烈的竞争。它通过“shardingKey MOD shards number”将行分片。最新的行会被分配到不同的分片中,从而避免了对最近记录的查询竞争。当分片键是字符串值(且可能涉及敏感信息披露)时,你可以使用 HASH 算法生成一个值,然后 MOD 算法可以使用这个值将数据分配到分片中。
TAG
然而,有时你可能需要根据单元格的值来分片数据,在这种情况下,你可以使用 TAG 分片算法。假设为了遵守 GDPR 规定,你希望将所有欧盟的数据存储在欧盟境内的服务器上。那么,如何操作一个分片分布式数据库系统来回答这个问题呢?如果 DBA 使用 TAG 分片算法,那么带有特定国家数据的行可以被发送到位于特定国家的分片中。要找出有多少记录受影响,我们的分片数据库系统只需要从欧盟分片中返回 COUNT(*)
,即可回答如下查询:SELECT COUNT(*) FROM registrant_table WHERE region = "EU"
。一个需要从整个分布式系统计算最终结果的分布式查询,变成了从一个分片中进行的简单查询。
没有一种方案适用于所有情况。为了实现最佳性能,花些时间深入分析你的具体业务场景。如果你希望快速入门,分布式分片数据库系统通常会选择一个适用于大多数用例的常见策略。
步骤 2:迁移现有数据
如果你决定实施分片,不需要将所有原始数据迁移到分片集群中。这样做会面临以下挑战:
- 如何在业务全天候运行的情况下对数据进行分片
- 如何在新的分片集群中重放增量数据
- 如何比较原始数据库与新分片集群之间的数据
- 如何找到将流量切换到新分片集群的最佳时机
然而,如果你决定将历史数据迁移到分片中,传统的方法如下:
- 首先,通过分片算法将历史数据分区到新的数据库分片集群中。建议使用一个程序自动移动数据,该程序将运行所有需要的 SQL 查询。
- 其次,运行一个平台或程序以提取和解析数据库日志,了解在分区过程中发生了哪些变化,并将这些变化应用到新的分片集群中(即增量数据分片)。
- 第三,选择一个数据检查策略来比较原始数据库和新分片集群之间的数据。这些数据检查策略可以在高精度和短时间内灵活选择,或者在两者之间取得平衡。你可以选择逐行比较或仅检查总量以确定检查的精度。如果你想实现最高的精度,逐行比较将需要最多的努力,而仅比较原始集群和新集群的行数则速度最快,但以牺牲准确性为代价。其他策略,如 CRC32,可以在精度和速度之间取得平衡。
步骤 3:将流量切换到新集群
假设前面的步骤都顺利完成,接下来的步骤是将在线流量切换到你的新分片集群。这应该在数据库集群不可写入的时间段内进行,以确保两个数据集保持一致并维持可选的查询功能——因此,非高峰时段通常是执行此步骤的最佳时间。
为了确保分布式数据的一致性,所有更新请求都应该被禁止,但查询是允许的,因为它们不会引起分布式系统中的任何变化。这个过程看起来足够简单,但处理每个部分可能会充满挑战。自动执行迁移可以将停机时间降到最低,但由于你将处理宝贵的数据,必须谨慎行事。
Apache ShardingSphere 就是将整个分片过程作为其主要功能之一。它提供不同的分片策略、数据迁移、重新分片,并管理现有的分片。
它还提供更高级的功能,以帮助解决接下来部分提到的问题。此外,Apache ShardingSphere 拥有一个活跃的社区,这意味着你的大多数问题都已被解决。
什么是良好的分片
现在你已经了解了分片的工作流程以及在数据库上执行分片的必要步骤,但什么才是良好的分片呢?
不需要过多扩展边缘理论或特定场景的需求,良好的分片通常具有以下六个特性:
- 易于设置和理解:即使 DBA(数据库管理员)发生变更,也能轻松理解和操作。
- 高可用性:系统能够在出现故障时继续正常运行。
- 弹性扩展能力:系统能够根据需求灵活扩展。
- 高分布式系统性能:系统在分布式环境下表现出色。
- 可观测性:系统能够提供足够的信息以便监控和调试。
- 低迁移开销:数据迁移的成本和复杂性较低。
这六个因素的存在代表了理想的分片状态,但这也取决于你选择的分片客户端。
分片和复制
除了上文提到的核心流程外,还需要了解以下内容,因为数据库场景多种多样,随着应用程序的扩展,你的需求也会随之改变。提高数据库性能和可扩展性的另一种方法是使用复制。复制会创建独立运行的数据库节点副本。写入一个节点的数据将被复制到其他副本节点上。
通常,专业人士和开发者都希望最大限度地利用数据库以获得高可用性和性能——然而,分片和复制的架构可能会导致复杂的数据库管理和路由策略。想象一下,每个分片都有副本节点。结果可能会像下图一样。如果一个主节点有多个副本,应用程序访问时的复杂性将加剧。
那么,分片和复制有什么区别呢?如上所述,分片是将一个大表拆分为几个小表来创建多个分片;而复制则是创建原始表的多个副本。每个副本都包含原始表的完整数据(即主节点的数据)。
分片可以帮助用户在多个服务器上均衡数据的存储,以实现可扩展性,而复制则会创建主数据库的备份以提高系统的可用性。这两种不同的架构为分布式系统带来了不同的优势。基于此,有些用户希望同时拥有这两种能力,因此在实际中,经常会看到分片和复制混合使用的架构。
如以上图所示,用户可能希望将一个包含海量数据的数据库分片到不同的服务器上,例如 P1、P2、P3。每个查询也将被分片到不同的分片上,以提高这个分布式数据库系统的 TPS 或 QPS。然而,如果其中一个分片崩溃,可用性将降至 2/3。而且,拉起另一个离线版本的副本非常耗时,可能导致严重的损失。为了提高这个分片系统的可用性,一个有效的方法是为每个分片拉起一个副本,即前面提到的主节点 P1、P2、P3。
R1、R2、R3 的存在说明了我上面解释的解决方案。当 P1 不可用时,它的副本 R1 将被提升为主节点,以继续为业务服务。这是一种安全的选择,基于的理念是停机越小,损失就越小。
这个想法听起来很不错,但这个分布式分片数据库系统的拓扑结构让应用程序的访问变得复杂。假设每个主节点拥有两个副本,那么由 P1、P2、P3 及其六个副本组成的网络将使开发者感到困惑和负担增加,产生以下问题:哪个主节点适合这个查询?如何访问它们的副本之一?如何在不同副本之间进行负载均衡?一旦主节点无法工作,谁将帮助我重新路由这个查询?
在我们的假设场景中,开发者的职责是为业务效率编写代码。这个出色的架构确实有其优点,但太复杂,难以利用和维护。
如何隐藏应用程序的复杂性
通常,用户可以选择两种类型的客户端或访问模式,外加一种新的“额外”类型的客户端。分片可以通过一个专用的数据库连接驱动程序启动,也可以通过将应用程序连接到一个代理应用程序来路由数据。
Sidecar 是现有分片模式中的新概念,源自服务网格。简单来说,它是一个与服务一起部署的代理实例,用于处理不同服务之间的通信、监控等。这个模式的操作类似于附在摩托车上的边车。这意味着 Sidecar 附在一个主应用程序上,同时为该应用程序提供支持功能。
如果我们使用专用驱动程序或代理而不是 Sidecar,它将表现为单个数据库服务器,帮助用户管理其数据库集群。通过这种方式,应用程序不会受到这些复杂访问拓扑结构的影响,也不需要重新架构自己以适应新的框架。
结论与趋势
分片是解决网络应用进化带来的新挑战的一种方法。其他解决方案包括 DBaaS(或云数据库)、新数据库架构,或者干脆采用传统的增加存储数据库数量的方法。分片是一种解决大规模数据问题的有效方法,但它并不是唯一的解决方案。随着技术的发展,新的数据库架构和服务也不断出现。保持对新趋势的开放态度,同时理解现有技术的优势,将有助于做出最佳的技术选择。
总之,分片和复制的组合可以显著提升数据库的性能和可用性,但也需要仔细规划和管理。通过合理选择和实施分片策略,可以有效应对不断增长的数据需求,确保系统的稳定性和可扩展性。