为了账号安全,请及时绑定邮箱和手机立即绑定

基于一致性哈希的分布式内存键值存储——CHKV

标签:
Java
Consistent Hashing based Key-Value Memory Storage

基于一致性哈希的分布式内存键值存储——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 要保持和 NClient 的TCP长连接,但是只有在集群发生变化时才有交互,所以使用IO多路复用负载就不大
  • NameNode 要和 MDataNode 保持心跳,TCP请求响应式,负载与 M 和心跳间隔秒数 interval 有关
  • DataNodeClient 是TCP请求响应式操作,操作结束断开连接,也可以考虑加入连接池
  • DataNodeNameNode 保持心跳
  • ClientNameNode 保持TCP长连接
  • ClientDataNode 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进程了,如 Linuxkill -s 9 23456Windows:taskkill /pid 23456

NameNode和DataNode启动后就可以使用Client了,代码示例如下:

Client代码示例在此,关键如下:

    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上,欢迎 star,欢迎 issue,欢迎 pull request......
总之就是欢迎大家和我一起完善这个项目,一起进步。

戳此看原文,来自MageekChiu

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
22
获赞与收藏
158

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消