braft

raft文档

https://github.com/baidu/braft/blob/master/docs/cn/raft_protocol.md

如何在分布式Server中使用braft来构建高可用系统

一、使用braft

1.1 注册并启动Server
int add_service(brpc::Server* server, const char* const butil::EndPoint& listen_addr);   // 负责把braft相关的service添加到brpc server里面。
    server->AddService(new RaftServiceImpl(listen_address), brpc::SERVER_OWNS_SERVICE)  // RaftServiceImpl主要和raft协议有关,有一些选举、append_entries和快照相关的接口。
    server->AddService(new CliServiceImpl, brpc::SERVER_OWNS_SERVICE)   // CliServiceImpl负责管理braft相关的工作,比如add_peer,get_leader,transfer_leader等操作。
1.2实现业务状态机

需要继承braft::StateMachine并且实现里面的接口

1.3构造braft::Node

一个Node代表了一个RAFT实例, Node的ID由两个部分组成:
GroupId: 为一个string, 表示这个复制组的ID.
PeerId, 结构是一个EndPoint表示对外服务的端口, 外加一个index(默认为0). 其中index的作用是让不同的副本能运行在同一个进程内, 在下面几个场景中,这个值不能忽略:
启动这个节点:

int start()
	node_options.initial_conf.parse_from(FLAGS_conf) // initial_conf只有在这个复制组从空节点启动才会生效,当有snapshot和log里的数据不为空的时候的时候从其中恢复Configuration。
		initial_conf只用于创建复制组,第一个节点将自己设置进initial_conf,再调用add_peer添加其他节点,其他节点initial_conf设置为空;也可以多个节点同时设置相同的inital_conf(多个节点的ip:port)来同时启动空节点。

RAFT需要三种不同的持久存储, 分别是:
RaftMetaStorage, 用来存放一些RAFT算法自身的状态数据, 比如term, vote_for等信息.
LogStorage, 用来存放用户提交的WAL
SnapshotStorage, 用来存放用户的Snapshot以及元信息. 用三个不同的uri来表示, 并且提供了基于本地文件系统的默认实现,type为local, 比如 local://data 就是存放到当前文件夹的data目录,local:///home/disk1/data 就是存放在 /home/disk1/data中。libraft中有默认的local://实现,用户可以根据需要继承实现相应的Storage。

1.4将操作提交到复制组

将操作序列化成IOBuf, 这是一个非连续零拷贝的缓存结构。构造一个Task, 并且向braft::Node提交

#include <braft/raft.h>
...
void function(op, callback) {
    butil::IOBuf data;
    serialize(op, &data);
    braft::Task task;
    task.data = &data;
    task.done = make_closure(callback);
    task.expected_term = expected_term;
    return _node->apply(task);
}

实现Snapshot

在braft中,Snapshot被定义为在特定持久化存储中的文件集合, 用户将状态机序列化到一个或者多个文件中, 并且任何节点都能从这些文件中恢复状态机到当时的状态.

Snapshot有两个作用:

  • 启动加速, 启动阶段变为加载Snapshot和追加之后日志两个阶段, 而不需要重新执行历史上所有的操作.
  • Log Compaction, 在完成Snapshot完成之后, 这个时间之前的日志都可以被删除了, 这样可以减少日志占用的资源.

在braft的中, 可以通过SnapshotReader和SnapshotWriter来控制访问相应的Snapshot.

一、日志复制
1.1 提交任务
构造Task
当客户端请求过来的时候,服务端需要将request转化为log entry(IOBuf),并构造一个braft::Task,将Task的data设置为log,并将回调函数done构造Closure传给Task的done,当函数最终成功执行或者失败的时候会执行回调。

posted @ 2021-08-22 11:53  淡然那片天  阅读(643)  评论(0)    收藏  举报