如何分片数据库? - stackoverflow


分片是解决网络应用发展带来的新挑战的方法之一。其他解决方案包括 DBaaS(或云中的数据库)、新的数据库架构,或者只是增加用于存储的数据库数量的老式方法。 
随着智能手机的出现,应用程序将我们消耗和产生的数据量增加到了 15 年前无法想象的水平。这给数据库集群带来了很大的压力,因为它们需要处理越来越多的流量,一些顶级网站和服务每周接收数十亿次访问。
当它到达数据库集群时,我们如何处理如此惊人的流量? 
答案可能是分片。
 
为什么需要分片
传统数据库可能难以处理越来越多的数据和查询流量。NoSQL和 NewSQL 概念现在非常流行,因此越来越多的受这些想法启发的新数据库产品正在投放市场。但仅凭这些概念并不能解决日益增长的数据问题。 
分片是一种将数据拆分为单独的行和列的技术,这些行和列保存在单独的数据库服务器实例上,以分散流量负载。每个小表称为一个分片。一些 NoSQL 产品如 Apache HBase 或 MongoDB 有分片,并且分片架构内置在 NewSQL 系统中

让我们看看一种特殊类型的 NewSQL 架构:与当今的 OLTP(在线事务处理)问题相关的分片。 
虽然有许多解决方案可以最大限度地减少数据库负载,但分片具有以下优点:

  •  在多台机器上分布数据存储
  •  轻松平衡不同分片的流量负载
  •  显着提高查询性能
  •  无需额外工作即可扩展数据库
  •  高效重用和升级传统 DBMS
  •  由于使用代理支持多租户,因此允许多个数据库跨用户使用单个服务器或云计算资源。  

 
如何对数据库进行分片
以下是一个基本工作流程,可让您为 DBMS 实现分片。在讨论了这项技术的设置和基本思想之后,我们将在稍后对一些基本方面提供一些更深入的见解。
创建分片的最佳技术之一是将数据拆分为多个小表。这些也称为分区。 
原始表可以分为垂直分片或水平分片;也就是说,通过将一列或多列存储在单独的表中,或者将一列或多行存储在单独的表中。这些表可以标记为垂直分片的“VS1”和平面分片的“HS1”。数字代表第一个表或第一个模式。然后是 2,然后是 3,以此类推。综合起来,这些数据子集构成了表的原始模式。 
以下是分片的两个关键概念:
  1. • 分片键:一个特定的列值,指示该行存储在哪个分片中。
  2. • 分片算法:一种将数据分布到一个或多个分片的算法。

 
  • Step 1:分析场景查询和数据分布,找到分片键和分片算法

确定存储任何给定行的分片,请将分片算法应用于分片键。不同的分片策略适合不同的场景。常见的策略包括:
  1. MOD:模数的缩写,这会将每第 n 行或每列发送到特定的分片。例如,MOD 3 算法会将第一、四和七行发送到第一个分片,将第二、五和八行发送到第二个分片,将第三、六和第九行发送到第三个分片,并且很快。 
  2. HASH:哈希分片在分片之间均匀随机分布数据。根据对该行的分片列值计算的一致哈希将每个表行放置在一个分片中。
  3. RANGE:这会将特定范围的行或列发送到各个分片。 
  4. TAG:这会发送与特定值匹配的所有行或列。 

因此,您要做的就是设计一个使用分片键的拟合算法。您的分片策略将显着影响查询效率和未来的横向扩展。不正确或糟糕的分片算法总是会在不同的分片之间创建冗余数据进行计算,最终导致整体计算性能不佳。
决定如何对数据库进行分片时要考虑的关键点是业务查询和数据分布的特征。每个数据库都会有影响这个决定的独特因素,但我们可以提供一些示例场景来说明一个好的分片算法如何有效地分布数据。 

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步:迁移现有数据

如果你决定实施分片,你不需要将所有的原始数据迁移到分片集群中。这样做是一个挑战,因为你会面临以下问题。
  1. 如何在业务24/7运行时分片数据 
  2. 如何在新的分片集群中重放增量数据 
  3. 如何比较原始数据库和新分片集群之间的数据 
  4. 如何找到将流量切换到新分片集群的最佳时机

然而,如果你确实决定将历史数据迁移到分片上,传统的方法如下。
  1. 首先,通过分片算法将历史数据分割到新的数据库分片集群中。推荐使用一个自动移动数据的程序,它将运行所有需要的SQL查询。
  2. 第二,运行一个平台或程序来拉动和解析数据库日志,了解在分区过程中发生了哪些变化,并将这些变化应用到新的分片集群中(增量数据分片)。
  3. 第三,选择一种数据检查策略来比较原始数据库和新分片集群之间的数据。这些数据检查策略是灵活的,从高精度到短周期,或者两者之间的平衡。你是想比较每个单元还是只检查总量,由你决定。在数据检查策略方面,要达到最高的准确度,逐一比较行数需要付出最大的努力,而只比较原集群和新集群的行数,则以牺牲准确度为代价,速度最快。其他策略,如CRC32,则是实现了准确性和速度的平衡。

 
  • 第3步:将流量转移到新的集群

