【转载——两个很基础的选举算法】分布式系统进程的选举

在分布式系统中,为了协调一组进程的动作,我们常常需要一个进程扮演协调者、初始者或管理者的角色。这个进程可以是进程组的任何一个,但关键的是进程组必须选举出唯一一个而且必须达到共识。

如果所有的进程都完全一样,它们之间没有任何可区别的属性,那么也就没有办法选举出一个特别的进程。因此,我们假设进程有一个全局唯一的编号,这个编号可以是网络地址或其他方法产生的编号。不失一般性,我们可以假设选举算法总是选举编号最大的进程作为协调进程。

我们另外还假设,每个进程都知道组内其他进程的编号。如果最大编号的进程总是在运行中并且总是能够担当协调者的角色,那么选举就变成了指派。选举算法需要考虑的是,当最大编号的进程因为这样和那样的原因不能成为协调者时,选举过程才会发生。我们称它为一个进程召集选举。

如果一个进程启动了选举算法的一次执行,且每次只能启动一次召集选举的过程,则原则上有 n 个进程的分布式系统可以并发地召集 n 次选举。算法的一个基本要求是对当选进程的选择必须是唯一的,即使有多个并发的召集过程在执行,最后的结果必须保证所有召集选举和参与选举的进程对当选的进程达成共识。

霸道算法

Garcia-Monila 在 1982 年的一篇论文中发明了所谓的霸道选举算法(Bully Algorithm)。当一个进程 P 发现协调者进程不再响应时,这个进程就召集选举。由于进程的独立性,在同一个时刻,系统中可能有多个召集选举的过程。假设 P 是召集选举的进程,每个召集选举的过程如下:

  1. P 向所有比自己编号大的进程发送一条 ELECTION(选举)消息。
  2. 如果 P 得不到任何回复,则 P 赢得选举,P 向所有进程发送 COORDINATOR(协调者)消息,宣布自己的胜利。
  3. 如果 P 得到任何一个回复,回复一定来自于比自己编号大的进程。P 的召集选举的工作结束,因为 P 此时已经不可能赢得选举。

其他进程或正在召集选举,或可能接收到比自己编号小的进程的 ELECTION 消息。当它收到一个 ELECTION 后,它回复一个 OK 消息给发送消息的进程;如果这时它还不是召集选举的进程,它也将开始一个召集选举的过程,即执行 1 到 3 的操作。
拥有最大编号的进程不召集选举,它直接发送 COORDINATOR 消息宣布胜利,霸道算法的名字由此得来。

环选举算法

关于选举的另一个著名算法是基于进程环的机制设计的。与一般的环算法不同的是,环选举算法并不使用令牌。在这个算法中,我们假设所有进程能够在物理上或逻辑上组成一个环结构,每个进程都保留一个按进程编号逻辑排序的一个表,因此知道自己的所有后继进程。

算法的过程非常简单。当一个进程 P 注意到协调者进程不再工作时,它将启动一个召集选举的过程:

  1. 进程 P 构造一个包含自己进程编号的 ELECTION 给后继进程,如果直接后继进程没有响应,进程 P 就将消息发送给环上的下一个进程,直到找到一个正常运行的进程。
  2. 接收到 ELECTION 消息的进程将自己的编号增加到 ELECTION 消息中,然后按照同样的方式将消息发送给后继进程。这样,消息在环上的传递将构造一个包含所有正常运行的进程的编号表。
  3. 当 ELECTION 消息最后回到召集选举的进程时,消息中最大编号的进程即成为选举的胜利者。召集选举的进程将消息类型改为 COORDINATOR,然后将消息沿着环重新发送一次,将选举结果通知所有的进程。
  4. 当 COORDINATOR 消息重新回到召集选举的进程时,算法终止。

同样,在环选举算法中,也可能同时存在多个召集选举的过程。当在这个时刻环结构不变时,最后的结果也是一致的,只是消息数量多一些,并无大碍。

关于选举算法的讨论

霸道选举算法和环选举算法都依赖一系列苛刻的假设:

  1. 假设了可靠的通道通信,更进一步的假设是系统中任何两个进程之间都可以通信。
  2. 每个进程都知道其他进程的编号,也就是说算法依赖一个全局的数据。
  3. 在多个并发召集选举的过程中,进程组的正常进程数量保持稳定,而且在环选举算法中,环结构也必须稳定。
  4. 假设进程能够明确地判断出一个正常运行的进程和一个已经崩溃的进程。

