基于Raft的分布式KV数据库

乌有先生ii 2021-12-26 18:24:49

项目背景

随着信息时代互联网中的数据呈爆炸式增长,这对数据的存储以及服务端的性能发出了巨大的挑战,传统的单机架构已经远远不能承受现在的访问量以及数据量。为了能够存储现在互联网中的数据,分布式存储已经是一种趋势。传统的存储已经越来越不能适应当今高并发的请求,而分布式系统在可靠性、扩展性以及性能等方面具有无可比拟的优势。分布式存储服务属于应用级的缓存服务,其管理的数据以及资源都分散在多个主机节点上,节点之间通过计算机网络相连组成的存储服务。当前分布式存储服务的研究和应用以及协议方面的探索已成为业界的热点。

国内外专家学者对分布式存储服务及其体系结构的研究日趋成熟,成果丰硕,设计实现了许多各具特色的成熟产品,例如Zookeeper、Chubby等,广泛应用与不同领域的生产实践中。这些分布式存储服务都需要有一致性算法的理论支撑,但在设计细节上应用了很多独特的新技术,保障了很好的可靠性、扩展性和性能。

本项目主要研究如何实现一个完整的Raft协议,根据自己实现的Raft,写一个KV数据库。同时实现 Raft 协议的 Snapshot RPC。为自己的KV数据库实现Sharding的功能。同时实现 multi Raft。

工程意义

分布式存储服务是现代应用为了提高其性能、可靠性、容错性的一种常见的技术手段,而对于存储服务的实现却对开发者提出了很大的挑战。开发者在开发自己的第三方应用程序时,如果还需要实现存储服务的细节,这势必会增大开发者开发应用程序的难度,并且会拖慢开发进度,所以一款封装了内部实现细节,而只暴露给开发者简单的接口的分布式存储服务对应用的开发显得非常重要。

本课题设计的分布式存储服务就把数据的一致性、可靠性等都封装在服务的内部,对开发者提供了友好的API,让开发者专注于应用的开发而不必担心底层数据存储的实现细节。

总体需求

传统的存储服务已经不能很好的满足不同用户的应用日益增长的存储需求,借助一致性算法构建分布式服务,提供多样化的存储接口供其他用户或第三方应用使用的服务越来越受到用户的青睐。本课题提出的分布式服务旨在基于分布式一致性算法的基础上为不同用户和第三方应用提供多样化的存储服务。在对用户需求进行分析,以及综合一致性算法的特点后,确定出本存储服务的功能主要从以下几个目标着手。

(1)保证数据的一致性:一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意节点读取到的数据都是最新的状态。具体实现就是在客户端将数据写入到主节点后,要立即将数据同步到从节点。在没有同步之前,不会返回操作成功的信息,只有当数据同步到了大部分的节点后,才会返回成功的信息。对于并发的请求,主节点会对其进行串行的处理,这样能保证数据的一致性。在保证一致性后,系统会有如下的特点:1.由于存在数据同步的过程,写操作的响应会有一定的延迟。2.为了保证数据一致性会对资源暂时锁定,待数据同步完成后释放锁定资源。3.如果请求数据同步失败的结点则会返回错误信息,一定不会返回旧数据。

(2)保证分区容忍性。通常分布式系统的各个结点部署在不同的子网,这就是网络分区,不可避免的会出现由于网络问题而导致结点之间通信失败,此时仍可对外提供服务,这叫分区容忍性。分区容忍性是分布式系统的基本特点。

功能需求

主要的工作点是底层数据一致性,集群可靠性的保障,在这基础之上对用户提供了操作存储服务的接口,所以目前对于用户所提供的功能是GET、PUT、APPEND操作。用例图如下所示

image-20211226180339437

对象交互建模(剧情描述)

本课题主要实现的几个点主要包括leader选举、日志复制、持久化、KV存储服务、日志压缩。前三个点是对raft的实现,在经过这几个步骤后,就搭建起了一个可以运行的raft集群,能够保证数据的一致性与集群的可靠性。

raft中的每个结点都有三个状态leader、follower、candidate。选举的状态转换如下图

image-20211226180448931

5.1 leader选举

  1. 初始化raft的状态,节点初始为follower

  2. 若发生electionTimer超时,则使用convert函数转为candidate

  3. 进行选举

  4. 对rf.peers的每一台机器都发送投票请求,携带args和reply

  5. RequestVote RPC对发送过来的请求进行回应

  6. 如果当前这台机器的term大于arg.term 或者 votefFor != -1 (即已经投票了)。 则返回false

  7. 否则投票给args中的candidate,并重置electionTimer。

  8. candidate判断对当前的server是否获得选票成功

  9. 如果成功,则将所得票数+1,并判断是否能够转为leader

  10. 如果不成功,则判断是否当前的term小于server的term。看是否要转为follower

5.2日志复制

  1. leader给每一个follower发送append Entries包

  2. 计算当前要发送的follower的preLogIndex。

  3. 构造AppendEntriesArgs

  4. 使用RPC发送

  5. 如果发送成功了,则更新对应的MathIndex和nextIndex

  6. 判断此次log entry是否在过半的机器上存储成功了

  7. 如果过半了,则更改leader的commitIndex,更且apply这些日志。在下一次发送心跳包的时候,follower会根据自身的commitIndex和leaderIndex,将lastApplied ~ commitIndex 的日志apply

  8. 如果不成功

  9. 若是因为Term不成功,即当前leader的term落后了,则leader直接转为follower

  10. 若是因为日志不成功,即日志不匹配。 则要将nextIndex--,直到和follower的日志匹配成功。

    image-20211226182110924

5.3 KV存储服务

  1. client 向 server 发送 Put, Get, Append请求每个 client 同时只发一个请求,不需要任何同步,会阻塞式的等待server执行成功。

  2. server 收到后调用 Start() 开始同步所有 raft 节点server 需要能并行处理不同 client 发起的并发的请求

  3. 同步结束,raft 节点通过 applyCh 通知所在 server

  4. server 了解到已经同步成功,开始执行 client 请求的操作

  5. 执行完成后,通过notifiy通知client此操作已经完成

image-20211226181948998

 

作者:乌有先生189

...全文
730 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
CSDN-Ada助手 2023-01-13
  • 打赏
  • 举报
回复
您可以前往 CSDN问答-大数据 发布问题, 以便更快地解决您的疑问

571

社区成员

发帖
与我相关
我的任务
社区描述
软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