571
社区成员
发帖
与我相关
我的任务
分享作者:283
随着互联网业务量的不断激增,单机数据库无论是从存储空间还是访问速度上,都已经远达不到目前业务的需求,目前业界的主流方案是对数据库进行分库分表,并由此产生了大量中间件。但是这种方案对于业务的侵入性最高,存在兼容性问题。况且由业务方来实现分布式事务处理和容灾,并不是非常好的选择。在这种背景下,分布式数据库的方案是一种更优秀的解决方案,某种程度上也是一种未来的趋势。基于上述背景,选择了基于强一致性共识算法raft的非关系型K/V键值对存储服务作为工程实践的课题。
这个课题一共由两个模块组成,一是raft模块的实现,二是K/V存储模块的实现,其中Raft模块实现也是项目的核心部分。
raft集群中共包含三种角色:



kv模块则包含两种角色:

1. 收集应用业务领域的信息。聚焦在功能需求层面,也考虑其他类型的需求和资料;
2. 头脑风暴。列出重要的应用业务领域概念,给出这些概念的属性,以及这些概念之间的关系;
3. 给这些应用业务领域概念分类。分别列出哪些是类、哪些属性和属性值、以及列出类之间的继承关系、聚合关系和关联关系;
4. 将结果用 UML 类图画出来。
对于raft模块,功能主要有三部分构成,分别是领导选举、日志复制和安全性要求。
Raft算法把时间轴划分为不同任期 Term。每个任期 Term 都有自己的编号 TermId,该编号全局唯一且单调递增

对于K/V存储模块,功能主要是存储服务提供的Put(key, value)、 Append(key, arg)和Get(key)方法,Put(key, value)替换数据库中特定键的值,Append(key, arg) 将 arg 附加到键的值,而Get(key)获取键的当前值。

本项目中提供存储服务的集群模块采用了简单的分层模式,具体如下图所示:

其中图中的数字表示不同模块相互通信、进行数据交互的方式
|
func (ps *Persister) SaveRaftState(state []byte) |
保存持久化raft节点状态的函数 |
|
func (ps *Persister) ReadRaftState() |
读取持久化raft节点状态的函数 |
|
func (ps *Persister) SaveStateAndSnapshot() |
存储快照点的函数 |
|
func (ps *Persister) ReadSnapshot() |
读取快照点的函数 |
|
func (rf *Raft) GetState() |
获取当前任期节点状态的函数 |
|
func (rf *Raft) AppendEntries() |
处理心跳或者日志的rpc通信函数 |
|
func (rf *Raft) sendAppendEntries() |
发送心跳或者日志的rpc通信函数 |
|
func (rf *Raft) RequestVote |
获取投票结果的rpc通信函数 |
|
func (rf *Raft) sendRequestVote |
向其他结点发起投票的rpc通信函数 |
|
func (rf *Raft) PutAppend() |
KV存储的写操作(含有插入、修改等) |
|
func (rf *raft) Get |
KV存储的读操作 |
1、通过进行需求分析和设计这两方面的工作,认识到需求分析和设计在软件开发中是至关重要的。一方面,由于它们是软件开发的前期工作,后续的编码和测试等等其他流程都要已它们为依托,如果没有做好,出现的问题会在后续被逐级放大,从而产生更多更严重的问题。另一方面,如果前期把这两项功能工作做好,后续的编码工作思路会非常清晰,按部就班把需求和模块翻译成代码即可,不会出现开发到一半进行卡壳的现象;
2、考虑到各大板块的互联网业务量逐渐达到瓶颈的现实情况,未来互联网市场必然是增量市场向存量市场转换的过程。某种程度上,这也是基础设施及基础软件发力的好机会,无论是数据库领域的各个方向,还是操作系统、编译器等,都是值得深究的方向。