概述
分布式系统设计中最关键的就是容错机制(Failure Tolerance)。这是因为通常情况下,一个客户端(Client)的请求(Request)会被发送至主服务器(Primary)上。而假如Primary挂掉了,那么该Request会被继续分散到备份服务器(Backup)上。而在攻城狮辛辛苦苦修理挂掉的服务器时,原先的Backup仍然要坚持响应Client的请求。当服务器修好后,Primary和Backup上的资料自然会不一致了,这时候如果没有一种有效地手段保证两个服务器继续保持同步状态,无疑会造成很严重的问题~
为了保证两个服务器始终处于同步状态(Sync),我们需要在Backup上实时对Primary进行复制(Replication)。Replication的方法大致分为两种:
- 状态转移:这种方法的大致思想是:Client将Request发送到Primary端,后者始终处于计算状态。同时,每隔一小段时间,后者将自己的全部状态打包发送至Backup端。一种较为理想的设计方法请参见Remus。简单来说,Remus采用了三层设计:应用层、系统层和Remus构架层。所运行的软件属于应用层,它们将运行在虚拟机,也即系统层上。最后,Remus构架层会将整个系统层的状态以一定时间间隔打包发送至Backup上,一般取25ms。该设计最大的优势在于,因为备份与软件运行的隔离,所有已经存在的软件不需要重新编写就可以获得分布式系统的全部特性。
- Replicated State Machine:这种设计的大致思想是,Client将Request发送至Primary后,Primary会将该Request抄送(Forward)到Backup端,两台服务器进行相同的运算,从而得到相同的状态。Lab2中所要求的一种最基本的分布式数据库用到的就是这种设计。
Lab2
说了那么多理论的东西,让我们来看一个简单但功能又比较齐全的例子。该例子选自MIT 6.824的Lab2,该Lab分为了A、B两部分。其中,A部分要求实现一个子系统,其功能是用一个Master服务器(在本Lab中,Master会一直十分坚挺)来负责决定哪个服务器在当前是Primary,哪个则是Backup。同时,当原先的Primary挂了后,Master要能够识别到并迅速把当前的Backup标识为新的Primary。而在B部分中,我们会设计一个数据库,它将支持Get(Key)、Put(Key, Value)及Append(Key, Value)。乍看这个貌似蛮简单的~但是,真正的难点在于,无论我们怎么折腾Primary和Backup(持续的开机、宕机循环),怎么的蹂躏这个数据库(多个Client同时并发发送Request),我们都要保证这个数据库正常的运行。怎么样,是不是有种跃跃欲试的感觉?
Lab2A
为了让叙述更