基于一致性哈希 https://zh.wikipedia.org/wiki/一致哈希 的分布式内存键值存储 --CHKV.
系统设计
NameNode : 维护 key 与节点的映射关系(Hash 环), 用心跳检测 DataNode(一般被动, 被动失效时主动询问三次), 节点增减等系统信息变化时调整数据并通知 Client;
DataNode : 存储具体的数据, 向 NameNode 主动发起心跳并采用请求响应的方式来实现上下线, 便于 NameNode 挪动数据
Client : 负责向 NameNode 请求 DataNode 数据和 Hash 算法等系统信息并监听其变化, 操纵数据时直接向对应 DataNode 发起请求就行, 暂时只包含 set,get,delete 三个操作
NameNode 失效则整个系统不可用
若当成内存数据库使用, 则只要有一个 DataNode 失效(未经请求与数据转移就下线了) 整个系统就不可对外服务; 若当成内存缓存使用, 则 DataNode 失效只是失去了一部分缓存, 系统仍然可用.
客户要使用 CHKV 就必须使用 Client 库或者自己依据协议 (兼容 redis) 实现, 可以是多种语言的 API.
分析
要想实现高可用有两点: NameNode 要主从双机热备, 避免单点失效; 每个 DataNode 可以做成主从复制甚至集群.
各个组件之间的连接情况:
NameNode 要保持和 N 个 Client 的 TCP 长连接, 但是只有在集群发生变化时才有交互, 所以使用 IO 多路复用负载就不大
NameNode 要和 M 个 DataNode 保持心跳, TCP 请求响应式, 负载与 M 和心跳间隔秒数 interval 有关
DataNode 与 Client 是 TCP 请求响应式操作, 操作结束断开连接, 也可以考虑加入连接池
DataNode 与 NameNode 保持心跳
Client 与 NameNode 保持 TCP 长连接
Client 与 DataNode TCP 请求响应式操作
如下图所示, 有 4 个连接, 其中 1,2 要保持连接, 3,4 完成请求后就断开连接
- NameNode
- || ||
1, 心跳请求响应 || ||2, 监听长连接
|| 3, 数据请求响应 ||
- DataNodes ========== Clients
- || ||
- ||
4, 数据转移, 可复用 3
开发优先级: 3,1,4,2
具体性能瓶颈要结合压测来分析
使用方法
DataNode 运行起来就可以直接使用 redis-cli 连接, 如
redis-cli -h 127.0.0.1 -p 10100
, 并进行 set,get,del 操作;
注意: 现在必须首先运行 NameNode, 然后通过 JVM 参数的方式调整端口, 可以在同一台机器上运行多个 DataNode, 若要在不同机器上运行 DataNode 则可以直接修改配置文件
新的 DataNode 可以直接上线, NameNode 会自动通知下一个节点转移相应数据给新节点; DataNode 若要下线, 则可以通过 telnet DataNode 节点的下线监听端口(TCP 监听) 如
telnet 127.0.0.1 6666
, 并发送 k 字符即可, 待下线的 DataNode 收到命令 k 后会自动把数据全部转移给下一个 DataNode 然后提示进程 pid, 用户就可以关闭该 DataNode 进程了, 如 Linux: kill -s 9 23456,Windows:
taskkill /pid 23456
NameNode 和 DataNode 启动后就可以使用 Client 了, 代码示例如下:
Client 代码示例在此, 关键如下: https://github.com/MageekChiu/CHKV/blob/master/Client/src/test/java/cn/mageek/client/ConnectionTest.java
- try(Client client = new Client("192.168.0.136","10102")){
- logger.debug(client.set("192.168.0.136:10099","123456")+"");
- logger.debug(client.get("192.168.0.136:10099")+"");
- logger.debug(client.set("112","23")+"");
- logger.debug(client.del("1321")+"");
- logger.debug(client.del("112")+"");
- }
代码结构
NameNode : 实现 NameNode 功能
handler : handler
res : 资源, 如常量, 命令工厂
service : 服务, 含 Client 管理, DataNode 管理
DataNode : 实现 DataNode 功能
command : 处理客户端各个命令的具体命令对象
job : 一些的任务如心跳, 数据迁移
handler : 处理连接的 handler
service : 服务, 含定时任务管理, 数据请求管理
Client : 实现 Client 功能
handler : handler
Client : 暴露给用户的命令管理
Connection : 发出网络请求
Common : 实现一些公共的功能, 上面三个模块依赖于此模块
command : 命令抽象类
model : 一些公用的 pojo, 如请求响应对象
util : 一些工具类
helper : 辅助脚本
水平有限, 目前项目的问题还很多, 可以列个清单:
高可用性保证
断线重连
DataNode 迁移数据的完整性保证
迁移过程数据的一致性
对于 WeakReference 的支持
更多数据类型
更多操作
完整的校验机制
等等......
全部代码在 Github https://github.com/MageekChiu/CHKV 上, 欢迎 star, 欢迎 issue, 欢迎 pull request...... 总之就是欢迎大家和我一起完善这个项目, 一起进步.
戳此 http://mageek.cn/archives/96/ 看原文, 来自 MageekChiu http://mageek.cn/
来源: https://juejin.im/post/5af553fb6fb9a07acc11c584