zoukankan      html  css  js  c++  java
  • 基于redis的分布式缓存disgear开源到github上了

    disgear是笔者参考solrcloud架构基于redis实现的分布式的缓存,支持数据切分到多台机器上,支持HA,支持读写分离和主节点失效自动选举,目前把它开放到github上,开放给大家

    github:https://github.com/yangbutao/disgear

    总体设计

                                        

                    

       

    1. 系统需求

    1) 性能

    内存操作,读写性能要求比较高

    2) 数据量

    支持数据切分,分为多个Shard,每个shard负责一定范围的数据

    3) 伸缩性

    当单个节点的数据量比较大的时,可以对该节点进行数据切分,分离成两部分,增加新的机器即可。

    4) 可用性

    系统不存在单点问题,缓存节点支持HA,master节点宕掉后,自动选举一个slave为主节点,对客户端透明

    2. 设计说明

    首先启动好所有的redis实例,每个redis实例有一个agent负责监控,agent ping redis实例的状态,agent 连接到zookeeper上创建/collections/collection1/leader_elect/shard1/election下的节点,监控比它小的节点,变化时更新leader节点。

    当agent连接zookeeper超时或者agent ping redis实例超时,会删除zookeeper上的election下的节点(agent ping redis超时,调用zookeeper api删除节点)。

    当ping到redis节点起来后,若检查到zookeeper上没有对应节点,则创建相应节点。

    Leader(master)是缓存负责响应的节点,replica(slave)只负责同步leader的数据,当leader宕机后,提升replica为主节点。

    以下是zookeeper上节点的相关说明:

    /collections

       |----collection1

            |----leader_elect

                   ----shard1[0-7ffffffff]      //节点启动时,一共需要分几个 分区,需要声明该节点属于哪个shard

                       ---election         //参与选举的节点列表,竞争成为leader节   点,并更新leaders节点列表和clusterstate.json节点内容,并调用脚 本 更改redis的master slave配置

                            ----10.1.1.21

                            ----10.1.1.22

                   ----shard2

                       ---eclection

                            ---10.1.1.23

                            ---10.1.1.24

             |---leaders

                  ----shard1              //当前shard的leader节点

                      ---10.1.1.21

                  -----shard2

                      ----10.1.1.24

    /observer                //负责watch collections中节点的变化,

    由leader节点更新 clusterstate.json节点的内容,observer节点需要在系统初始 化过程中最新选举出leader节点,做watch collections下的 节点的变化。

         |---election          //其下是供选择的节点

         |----leader           //这样一个好处是每个client节点无需对多个zookeeper的节点监控计算,由单独的节点对这些变化的节点做监控, 来更新集群状态,这样每个client只需要 watch 集群状态 内容zookeeper节点即可。

    /live_nodes

        |---10.1.1.21

        |----10.1.1.22

        |----10.1.1.23

        |-----10.1.1.24

    /clusterstate.json                      //集群状态,当有节点变化时,更新这个节点 内容,每个client端监听该节点内容的变化, 缓存在本地cache中。

    相关内容如下:

    {collection1={

      "shards":{

        "shard1":{

          "range":"80000000-ffffffff",

           “leader”:node1,

          "replicas":{

            "node1":{

              "state":"alive",         "node_name":"192.168.1.21:8983"},

            "node2":{

              "state":"alive",

                "node_name":"192.168.1.22:8983"

              }}},

     "shard2":{

          "range":"0-7fffffff",

          "state":"active",

           “leader”:node3,

          "replicas":{

            "node3":{

             "node_name":"192.168.1.23:8983"},

            "core_node4":{

               "node_name":"192.168.1.24:8983"

              }}},

    模块设计说明 

    1. 数据切分、节点扩容、key hash

    对于数据切分,数据的范围取Integer.MIN_VALUE, Integer.MAX_VALUE,首次初始化时,根据规划的Shard的数量,平均进行切分,每个Shard负责一个固定的数据范围,比如Shard1[0-7fffffff],这些Shard和数据的范围会持久化到zookeeper节点上,以便于集群重启后,从zookeeper本地拉起Shard划分和数据范围的相关数据,如下图所示。

    /collections

       |----collection1

            |----leader_elect

                   ----shard1[0-7ffffffff] 

                   ----shard2[800000-9ffffffff]

    当需要扩容缓存节点时,管理员可以对Shard进行split操作,生成两个新的Shard,每个Shard负责一部分数据,注册在zooleeper上的/collections/collection1/leader_elect节点下。比如Shard1[0-7ffffffff]经过split操作后,变成Shard1_1[0-3ffffffff]和Shard1_2[400000-7fffffffff]。

    /collections

       |----collection1

            |----leader_elect

                   ----shard1[0-7ffffffff] 

                   ----shard2[800000-9ffffffff]

                       ----shard1_1[0-3ffffffff] 

                       ----shard1_2[0-3ffffffff]

      新的节点加入到新的Shard分区中,完成leader选举等一系列操作后,更新集群拓扑状态,并删除老的Shard分区,这样新的Shard就处于可用状态。

    对于key的hash定位,采用murmurhash3_x86_32 算法,效率比较高,然后判断该hash值落在哪个shard的数据范围内,进行数据的分区定位。

    2. 缓存代理Agent

    Agent作为缓存节点的代理,一方面和zookeeper进行通信,把缓存节点的状态通知给zookeeper,另外一方面对redis缓存节点做管理和监控。

    1) Agent检测redis节点是否存活:

    需要在Agent中调用以下脚本(monitor_redis.sh),把返回的结果,通知给zookeeper

    ALIVE=$(/opt/cache/redis-2.6.16/src/redis-cli -h 10.1.1.25 -p 6379 -a 123 PING)

    echo $ALIVE

    2) 变更为master节点

    当节点上的agent在zookeeper上成为leader节点时,需要通知agent把它代理的redis变更为master节点,agent调用以下脚本。

    主节点的脚本(redis_master.sh):

    #!/bin/bash

    /opt/cache/redis-2.6.16/src/redis-cli -h 10.1.1.26 -p 6379 slaveof NO ONE   

    3) 变更为slave节点

    当节点上的agent在zookeeper上成为replica节点时,需要通知agent把它代理的redis变更为slave节点,agent调用以下脚本。

    slave节点脚本(redis_slaves.sh):

    #!/bin/bash

    /opt/cache/redis-2.6.16/src/redis-cli -h 10.1.1.26 -p 6379 slaveof 10.1.1.25 6379 

    3. 集群状态观察者Observer

    Observer负责对整个集群collection下的Shard节点的变动进行监听,更新zookeeper上的集群状态节点cloudstate.json。

    Agent节点在启动过程中,首选要做的就是Observer的选举。

    Observer需要由zookeeper选举出来后,监听collections下节点的变化,若有变化则进行处理process,计算的结果设置到zookeeper的cloudstate.json节点。

    当cloudstate.json节点数据变化时,负责监听该节点的所有客户端都更新本地客户端内存。

    /observer                

         |---election          

              ----10.1.1.21

              ----10.1.1.22

             -----10.1.1.23

         |----leader         

               -----10.1.1.22      

    4. Shard leader选举

    Shard节点在zookeeper上创建完成后,缓存节点在启动的过程中,需要通过命令行-D参数或者配置文件的形式加入到集群中的某一个Shard分区下,参与leader的选举,具体实现是为每个节点生成一个数字,每个节点只需要监控比自己小的节点即可,如有变化,则进行通知,并使得数字最小的节点成为leader节点。

    /collections

       |----collection1

            |----leader_elect

                   ----shard1               //节点启动时,一共需要分几个分区,需要 声明该节点属于哪个shard

                       ---eclection         //参与选举的节点列表,竞争成为leader节   点,并更新leaders节点列表和clusterstate.json节点内容,并调用脚 本 更改redis的master slave配置

                            ----10.1.1.21

                            ----10.1.1.22

                   ----shard2

                       ---eclection

                            ---10.1.1.23

                            ---10.1.1.24

             |---leaders

                  ----shard1              //当前shard的leader节点

                      ---10.1.1.21

                  -----shard2

                      ----10.1.1.24

    5. 缓存节点的扩容

    当某shard的访问压力过大或者数据量比较大时候,节点的扩展有两种方式,

    一种是增加shard中的节点数量,提高读的能力,这种方式已经实现;

    另外一种方式对压力大的shard做split的操作,一个shard分割为两个shard,提高shard的写数据的能力,这种节点的扩展方式目前还不支持,已纳入到后续的计划中。

    使用说明

    Agent的启动脚本:

    MAIN="com.newcosoft.cache.agent.AgentMain"
    $JAVA $JAVA_OPTS  -cp "$CLASSPATH" $JVMFLAGS $MAIN  -Dcol=col1 -Dshard=shard1 -Dnode=node25
      -DbaseUrl=10.1.1.25:6379 -DscriptPath=/opt/lsmp -DshardNum=3 -Dzk_url=10.1.1.25:2181

    其中-Dcol表示当前创建的collection名称,对于redis来讲,代表要存储库的逻辑名称

    -Dshard表示当前的节点的shard名称

    -Dnode表示当前节点的逻辑名称

    -DbaseUrl表示redis的主机IP和端口号

    -DscriptPath表示redis监控和操作相关的脚本的路径,脚本有monitor_redis.sh、redis_master.sh、redis_slaves.sh

    -DshardNum表示当前collection中的shard数目

    -Dzk_url代表zookeeper集群的地址

    Client端的使用:

    在使用disgear的client端启动初始化中,引用disgear相关的jar,并调用

    com.newcosoft.client.ClusterStateCacheManager.INSTANCE=new ClusterStateCacheManager(zkUrl);

    ClusterStateCacheManager.INSTANCE.createClusterStateWatcher();

    创建clusterState的监听器。

    这样后续通过com.newcosoft.client.ClusterStateCacheManager.INSTANCE.getClusterState()就可以获得当前集群的节点状态,

    进而选择合适的节点进行分发数据存取请求。

  • 相关阅读:
    66. Plus One
    Binder
    Activity启动模式笔记整理
    ANR和FC
    java之yield(),sleep(),wait()区别详解-备忘笔记
    Http方法:Get请求与Post请求的区别
    BroadcastReceiver的用法笔记
    java笔记
    Leetcode -- Day 17 & Day 18 & Day 19
    Leetcode -- Day 14&Day15&Day16&Day17
  • 原文地址:https://www.cnblogs.com/archoncap/p/4882803.html
Copyright © 2011-2022 走看看