百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

数据系统 - 领导和随从 领导者和跟随者的区别是什么?

liebian365 2024-11-13 13:30 19 浏览 0 评论

每个存储了一份数据库拷贝的节点称为一个replica复制品,如果有许多的复制品,那么就会出现一个问题:我们怎么保证所有的数据都能及时的更新到所有的复制品中。

每次对数据库的写入都需要对每个复制品做处理;否则,复制品就不能包含相同的数据了。最通常的解决方案称为leader-based replication,也被称为active/passivemaster-slave replication,主从复制,如下图所示:

它是这么工作的:

  1. 一个复制品被设计成为leader领导,也被称为masterprimary,当客户端想要写数据库时,他们必须将他们的请求发送给leader,它会把新的数据首先写入本地的存储中。
  2. 其他的复制品被称为followers随从,也被称为read replicasslavessecondaries,或hot standbys。一旦leader把新的数据写入它的本地存储后,它也会把数据作为replication log或是change stream的一部分,发送给followers。每个followes会得到来自leader的log,然后以此更新其本地数据库的存储,通过这样的形式处理以保持它们和leaders的一致。
  3. 当用户想要从数据库读取数据时,这个数据库可以是leader也可以是任何一个followers。然而,只有leader能接受写的请求,follwers是只读的。

这个模式的拷贝是很多关系型数据库的内置功能,诸如PostgreSQL(从9.0版本开始),MySQL,Oracle Data Guard以及SQL Server的AlwaysOn Availability Groups。它也被用于一些非关系型数据库,包括MongoDB,RethinkDB,和Espresso。

leader-based拷贝并不严格限制于数据库:分布式消息代理诸如Kafka和RabbitMQ highly availale queues也使用这个机制。一个网络文件系统和注入DRBD的拷贝块设备也用到类似的机制。


拷贝:同步 VS 异步

拷贝系统的一个重要的细节就是拷贝是同步发生的,还是异步的。在关系型数据库中,这通常是一个可选项,而其他的一些系统则通常是hardcode了其中一个。

让我们看看上图中发生了什么,一个网站的用户更新了他的简介图片。在某个时间点,客户端发送更新请求给leader;随后很快,leader接受到了这个请求。在某个时间点,leader把数据更改转发给了followes。最后,leader通知客户端更新成功。

下图展示了系统不同组件(用户的客户端,leader, 两个followes)之间的通信。时间流从左往右。请求或响应消息以箭头表示。

在上图中,对于followr1的拷贝是同步的:leader一直等到followe1确定收到了写的请求,(而在其他客户端看到这个写所产生的变化之前),才向用户汇报成功。对于follower2的拷贝是异步的:leaders发送了信息,但没有等待来自follower的响应。

图表也展示了在follower2处理消息之前有延迟。正常情况下,拷贝是很快的:大多数的数据库系统不到一秒就可以把更改应用到follower。然而,这到底可能花多少时间是没有任何保证的。有一些follower落后leader好几分钟的情况,比方说,follower从一次failure中恢复过来,或是系统操作已经接近最大容量,又或是在两个节点之间有网络问题。

同步拷贝的优势是确保folloer可以和leader一样有一个及时的更新。如果leader突然fail了,我们可以仍可以从follower那里获得数据。缺点是如果同步的followers不响应,因为它crash了或是网络玩儿你,又或是其他原因,那么这个写请求就得不到处理。leader会阻塞所有的其他写请求,直到同步复制品可以再次被访问到。

因为任何一个节点的故障会导致整个系统停下来,所以让所有的follower同步是不切实际的。在实践中,如果你使能了数据库的同步机制,这通常意味着follower中的其中一个是同步的,其他的是异步的。如果同步的follower变得不能访问或者很慢,那么异步的follower中的一个就会变成同步的。这也保证了你至少可以在两个节点上(一个是leader,一个是同步follower)保有最新的数据。这种配置有时被称为semi-synchronous半同步

