mirror of
https://github.com/Vonng/ddia.git
synced 2024-12-06 15:20:12 +08:00
故障转移->故障切换
This commit is contained in:
parent
f8378a38a3
commit
b16a60d7f1
2
ch11.md
2
ch11.md
@ -676,7 +676,7 @@ GROUP BY follows.follower_id
|
||||
|
||||
Storm的Trident基于类似的想法来处理状态【78】。依赖幂等性意味着隐含了一些假设:重启一个失败的任务必须以相同的顺序重放相同的消息(基于日志的消息代理能做这些事),处理必须是确定性的,没有其他节点能同时更新相同的值【98,99】。
|
||||
|
||||
当从一个处理节点故障转移到另一个节点时,可能需要进行**防护(fencing)**(参阅“[领导和锁](ch8.md#领导和锁)”),以防止被假死节点干扰。尽管有这么多注意事项,幂等操作是一种实现**恰好一次语义**的有效方式,仅需很小的额外开销。
|
||||
当从一个处理节点故障切换到另一个节点时,可能需要进行**防护(fencing)**(参阅“[领导和锁](ch8.md#领导和锁)”),以防止被假死节点干扰。尽管有这么多注意事项,幂等操作是一种实现**恰好一次语义**的有效方式,仅需很小的额外开销。
|
||||
|
||||
#### 失败后重建状态
|
||||
|
||||
|
18
ch5.md
18
ch5.md
@ -96,17 +96,17 @@
|
||||
|
||||
在其本地磁盘上,每个从库记录从主库收到的数据变更。如果从库崩溃并重新启动,或者,如果主库和从库之间的网络暂时中断,则比较容易恢复:从库可以从日志中知道,在发生故障之前处理的最后一个事务。因此,从库可以连接到主库,并请求在从库断开连接时发生的所有数据变更。当应用完所有这些变化后,它就赶上了主库,并可以像以前一样继续接收数据变更流。
|
||||
|
||||
#### 主库失效:故障转移
|
||||
#### 主库失效:故障切换
|
||||
|
||||
主库失效处理起来相当棘手:其中一个从库需要被提升为新的主库,需要重新配置客户端,以将它们的写操作发送给新的主库,其他从库需要开始拉取来自新主库的数据变更。这个过程被称为**故障转移(failover)**。
|
||||
主库失效处理起来相当棘手:其中一个从库需要被提升为新的主库,需要重新配置客户端,以将它们的写操作发送给新的主库,其他从库需要开始拉取来自新主库的数据变更。这个过程被称为**故障切换(failover)**。
|
||||
|
||||
故障转移可以手动进行(通知管理员主库挂了,并采取必要的步骤来创建新的主库)或自动进行。自动故障转移过程通常由以下步骤组成:
|
||||
故障切换可以手动进行(通知管理员主库挂了,并采取必要的步骤来创建新的主库)或自动进行。自动故障切换过程通常由以下步骤组成:
|
||||
|
||||
1. 确认主库失效。有很多事情可能会出错:崩溃,停电,网络问题等等。没有万无一失的方法来检测出现了什么问题,所以大多数系统只是简单使用**超时(Timeout)**:节点频繁地相互来回传递消息,并且如果一个节点在一段时间内(例如30秒)没有响应,就认为它挂了(因为计划内维护而故意关闭主库不算)。
|
||||
2. 选择一个新的主库。这可以通过选举过程(主库由剩余副本以多数选举产生)来完成,或者可以由之前选定的**控制器节点(controller node)**来指定新的主库。主库的最佳人选通常是拥有旧主库最新数据副本的从库(最小化数据损失)。让所有的节点同意一个新的领导者,是一个**共识**问题,将在[第9章](ch9.md)详细讨论。
|
||||
3. 重新配置系统以启用新的主库。客户端现在需要将它们的写请求发送给新主库(将在“[请求路由](ch6.md#请求路由)”中讨论这个问题)。如果老领导回来,可能仍然认为自己是主库,没有意识到其他副本已经让它下台了。系统需要确保老领导认可新领导,成为一个从库。
|
||||
|
||||
故障转移会出现很多大麻烦:
|
||||
故障切换会出现很多大麻烦:
|
||||
|
||||
* 如果使用异步复制,则新主库可能没有收到老主库宕机前最后的写入操作。在选出新主库后,如果老主库重新加入集群,新主库在此期间可能会收到冲突的写入,那这些写入该如何处理?最常见的解决方案是简单丢弃老主库未复制的写入,这很可能打破客户对于数据持久性的期望。
|
||||
|
||||
@ -116,9 +116,9 @@
|
||||
|
||||
[^ii]: 这种机制称为**屏蔽(fencing)**,充满感情的术语是:**爆彼之头(Shoot The Other Node In The Head, STONITH)**。
|
||||
|
||||
* 主库被宣告死亡之前的正确超时应该怎么配置?在主库失效的情况下,超时时间越长,意味着恢复时间也越长。但是如果超时设置太短,又可能会出现不必要的故障转移。例如,临时负载峰值可能导致节点的响应时间超时,或网络故障可能导致数据包延迟。如果系统已经处于高负载或网络问题的困扰之中,那么不必要的故障切换可能会让情况变得更糟糕。
|
||||
* 主库被宣告死亡之前的正确超时应该怎么配置?在主库失效的情况下,超时时间越长,意味着恢复时间也越长。但是如果超时设置太短,又可能会出现不必要的故障切换。例如,临时负载峰值可能导致节点的响应时间超时,或网络故障可能导致数据包延迟。如果系统已经处于高负载或网络问题的困扰之中,那么不必要的故障切换可能会让情况变得更糟糕。
|
||||
|
||||
这些问题没有简单的解决方案。因此,即使软件支持自动故障切换,不少运维团队还是更愿意手动执行故障转移。
|
||||
这些问题没有简单的解决方案。因此,即使软件支持自动故障切换,不少运维团队还是更愿意手动执行故障切换。
|
||||
|
||||
节点故障、不可靠的网络、对副本一致性,持久性,可用性和延迟的权衡 ,这些问题实际上是分布式系统中的基本问题。[第8章](ch8.md)和[第9章](ch9.md)将更深入地讨论它们。
|
||||
|
||||
@ -153,7 +153,7 @@
|
||||
|
||||
PostgreSQL和Oracle等使用这种复制方法【16】。主要缺点是日志记录的数据非常底层:WAL包含哪些磁盘块中的哪些字节发生了更改。这使复制与存储引擎紧密耦合。如果数据库将其存储格式从一个版本更改为另一个版本,通常不可能在主库和从库上运行不同版本的数据库软件。
|
||||
|
||||
看上去这可能只是一个微小的实现细节,但却可能对运维产生巨大的影响。如果复制协议允许从库使用比主库更新的软件版本,则可以先升级从库,然后执行故障转移,使升级后的节点之一成为新的主库,从而执行数据库软件的零停机升级。如果复制协议不允许版本不匹配(传输WAL经常出现这种情况),则此类升级需要停机。
|
||||
看上去这可能只是一个微小的实现细节,但却可能对运维产生巨大的影响。如果复制协议允许从库使用比主库更新的软件版本,则可以先升级从库,然后执行故障切换,使升级后的节点之一成为新的主库,从而执行数据库软件的零停机升级。如果复制协议不允许版本不匹配(传输WAL经常出现这种情况),则此类升级需要停机。
|
||||
|
||||
#### 逻辑日志复制(基于行)
|
||||
|
||||
@ -325,7 +325,7 @@
|
||||
|
||||
***容忍数据中心停机***
|
||||
|
||||
在单主配置中,如果主库所在的数据中心发生故障,故障转移可以使另一个数据中心里的追随者成为领导者。在多活配置中,每个数据中心可以独立于其他数据中心继续运行,并且当发生故障的数据中心归队时,复制会自动赶上。
|
||||
在单主配置中,如果主库所在的数据中心发生故障,故障切换可以使另一个数据中心里的追随者成为领导者。在多活配置中,每个数据中心可以独立于其他数据中心继续运行,并且当发生故障的数据中心归队时,复制会自动赶上。
|
||||
|
||||
***容忍网络问题***
|
||||
|
||||
@ -479,7 +479,7 @@
|
||||
|
||||
[^vi]: Dynamo不适用于Amazon以外的用户。 令人困惑的是,AWS提供了一个名为DynamoDB的托管数据库产品,它使用了完全不同的体系结构:它基于单引导程序复制。
|
||||
|
||||
在一些无领导者的实现中,客户端直接将写入发送到到几个副本中,而另一些情况下,一个**协调者(coordinator)**节点代表客户端进行写入。但与主库数据库不同,协调员不执行特定的写入顺序。我们将会看到,这种设计上的差异对数据库的使用方式有着深远的影响。
|
||||
在一些无领导者的实现中,客户端直接将写入发送到到几个副本中,而另一些情况下,一个**协调者(coordinator)**节点代表客户端进行写入。但与主库数据库不同,协调者不执行特定的写入顺序。我们将会看到,这种设计上的差异对数据库的使用方式有着深远的影响。
|
||||
|
||||
### 当节点故障时写入数据库
|
||||
|
||||
|
2
ch7.md
2
ch7.md
@ -207,7 +207,7 @@ SELECT COUNT(*)FROM emails WHERE recipient_id = 2 AND unread_flag = true
|
||||
|
||||
- 如果事务实际上成功了,但是在服务器试图向客户端确认提交成功时网络发生故障(所以客户端认为提交失败了),那么重试事务会导致事务被执行两次——除非你有一个额外的应用级除重机制。
|
||||
- 如果错误是由于负载过大造成的,则重试事务将使问题变得更糟,而不是更好。为了避免这种正反馈循环,可以限制重试次数,使用指数退避算法,并单独处理与过载相关的错误(如果允许)。
|
||||
- 仅在临时性错误(例如,由于死锁,异常情况,临时性网络中断和故障转移)后才值得重试。在发生永久性错误(例如,违反约束)之后重试是毫无意义的。
|
||||
- 仅在临时性错误(例如,由于死锁,异常情况,临时性网络中断和故障切换)后才值得重试。在发生永久性错误(例如,违反约束)之后重试是毫无意义的。
|
||||
- 如果事务在数据库之外也有副作用,即使事务被中止,也可能发生这些副作用。例如,如果你正在发送电子邮件,那你肯定不希望每次重试事务时都重新发送电子邮件。如果你想确保几个不同的系统一起提交或放弃,**二阶段提交(2PC, two-phase commit)** 可以提供帮助(“[原子提交和两阶段提交(2PC)](ch9.md#原子提交与二阶段提交(2PC))”中将讨论这个问题)。
|
||||
- 如果客户端进程在重试中失效,任何试图写入数据库的数据都将丢失。
|
||||
|
||||
|
2
ch8.md
2
ch8.md
@ -16,7 +16,7 @@
|
||||
|
||||
[TOC]
|
||||
|
||||
最近几章中反复出现的主题是,系统如何处理错误的事情。例如,我们讨论了**副本故障转移**(“[处理节点中断](#ch5.md#处理节点宕机)”),**复制延迟**(“[复制延迟问题](ch6.md#复制延迟问题)”)和事务控制(“[弱隔离级别](ch7.md#弱隔离级别)”)。当我们了解可能在实际系统中出现的各种边缘情况时,我们会更好地处理它们。
|
||||
最近几章中反复出现的主题是,系统如何处理错误的事情。例如,我们讨论了**副本故障切换**(“[处理节点中断](#ch5.md#处理节点宕机)”),**复制延迟**(“[复制延迟问题](ch6.md#复制延迟问题)”)和事务控制(“[弱隔离级别](ch7.md#弱隔离级别)”)。当我们了解可能在实际系统中出现的各种边缘情况时,我们会更好地处理它们。
|
||||
|
||||
但是,尽管我们已经谈了很多错误,但之前几章仍然过于乐观。现实更加黑暗。我们现在将悲观主义最大化,假设任何可能出错的东西**都会**出错[^i]。(经验丰富的系统运维会告诉你,这是一个合理的假设。如果你问得好,他们可能会一边治疗心理创伤一边告诉你一些可怕的故事)
|
||||
|
||||
|
8
ch9.md
8
ch9.md
@ -17,7 +17,7 @@
|
||||
|
||||
现在我们将继续沿着同样的路线前进,寻求可以让应用忽略分布式系统部分问题的抽象概念。例如,分布式系统最重要的抽象之一就是**共识(consensus)**:**就是让所有的节点对某件事达成一致**。正如我们在本章中将会看到的那样,尽管存在网络故障和流程故障,可靠地达成共识是一个令人惊讶的棘手问题。
|
||||
|
||||
一旦达成共识,应用可以将其用于各种目的。例如,假设你有一个单主复制的数据库。如果主库挂点,并且需要故障转移到另一个节点,剩余的数据库节点可以使用共识来选举新的领导者。正如在“[处理节点宕机](ch5.md#处理节点宕机)”中所讨论的那样,重要的是只有一个领导者,且所有的节点都认同其领导。如果两个节点都认为自己是领导者,这种情况被称为**脑裂(split brain)**,且经常导致数据丢失。正确实现共识有助于避免这种问题。
|
||||
一旦达成共识,应用可以将其用于各种目的。例如,假设你有一个单主复制的数据库。如果主库挂点,并且需要故障切换到另一个节点,剩余的数据库节点可以使用共识来选举新的领导者。正如在“[处理节点宕机](ch5.md#处理节点宕机)”中所讨论的那样,重要的是只有一个领导者,且所有的节点都认同其领导。如果两个节点都认为自己是领导者,这种情况被称为**脑裂(split brain)**,且经常导致数据丢失。正确实现共识有助于避免这种问题。
|
||||
|
||||
在本章后面的“[分布式事务和共识](#分布式事务和共识)”中,我们将研究解决共识和相关问题的算法。但首先,我们首先需要探索可以在分布式系统中提供的保证和抽象的范围。
|
||||
|
||||
@ -210,7 +210,7 @@
|
||||
|
||||
[^iv]: 对单领域数据库进行分区(分片),以便每个分区有一个单独的领导者,不会影响线性一致性,因为线性一致性只是对单一对象的保证。 交叉分区事务是一个不同的问题(参阅“[分布式事务和共识](#分布式事务和共识)”)。
|
||||
|
||||
从主库读取依赖一个假设,你确定领导是谁。正如在“[真理在多数人手中](ch8.md#真理被多数人定义)”中所讨论的那样,一个节点很可能会认为它是领导者,而事实上并非如此——如果具有错觉的领导者继续为请求提供服务,可能违反线性一致性【20】。使用异步复制,故障转移时甚至可能会丢失已提交的写入(参阅“[处理节点宕机](ch5.md#处理节点宕机)”),这同时违反了持久性和线性一致性。
|
||||
从主库读取依赖一个假设,你确定领导是谁。正如在“[真理在多数人手中](ch8.md#真理被多数人定义)”中所讨论的那样,一个节点很可能会认为它是领导者,而事实上并非如此——如果具有错觉的领导者继续为请求提供服务,可能违反线性一致性【20】。使用异步复制,故障切换时甚至可能会丢失已提交的写入(参阅“[处理节点宕机](ch5.md#处理节点宕机)”),这同时违反了持久性和线性一致性。
|
||||
|
||||
***共识算法(线性一致)***
|
||||
|
||||
@ -468,7 +468,7 @@
|
||||
|
||||
如果你的程序只运行在单个CPU核上,那么定义一个操作全序是很容易的:可以简单地就是CPU执行这些操作的顺序。但是在分布式系统中,让所有节点对同一个全局操作顺序达成一致可能相当棘手。在上一节中,我们讨论了按时间戳或序列号进行排序,但发现它还不如单主复制给力(如果你使用时间戳排序来实现唯一性约束,而且不能容忍任何错误)。
|
||||
|
||||
如前所述,单主复制通过选择一个节点作为主库来确定操作的全序,并在主库的单个CPU核上对所有操作进行排序。接下来的挑战是,如果吞吐量超出单个主库的处理能力,这种情况下如何扩展系统;以及,如果主库失效(“[处理节点宕机](#处理节点宕机)”),如何处理故障转移。在分布式系统文献中,这个问题被称为**全序广播(total order broadcast)**或**原子广播(atomic broadcast)**[^ix]【25,57,58】。
|
||||
如前所述,单主复制通过选择一个节点作为主库来确定操作的全序,并在主库的单个CPU核上对所有操作进行排序。接下来的挑战是,如果吞吐量超出单个主库的处理能力,这种情况下如何扩展系统;以及,如果主库失效(“[处理节点宕机](#处理节点宕机)”),如何处理故障切换。在分布式系统文献中,这个问题被称为**全序广播(total order broadcast)**或**原子广播(atomic broadcast)**[^ix]【25,57,58】。
|
||||
|
||||
[^ix]: “原子广播”是一个传统的术语,非常混乱,而且与“原子”一词的其他用法不一致:它与ACID事务中的原子性没有任何关系,只是与原子操作(在多线程编程的意义上 )或原子寄存器(线性一致存储)有间接的联系。全序广播是另一个同义词。
|
||||
|
||||
@ -809,7 +809,7 @@
|
||||
|
||||
答案取决于如何选择领导者。如果主库是由运维人员手动选择和配置的,那么你实际上拥有一种**独裁类型**的“共识算法”:只有一个节点被允许接受写入(即决定写入复制日志的顺序),如果该节点发生故障,则系统将无法写入,直到运维手动配置其他节点作为主库。这样的系统在实践中可以表现良好,但它无法满足共识的**终止**属性,因为它需要人为干预才能取得**进展**。
|
||||
|
||||
一些数据库会自动执行领导者选举和故障转移,如果旧主库失效,会提拔一个从库为新主库(参见“[处理节点宕机](ch5.md#处理节点宕机)”)。这使我们向容错的全序广播更进一步,从而达成共识。
|
||||
一些数据库会自动执行领导者选举和故障切换,如果旧主库失效,会提拔一个从库为新主库(参见“[处理节点宕机](ch5.md#处理节点宕机)”)。这使我们向容错的全序广播更进一步,从而达成共识。
|
||||
|
||||
但是还有一个问题。我们之前曾经讨论过脑裂的问题,并且说过所有的节点都需要同意是谁领导,否则两个不同的节点都会认为自己是领导者,从而导致数据库进入不一致的状态。因此,选出一位领导者需要共识。但如果这里描述的共识算法实际上是全序广播算法,并且全序广播就像单主复制,而单主复制需要一个领导者,那么...
|
||||
|
||||
|
@ -118,9 +118,9 @@
|
||||
|
||||
|
||||
|
||||
### 故障转移(failover)
|
||||
### 故障切换(failover)
|
||||
|
||||
在具有单一领导者的系统中,故障转移是将领导角色从一个节点转移到另一个节点的过程。请参阅第156页的“处理节点故障”。
|
||||
在具有单一领导者的系统中,故障切换是将领导角色从一个节点转移到另一个节点的过程。请参阅第156页的“处理节点故障”。
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user