有很多放宽假设条件下如何改进算法的讨论,但就算法的应用来说,召集选举的过程不应该是很频繁的,参与选举的进程数量和结构应该是相对稳定的。我们看不到频繁故障下的频繁选举的应用价值。因此,虽然算法的适用条件比较苛刻,但它们基本能够满足应用的需求。

时间: 2024-08-31 17:58:50

【转载——两个很基础的选举算法】分布式系统进程的选举的相关文章

java-Java一个很基础的面试题【求助】

问题描述 Java一个很基础的面试题[求助] public class Apple extends Fruit { private String name = "apple"; public Apple () { tellName(); printName(); } public void tellName() { System.out.println("Apple tell name: " + name); } public void printName() {

C#的一个关于继承很基础但又很让我不解的问题。。。

问题描述 C#的一个关于继承很基础但又很让我不解的问题... class Program { static void Main(string[] args) { Person p = new Student(); Console.WriteLine(p.GetType()); p.SayHi(); Console.ReadKey(); } class Person { public void SayHi() { Console.WriteLine("我是人类"); } } class

《算法基础:打开算法之门》一3.6 小结

3.6 小结 在本章和上一章中,我们已经看到了关于查找的4个算法和关于排序的4个算法.我们将它们的特性总结在以下两个表中.因为第2章的3个查找算法仅仅是关于同一个题目的变形,我们将BETTERLINEARSEARCH或SENTINELLINEARSEARCH作为线性查找的代表均可. 这两个表中没有显示平均情况下的运行时间,因为除了典型的快速排序外,其他算法的平均情况下的运行时间均与最坏情况下的运行时间一致.我们已经学习了,当数组元素按顺序随机产生时,快速排序平均情况下的运行时间仅仅是Θ(

java 关于扩展类 很基础的一个 刚接触java求指导

问题描述 java 关于扩展类 很基础的一个 刚接触java求指导 已经有了一个类 public class Person{ } 之后又有一个Person类的扩展类Student类 那么在 eslipse中编写程序时 是有两个类 对吧?那扩展类Student需要如何创建这个类啊? 解决方案 首先在eclipse中新建两个类,在其中一个类中写main方法写测试代码.测试要依据你的需求看怎么测了. 解决方案二: public Student extends Person{ //extends继承 }

两个很详细的shell 实例代码_其它

两个很详细的shell 实例 一般编程步骤 现在我们来讨论编写一个脚本的一般步骤.任何优秀的脚本都应该具有帮助和输入参数.并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意.这时候,在写一个新的脚本时我们只需要执行一下copy命令: cp framework.sh myscript 然后再插入自己的函数. 让我们再看两个例子: 二进制到十进制的转换 脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数.这也是一个用expr命令

字符串-一个很基础的返回值问题

问题描述 一个很基础的返回值问题 想要打印字符串数组,去掉中间的空格和Tab,并且删除全为空的行,哪里有错?谢谢. #include #define MAXLINE 1000 int getline(char line[], int maxline); int copy(char to[],char from[]); int main(){ int len; int max; char line[MAXLINE]; max=0; while ((len=getline(line,MAXLINE)

要求时间复杂度为O(n)的求两个位置之间最大值的算法

问题描述 要求时间复杂度为O(n)的求两个位置之间最大值的算法 把一串数(32位int型)放到Num中,求begin和end位置使得begin与end之间的是数字和最大,要求时间复杂度是O(n). 注:不可以先排序,这串数字的位置不能改变. 最好有源码,思路也可以. 解决方案 #include #include int getmax(int first, int second) { return first > second ? first : second; } int main() { in

任意两个多边形求并的算法并用编程实现

问题描述 任意两个多边形求并的算法并用编程实现 任意两个多边形求并的算法并用编程实现 任意两个多边形求并的算法并用编程实现 解决方案 求任意多边形的内点的算法 解决方案二: 不知道求并什么意思?是面积还是什么?面积的话两者相加减去更公共部分就可以了. 解决方案三: 不知道具体要求什么 ....

io流-一道很基础的题,卡住了,求解

问题描述 一道很基础的题,卡住了,求解 题目为:1.读取本地文件message.txt,输入年份,输出当年的世界杯举办国以及冠军国,如果该年份没有举办世界杯,请输出"没有举办". System.in--->year:1931 读出来:存Map集合 1930 乌拉圭|乌拉圭 1934 意大利|意大利 解决方案 用filestream读取,split分隔装入hashmap 解决方案二: 基础的一道题分享一道java基础题,测测你是不是基础扎实一道用冒泡排序做数组的题,求解