通常,leader-based的拷贝会被完全配置成异步。在这样的情况下,如果leader fail并且不可恢复,那么任何还没有复制到follower的写都会丢失。这些意味着即使客户端得到了确认,写请求也不能保证是可持久的。然而,一个完全异步配置的优势是leader可以持续性的处理写请求,即使它的所有的followers都fail了。

对于持久性的弱化听上去像是一个糟糕的权衡,但异步拷贝还是被广泛使用,特别是有许多follower时或是它们在地理上是分散的。

设立新的随从

时不时的,我们就需要设立一些新的followers,也许是为了增加复制品的数量,又或许是替代坏了的节点。那么你怎么保证新的follower可以有一份精确的对于leader的拷贝呢?

简单从一个节点拷贝数据文件到另一个节点一般而言是不够的:因为客户端会不停地向数据库写入数据,数据一直是在变化的,所以一个标准的文件拷贝在不同的时间点上会看到数据库中不同的部分。结果也就没有什么意义了。

你可以在拷贝磁盘文件时锁上数据库,这也就导致拒绝了所有的写请求,但这会违背了我们高度可用性的宗旨。幸运的是,设立一个新的follower通常不需要停机。从概念上来说,是按照如下处理:

  1. 获取leader数据库在某个时间点的一致性快照,如果可能的话,就不用对整个数据库上锁了。由于有备份的需求,大多数的数据库都有这个特性。在一些情况下,也需要一些第三方工具,诸如针对MySQL的innobackupex。
  2. 把快照复制到新的follower节点。
  3. follower连接上leader,并且请求自快照后的所有的发生的数据变化。这要求快照与leader的复制日志中的确切位置相关联。这个位置有不同的名字,比方说在PostgeSQL中称为log sequence number,在MySQL中称为binlong coordinates。
  4. 当follower处理完子快照后的数据变化的后续记录,我们就认为它已经catch up。它现在可以继续像其他follower一样处理来自leader的后续数据变化了。

在实践中,根据数据库的不同,设立新的follower的步骤是很不一样的。在一些系统中,这个处理过程是完全自动的,而在其他系统中,这可能是一个有点不可思议的多步骤工作流程,需要管理员手动执行。


处理节点失效

任何在系统的节点都会宕机,也许是由于一次意外的故障,但也可能就是由于一个计划中的维护,比方说为了安装一个安全补丁而重启机器。能够在不停机的情况下重启单个节点是很大的运维优势。因此,我们的目标是即使单个节点发生故障,也能使系统整体正常运行,并使节点中断的影响尽可能小。

那么在leader-based的拷贝中,怎么实现这种高可用性呢?

Follower failure : Catch-up式恢复

在本地磁盘上,每个follower都会保有一份来自leaders的数据变更的日志。如果follower崩溃并且重启后,或是leader和follower之间的网络被临时中断后,follower可以很简单的恢复过来:根据日志,它知道故障发生前最后一个处理的事务。因此follower连接上leader,然后请求follower失连这段时间内的所有数据的变化。当这些变化被应用后,他就追赶catch up上了leaders,然后就可以像以前一样工作了。

Leader failure:故障转移

处理leader的failure比较棘手:需要把follower中的某一个晋升为leader,客户端需要重新配置才能把它们的写请求发送给新的leader,并且其他的followerx需要开始处理来自新的leader的数据变化。这个过程称为failover故障转移

故障转移可以手动(管理员被告知leader fail了,需要采取必要的步骤设立一个新的leader)或自动发生。通常一个自动的故障转移由如下几个步骤组成:

  1. 确认leader已经fail了。有很多可能会出错的地方:崩溃,断电,网络问题等等。没有万无一失的方法可以检测出哪里出了问题,因此大多数系统仅使用超时:节点之间经常来回反弹消息,如果某个节点在一段时间(例如30秒)内没有响应,则认为该节点已死。 (如果故意将领导者撤下以进行计划维护,则这不适用。)
  2. 选择一个新的leader。这可以通过一个选举进程实现(leader是被大多数的剩余的复制品选择的),或者一个新的leader可以被之前当选充当的控制器的节点controller node委派。对于leader的最佳候选者是与原来leader的数据库的更新最及时的,也就是说最小化数据丢失。
  3. 重新配置系统使用新的leader。客户端现在需要把它们的写的i请求发送给新的leader。如果老的leader回来了,它也许还会认为自己是leader,并没有意识到其他的复制品已经强制它退位让贤了。系统需要确保老的leader成为一个follower并且识别到新的leader。

