基于RAFT算法的软件系统设计方案
基于RAFT算法的软件系统设计方案
一 项目概述
Raft算法概述
Raft算法由leader节点来处理一致性问题。leader节点接收来自客户端的请求日志数据,然后同步到集群中其它节点进行复制,当日志已经同步到超过半数以上节点的时候,leader节点再通知集群中其它节点哪些日志已经被复制成功,可以提交到raft状态机中执行。
在Raft算法中,一个集群里面的所有节点有以下三种状态:
Leader:领导者,一个集群里只能存在一个Leader。
Follower:跟随者,follower是被动的,一个客户端的修改数据请求如果发送到Follower上面时,会首先由Follower重定向到Leader上,
Candidate:参与者,一个节点切换到这个状态时,将开始进行一次新的选举。
每一次开始一次新的选举时,称为一个任期。每个任期都有一个对应的整数与之关联,称为“任期号”,任期号用单词“Term”表示,这个值是一个严格递增的整数值.
raft算法将要解决的一致性问题分为了以下几个子问题:选举子问题、复制日志子问题、安全保证和故障恢复子问题。这些问题都会在下面的内容中一一解决。
二 软件设计方案接口API
func (e *ClientEnd) Call
|
不同服务器之间发起RPC远程调用的Call函数
|
func (rf *Raft) runLeader
|
领导者状态的函数
|
func (rf *Raft) runFollower
|
下属者状态的函数
|
func (rf *Raft) runCandidate()
|
候选者状态的函数
|
func (rf *Raft) AppendEntries
|
处理心跳或者日志
|
func (rf *Raft) sendAppendEntries(
|
发送心跳或者日志
|
func (rf *Raft) RequestVote
|
返回投票结果
|
func (rf *Raft) sendRequestVote
|
发起投票竞选
|
| func (rf * raft) Put | 更新数据库中的键值对 |
| func (rf *raft) Get | 返回对应Key的Value |
三 软件架构的各种视图
软件架构模型是通过一组关键视图来描述的,同一个软件架构,由于选取的视角(Perspective)和抽象层次不同可以得到不同的视图,这样一组关键视图搭配起来可以完整地描述一个逻辑自洽的软件架构模型。一般来说,我们常用的几种视图有分解视图、依赖视图、泛化视图、执行视图、实现视图、部署视图和工作任务分配视图。
分解视图
对系统的常用分解方法有面向功能分解,面向数据分解,面向特征分解,面向并发分解等,根据本项目的特点,比较适合面向角色(功能对象)分解

依赖视图
依赖视图展现了软件模块之间的依赖关系。比如一个软件模块A调用了另一个软件模块B,那么我们说软件模块A直接依赖软件模块B。如果一个软件模块依赖另一个软件模块产生的数据,那么这两个软件模块也具有一定的依赖关系。依赖视图在项目计划中有比较典型的应用。比如它能帮助我们找到没有依赖关系的软件模块或子系统,以便独立开发和测试,同时进一步根据依赖关系确定开发和测试软件模块的先后次序。依赖视图在项目的变更和维护中也很有价值,比如它能有效帮助我们理清一个软件模块的变更对其他软件模块带来影响范围

执行视图
执行视图展示了系统运行时的时序结构特点,比如流程图、时序图等。执行实体可以最终分解到软件的基本元素和软件的基本结构,
执行实体可以最终分解到软件的基本元素和软件的基本结构,因而与软件代码具有比较直接的映射关系。在设计与实现过程中,我们一般将执行视图转换为伪代码之后,再进一步转换为实现代码。
因而与软件代码具有比较直接的映射关系,本项目采用流程图描述执行视图

泛化实现视图
泛化视图展现了软件模块之间的一般化或具体化的关系,描述了软件在抽象层面上的关系,进一步展示了整个软件系统的各层架构。
本工程项目实际上,最重要的模块只有Raft模块和LabRPC模块和KV模块。此工程项目是建立在多个服务器的基础上的,不同的服务器的Raft模块会根据结点状态运行对应的功能。
不同服务器的Raft模块会根据一个当前服务器的小的数据结构决定这个服务器模块的状态,从而决定当前服务器结点的RAFT模块是运行Leader 进程,还是运行Follower进程,还是Candidate进程。
例如:状态小模块

本工程项目主要是以不同的服务器结点之间的RAFT模块的状态和通信进行分析,泛化图如下:

不同服务器结点的模块主要通过调用LabRPC模块进行通信:例如A服务器的RAFT(Leader)模块要和B服务器的RAFT(Follower)模块进行通信要调用如下LABRPC模块
RPC模块根据不同的关键词AppendEntry或者RequestVote向对应的CALL调用的进行相对的选择回复,上面泛化图的通信的RPC调用泛化图如下:

部署视图
部署视图是将执行实体和计算机资源建立映射关系。这里的执行实体的粒度要与所部署的计算机资源相匹配,比如以进程作为执行实体,那么对应的计算机资源就是主机,这时应该描述进程对应主机所组成的网络拓扑结构,这样可以清晰地呈现进程间的网络通信和部署环境的网络结构特点。当然也可以用细粒度的执行实体对应处理器、存储器等。部署视图有助于设计人员分析一个设计的质量属性,比如软件处理网络高并发的能力、软件对处理器的计算需求等。,更好的设计通信线路。
部署视图如下:(下面的箭头代表了只有箭头指向的目的体才能收到对应源体发来的信息。)

工作分配视图
工作分配视图将系统分解成可独立完成的工作任务,以便分配给各项目团队和成员。工作分配视图有利于跟踪不同项目团队和成员的工作任务的进度,也有利于在个项目团队和成员之间合理地分配和调整项目资源,甚至在项目计划阶段工作分配视图对于进度规划、项目评估都非常由帮助!工作分配视图如下:

本次项目由我和同学共同开发,舍友A负责领导者模块代码,我负责追随者模块代码,舍友C负责候选者模块代码,然后大家共同完成LABRPC模块的代码。
实现视图
实现视图是描述软件架构和源文件之间的映射关系。比如软件架构的静态结构以包图或设计类图的方式来描述,但是这些包和类都是在哪些目录的哪些源文件中具体实现的呢?一般我们通过目录和源文件的命名来对应软件架构中的包、类等静态结构单元,这样典型的实现视图可以由软件项目的源文件目录树来呈现。实现视图有助于码农在海量源代码文件中找到具体的某个软件单元的实现。实现视图与软件架构的静态结构之间映射关系越是对应的一致性高,越是有利于软件的维护,因此实现视图是一种非常关键的架构视图。
实现视图如下:(关键模块用红线框了起来)




四 数据库设计
无.RAFT算法就是为了维护数据库的一致性和保证统一的而开发的一致性系统。
五 系统概念的核心工作机制
概念模型
概念是人对能代表某种事物或发展过程的特点及意义所形成的思维结论。
概念原型是一种虚拟的、理想化的软件产品形式
核心工作机制,本项目的核心除了在于三个不同的角色状态之外,另外一个核心就是表现是不同的时序所出现的不同的工作阶段。
RAFT算法主要分三个阶段:(这三个阶段是可能会循环往复的)
选举阶段一:
Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时,初始化为Follower。Leader向所有Followers周期性发送heartbeat。
如果Follower在选举超时时间内没有收到Leader的heartbeat,就会等待一段随机的时间后发起一次Leader选举。顺序如下:
1、A、B主机向C主机投票请求,A先到达,C同意A成为领导,那么A投的是自己的一票,A成为领导,A向B C主机发送心跳。
2、B收到A的领导的心跳,,表示有其它服务器成为Leader,,从Candidate状态退成Follower者。
3、如果选举阶段,没有服务器赢得多数的投票,等待选举超时,继续下一轮选举。
正常工作阶段二(日志发送和日志同步):
Leader的工作:Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,
然后并行的向其他服务器发起 AppendEntries RPC,复制日志条目。当这条日志被复制到大多数服务器上,Leader将这条日志应用到它的状态机并向客户端返回执行结果。
某些Followers可能没有成功的复制日志,Leader会无限的重试 AppendEntries RPC直到所有的Followers最终存储了所有的日志条目。
日志同步保证如下两点:如果不同日志中的两个条目有着相同的索引和任期号,则它们所存储的命令是相同的。如果不同日志中的两个条目有着相同的索引和任期号,则它们之前的所有条目都是完全一样的。
Follower的工作:接收领导的心跳,保持Follower状态
心跳超时或者出现故障以及故障恢复阶段三:
心跳超时问题:
1、若Follower等待Leader的心跳超时,因为Leader可能宕机了,那么部分Follower又会发起投票竞选了,成为Candidate,此时又返回到了选举阶段。
故障问题:
1、若出现Candidate请求的做领导的任期Term不一样的情况。此时选择最新的请求的Term最新的那一个Candidate节点服务器做领导。
2、若出现出现Candidate请求的做领导的任期Term一样而且到达时间一模一样,就选择具有最新的日志的记录的Candidate做领导。
3、就是部分Follower节点的对在某一个顺序上的日志的任期的和其他节点顺序上的不一样,可能还收到了上一任任期的领导节点的日志,出现了错误。那么新任期的领导者需要再次日志给所有节点去重新对客户端发来的请求,再做一次一致性的日志完成再返回客户
六 软件系统运行环境和技术选型:
本项目使用了Goland开发工具,以golang为开发语言。可使用Docker打包运行在任何Linux服务器上。
Docker
Docker 容器是一个开源的应用容器引擎,让开发者可以以统一的方式打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何安装了docker引擎的服务器上(包括流行的Linux机器、windows机器),也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架包括系统
七 总结
通过这一次课后作业,我学会了一个完整的软件工程项目的建立过程中各种视图的绘图,各种视图对于软件开发起到了举轻若重的作用,非常有利于我们的项目开发,有利于项目的人员分配,项目的层次剖析,项目的流程实现,项目的模块分解和依赖联系的建立。
浙公网安备 33010602011771号