假设上述步骤顺利完成,下一步是将在线流量切换到你的新分片集群。这应该发生在数据库集群不能被写入的时期,以便两个数据集保持一致,并保持可选的查询--非高峰期是这个步骤的常见选择。

为了保持分布式数据的一致性,应该禁止所有更新请求,但允许查询,因为它们不会在分布式系统中引起任何变化。
这个过程足够直截了当,但每个部分的处理都会有挑战性。自动执行移动将最大限度地减少停机时间,并建议谨慎行事,因为你将处理宝贵的数据。

好消息是,你不是第一个遇到这些挑战的人。开源项目让我们能够站在巨人的肩膀上。

Apache ShardingSphere(我是它的贡献者)将整个分片过程作为其主要功能之一来处理。它提供不同的分片策略,迁移数据,重新分片,并管理现有的分片。

它还提供了更多的高级功能,以帮助解决下一节中提到的问题。作为额外的奖励,Apache ShardingSphereit拥有一个活跃的社区,这意味着你的大多数问题已经得到解决。
 
 
使用分片和复制 

除了上面提到的核心流程外,还要对下面的项目进行训练,因为数据库场景是多样化的,你的需求会随着应用的扩展而改变。

另一种提高数据库性能和可扩展性的方法是通过复制。复制创建独立运行的重复数据库节点。写入一个节点的数据就会被复制到另一个重复的节点上。

一般来说,无论是专业人士还是从事激情项目的开发人员,都会努力从数据库中榨取最大的能量,以获得高可用性和性能--然而,分片和复制的架构会导致复杂的数据库管理和路由策略。

那么,分片和复制之间有什么区别?
分片是指将一个大表分割成几个小表,以创建许多分片;
另一方面,复制将创建原始表的许多副本。每个副本将包含原表(主节点)的全部数据。

分片可以帮助用户在多个服务器上平衡数据的存在,以获得可扩展性,而复制将创建主数据库的备份以提高系统的可用性。
这两种不同的架构给分布式系统带来了不同的优势。
基于这一推理,一些用户希望同时拥有这两种能力,因此,同时利用分片和复制的混合架构并不罕见。

例如:用户可能希望将一个包含巨大数据量的数据库分片到不同的服务器上,比如P1、P2、P3。每个查询也将被分片到不同的分片中,以提高这个分布式数据库系统的TPS或QPS。然而,如果其中一个分片崩溃了,可用性将降低到2/3。
此外,拉起另一个离线版本的副本是很耗时的,会造成严重后果的损失。为了提高这个分片系统的可用性,一个有效的方法是为每个分片拉起复制,也就是前面提到的主节点P1、P2、P3。

R1、R2、R3的存在说明了我上面解释的解决方案。当P1不可用时,它的复制,R1,将被提升到主节点,为业务服务。这是一个安全的选择,它的想法是,故障越小,对你的业务和服务的损失就越小。

这个想法听起来不错,但这种分布式分片数据库系统的拓扑结构使应用访问变得复杂。假设每个主节点拥有两个副本,那么由P1、P2、P3和它们的六个副本组成的网络将使开发人员感到困惑和负担,提出的问题包括:哪个主节点对这个查询是正确的? 如何访问它们的一个副本?如何在不同的副本之间做负载平衡?一旦主节点不能工作,谁会帮我重新安排这个查询?

在我们假设的场景中,开发人员的责任是为业务效率编码。这种非凡的架构确实有优势,但要利用和维护却太复杂了。

如何从应用中隐藏这种复杂性?

一般来说,有两种类型的客户端或访问模式供用户选择,外加一种新的 "奖励 "类型的客户端。分片可以通过专门的数据库连接驱动程序来唆使,也可以通过将你的应用程序连接到一个路由数据的代理应用程序。

Sidecar是分片可用模式中较新的概念,源自于服务网格。简单来说,它是一个与服务一起部署的代理实例,用于处理不同服务之间的通信、监控等。这种模式的运作类似于连接在摩托车上的副车。这意味着副车附着在父级应用上,同时为应用提供支持功能。

如果我们使用一个专门的驱动程序或代理,而不是sidecar,它将作为一个单一的数据库服务器行事和出现,帮助用户管理他们的数据库集群。这样,应用程序就不会受到这些复杂的访问拓扑结构的影响,或者不得不重构自己以适应新的框架。