故障转移也充满了可能出错的地方:

  • 如果使用了异步拷贝,那么新的leader可能在老的leader fail前没有收到所有的写的数据。如果之前的leader在之后的leader被选出来之后又重新加入了进来,那么这些写该怎么处理?新的leader也许会同时收到有冲突的写请求。最通常的做法是丢弃老的leader的还没有被拷贝的写的请求,虽然这违背了客户端对持久化的期望。
  • 如果有其他数据库之外的数据存储需要和数据库中的内容协作,那么丢弃数据是很危险的。比方说,在Github的一次事故中,一个过时的MySQLfollower被晋升为leader,数据库使用一个自增的计数器对新的行分配主键,但因为新的leader计数器落后于老的leader,它会使用一些之前已经在老leader上分配出去的主键,这些主键也在Redis的存储中使用,因此对于主键的重复使用会导致在MySQL和Redis之间的不一致,这会导致一些个人数据展示给错误的用户。
  • 在某些故障中,会发生两个节点都认为自己是leader的情形。这被称为split brain,这是很危险的:因为如果两个leader都接受写请求,那么就没有处理冲突的进程了。数据很可能丢失或者损坏。为了安全,一些系统会在侦测到两个leader时关掉其中一个。然而,如果这个机制没有被认真的设计,会导致两个节点都会被关闭。
  • 在leader被宣告死亡前,正确的超时是多少?在leader fail的情况下,更长的超时意味着更长时间的恢复。然而,如果超时过短,就会有一些非必要的故障转移。比方说,一个临时的负载尖峰就会导致一个节点的相应时间的增加,超过超时时间,或者一个网络的不稳定会导致包延迟。如果系统已经因为高负载或是网络问题表现的很挣扎,那么一次非必要的故障转移很可能会让情况更糟糕,而不是改善。

对于这些问题没有简单的解决方法。因此,即使软件支持自动故障转移,一些运维团队也更倾向于手动执行。

这些问题-节点故障不可靠的网络;在副本一致性持久性可用性延迟方面的权衡是实际上是分布式系统中的基本问题。


拷贝日志的实现

leader-based的拷贝是如何在后台运行?在实践中使用了几种不同的拷贝方法,因此让我们简要地介绍一下每种方法。

基于语句的拷贝

在最简单的情况中,leader记录每次执行的写请求(语句),然后把语句日志发送给followers。对于关系型数据库,这意味着每个INSERT、UPDATE、或是DELETE语句都会转发给followers,并且每个follower都会粘贴然后执行它,就好像是从客户端那边直接接收到的。

虽然这听起来很合理,但有许多方法可以使这个方法不可行:

  • 任何调用非确定性函数的语句,例如NOW(),以获得当前日期和时间或RAND()以获取随机数,很可能会使每个复制品上的值都不同。
  • 如果语句使用了一个自增的列,或者如果他们依赖数据库中的某些已有的数据。比如说 UPDATE ... WHERE <some condition>,那么在每个复制品上都必须以相同的顺序准确的执行,不然会有不同的效果。当有多个并发的执行事务时,会产生限制。
  • 有副作用的语句(比如说,触发器,存储的过程,用户定义的功能)可能会在每个复制品上产生不同的副作用,除非副作用是绝对确定是什么的。

关于这些问题是可能解决的,比方说,leader可以在语句被记录时用一个固定的返回值替代任何非确定性的函数调用,这样follower都可以获得相同的值了。但是,由于存在许多极端情况,因此现在通常首选其他复制方法

5.1版之前的MySQL中使用了基于语句的复制。由于它非常紧凑,因此有时仍会在今天使用,但是默认情况下,如果语句中存在任何不确定性,MySQL现在会切换到基于行的复制(后面会说道)。VoltDB使用基于语句的复制,并通过要求事务具有确定性来使其安全。

