raftd 基于raft和bolt的分布式KV数据库 由于简单实现了租约系统 可以用于简单的服务发现 基于gin框架提供http服务
Go to file
2022-03-15 11:40:39 +08:00
cmd/raftd 使用最新的lsmdb接口 Update 减少文件生成;使用msgpack序列化map 提高性能 2022-03-15 11:40:39 +08:00
httpd 新增撤销租约的接口 2022-02-16 09:47:21 +08:00
store 使用最新的lsmdb接口 Update 减少文件生成;使用msgpack序列化map 提高性能 2022-03-15 11:40:39 +08:00
utils 增加租约系统 用于服务发现 还有不少bug 最突出的是 由于raft的特性 会进行状态机恢复 之前删除的租约会重新创建 如果某个租约没有人租用 会一直存在下去(可以考虑添加租约失效时间) 还有在租约恢复到最新状态之前有新的操作是可以的 也就是逻辑上已经被删除的租约又被创建出来的并且可以访问 这些问题我认为暂时无法解决 后续学一把raft实现看看 或者问问老师什么的 2022-02-13 21:30:26 +08:00
.gitignore 我又来更新辣 没想的那么难 维护好状态机是关键 这次提交还有不少bug:有几处可能的数据竞争 状态机中的bolt事务应该合并到一个函数执行,否则会导致一些数据被篡改 2022-02-14 18:12:51 +08:00
go.mod 使用最新的lsmdb接口 Update 减少文件生成;使用msgpack序列化map 提高性能 2022-03-15 11:40:39 +08:00
go.sum 使用最新的lsmdb接口 Update 减少文件生成;使用msgpack序列化map 提高性能 2022-03-15 11:40:39 +08:00
LICENSE Initial commit 2022-01-22 18:17:35 +08:00
README.md 更新Usage 增加重定向指令 2022-03-15 11:22:45 +08:00

raftd

raftd 基于raft算法,支持数据持久化(bolt)的分布式KV数据库可以用于简单的服务发现基于gin框架提供http服务

Usage

cd cmd/raftd

go build

./raftd -id node01 -haddr 127.0.0.1:8001 -raddr 127.0.0.1:8101 ~/.raftd01

./raftd -id node02 -haddr 127.0.0.1:8002 -raddr 127.0.0.1:8102 -join 127.0.0.1:8001 ~/.raftd02

./raftd -id node03 -haddr 127.0.0.1:8003 -raddr 127.0.0.1:8103 -join 127.0.0.1:8001 ~/.raftd03
curl -X PUT 127.0.0.1:8001/key/test -T ./test.png

curl 127.0.0.1:8001/key/test --output 1.png

步骤:

  1. 启动的时候只make() 然后 调用 tx.ForEach() 遍历整个 db 建立缓存
  2. 更新/删除 KV 的时候同步更新缓存
  3. 集群同步的时候 直接使用 Store.m 进行数据传输

节点同步的步骤:

  1. 先 fsm.db.Close() 然后 截断 data.db
  2. 重新建立 db bolt.Open(...)
  3. range snapshot.m 然后执行一个 Batch Update 将数据同步到 fsm.db 和 fsm.m 中
  4. TODO 失败的情况

租约系统(可以用于服务发现)

Usage

获取租约并续租

# 服务1
ID=$(curl -sL -XPOST 127.0.0.1:8001/lease/grant\?ttl=10\&name=/esq/node-1);while true;do curl -sL -XPOST 127.0.0.1:8001/lease/keepalive/$ID -d 'key=nodeinfo' -d 'data={"http_addr":"127.0.0.1:9001","tcp_addr":"127.0.0.1:9002","node_id":1,"weight":1}';sleep 3;done


# 服务2
ID=$(curl -sL -XPOST 127.0.0.1:8001/lease/grant\?ttl=10\&name=/esq/node-2);while true;do curl -sL -XPOST 127.0.0.1:8001/lease/keepalive/$ID -d 'key=nodeinfo1' -d 'data={"http_addr":"127.0.0.1:9003","tcp_addr":"127.0.0.1:9004","node_id":2,"weight":2}';sleep 3;done

获取键值对

curl -sL -XPOST 127.0.0.1:8001/lease/kv/nodeinfo -d 'prefix=/esq/node'

实现原理

  1. 创建一个DefaultLeaseBucketName的Bucket
  2. 用雪花算法生成一个LeaseId这个Id作为一个子桶里面存放共享这个租约的键值对注意有一个Key是不允许覆写的KeyName为 meta,存放当前租约的元数据,包括 LeaseTTL LeaseAliveCount LeaseStatus LeaseName
  3. 启动一个 goroutine 每秒检测当前租约的状态,一旦有客户端租用了当前租约,租约的状态就从 CREATE 转为 ALIVE并且给租约中的所有键值对的TTL减去一在操作完所有的键值对后统计TTL不为0的AliveCount如果AliveCount==0撤销当前租约(退出当前goroutine,删除这个LeaseId的子桶)
  4. 续租客户端在申请完租约后会从服务端获取租约号使用租约号可以续租一旦续租对应租约中的对应键值对的TTL会重新置为这个租约的TTL(从 meta 中获取)

TODO

  • 申请了却从不租用的租约该怎么处理这些租约的状态为CREATE如果每次同步状态机时全部重启loopCheck会消耗一定的资源如果同步的时候直接删除这些租约属实 鸭子睁眼——大可不必 了,目前有一个可能的解决方案是 PutInPool

  • TimeToLive API

  • 存放租约的树换成LSM-TreeKV系统属于读多写少租约系统属于读写都比较多每秒会有多个协程更新整棵树可以考虑为租约系统单独做一个存储引擎准备参考https://github.com/dgraph-io/badger/tree/v1.0.0,这个库比较成熟,值得借鉴

  • 关于 LSM Tree 存放租约 key 应该设计为 LeaseID value 设计为 metaSize(4bytes)valueSize(4bytes)meta(struct_json_bytes)value(map_json_bytes) TODO:考虑使用某个更高性能的json库