预写日志Write-ahead log(WAL)

之前的文章中我们提到过存储引擎是如何在磁盘上存储数据的,我们发现通常每次写都会附加到一个日志中:

  • 在log结构的存储引擎中(SSTable和LSM-Trees),这个日志是存储的主战场。后台会压缩日志分段和做垃圾回收。
  • 在B-tree的情况中,通过覆写单独的磁盘块,每次修改都会先预写到日志中,以便在crash后恢复一致。

上述两种情形,日志都是一个只能附加的字节序列,包含着对数据库的所有的写请求。我们可以使用完全相同的日志在另一个节点上创建一个复制品,因为除了把日志写入磁盘,leader也可以把它通过网络发送给follower。

当follower处理这个日志时,它就可以创建一个和leader完全一样的数据结构了。

这种复制方法在PostgreSQL和Oracle等中使用。主要缺点是该日志以非常低的级别描述了数据:WAL包含在哪些磁盘块中更改了哪些字节的详细信息。这使得复制与存储引擎紧密耦合。如果数据库将其存储格式从一种版本更改为另一种版本,则通常无法在数据库软件版本不同的leader和follower上运行。

这可能看起来只是次要的实现细节,但可能会对运营产生重大影响。如果复制协议允许follower使用比leader更新的软件版本,则可以通过先升级follower然后执行故障转移以使升级后的节点之一成为新领导者来执行数据库软件的零宕机时间升级。如果复制协议不允许版本不匹配(WAL的常见情况),则此类升级需要停机。

逻辑(row-based基于行的)日志复制

一种替代方法是对拷贝和存储引擎使用不同的日志格式,这允许将拷贝日志与存储引擎内部分离。这种拷贝日志称为逻辑日志,以区别于存储引擎的(物理)数据表示形式。

关系型数据库的逻辑日志通常是一系列记录,这些记录以按行的粒度描述了对数据库表的写操作:

  • 对于插入的行,日志包含所有列的新值。
  • 对于已删除的行,日志包含足够的信息以唯一地标识已删除的行。通常,这将是主键,但是如果表上没有主键,则需要记录所有列的旧值。
  • 对于更新的行,日志包含足够的信息以唯一的标识更新的行以及所有列的新值(或至少所有已更改列的新值)。

一次修改几行的事务会生成多个此类日志记录,然后是一条记录,表明该事务已提交。 MySQL的binlog(配置为使用基于行的复制时)使用这种方法。

由于逻辑日志与存储引擎内部分离,因此可以更轻松地保持向后兼容,从而使leader和follower可以运行不同版本的数据库软件,甚至运行不同的存储引擎。

逻辑日志格式也更易于外部应用程序解析。如果要将数据库的内容发送到外部系统(例如用于脱机分析或构建自定义索引和缓存的数据仓库)到外部系统,这就有很有用了。这种技术被称为change data capture

基于触发器的拷贝

到目前为止描述的复制方法是由数据库系统实现的,而无需涉及任何应用程序代码。在很多情况下,这就是您想要的。但是在某些情况下,需要更大的灵活性。例如,如果您只想复制一部分数据,或者想从一种数据库复制到另一种数据库,或者需要冲突解决逻辑,则可能需要将复制移到应用程序层。

某些工具(例如Oracle GoldenGate)可以通过读取数据库日志来使数据更改对应用程序可用。一种替代方法是使用在许多关系数型据库中可用的功能:triggers和stored procedures。

triggers使您可以注册在数据库系统中发生数据更改(写事务)时自动执行的自定义应用程序代码。触发器有机会将此更改记录到单独的表中,外部进程可以从中读取该更改。然后,该外部过程可以应用任何必要的应用程序逻辑,并将数据更改复制到另一个系统。例如,用于Oracle的Databus和用于Postgres的Bucardo就是这样工作的。

基于触发器的复制通常比其他复制方法具有更大的开销,并且比数据库的内置复制更容易出现错误和限制。但是,由于其灵活性,它可能仍然有用。

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: