dister分布式框架

核心组件

1、服务配置管理中心
2、服务注册与发现
3、服务健康检查
4、服务负载均衡

集群角色 和 RAFT角色

dister集群有两种角色的概念,一种是集群角色(client/server),一种是RAFT角色(follower/candidate/leader)

集群角色

  • client:可以看做一个独立进程的SDK,仅作API操作,不会参与RAFT的leader选举、也不会存储任何的集群数据;
  • server:集群的关键节点,参与leader选举,每个server节点保持与leader数据同步与数据的一致性,保证整个集群的高可用;

一个dister集群中至少应当有一个server节点,当集群中的leader节点出现故障后,其他的server就会按照既定的election算法快速执行选举,选举成功后新的leader将会接替故障的leader继续行使leader职能。dister集群随时保持每个节点的状态同步(leader与server节点之间保持数据一致性),需要使用集群功能的应用端,本地需要运行一个client节点。

RAFT

dister集群底层的分布式一致性算法使用的是RAFT,但是对于RAFT算法中某些设计进行了改进,主要在于:集群设计、选举设计、数据同步、分区问题处理、负载均衡处理

选举设计

  • dister按照比分机制来进行leader选举,允许一个节点投票给多个candidate,请求投票时由请求节点记录与目标节点的响应时差(纳秒),并且保证至少 n/2+1 个节点票数作为选举前提。这样各节点经过最多两轮与其他节点之间的对比(RequestScore + CompareScore),谁获得的投票多,并且耗费的时间最短(两个candidate节点在投票相等的情况下会继续对比响应时差,响应越快比分越高),那么该节点即可被选举为leader,其他节点在对比中被淘汰为follower。这样的选举非常快,它只需要经过最多两轮各节点的对比便能选举出leader,不会出现spit vote的情况,并且选举出的leader往往是集群中网络吞吐比较快速的节点。集群故障恢复也会更加迅速,可靠性相对于传统的RAFT选举机制要好。
  • 在dister选举中,影响选举的因素除了选票和比分外,还包括数据版本,即整个dister集群中数据集最新的节点优先成为leader。此外,dister的选举和RAFT的传统选举都有先发优势这一说,也就是首先发起选举的节点成为leader的概率越高。

数据同步

dister对RAFT数据同步机制改进的目的,是支持对同步并发性能与数据强一致性之间取了一个折中的方案。在数据的请求处理中,dister为用户提供了可选择的3种方案(由用户自主选择):

a、强一致性:(默认)传统RAFT数据同步机制;

b、中一致性:集群保证leader和另外同一个节点数据更新之后才算是成功,其他节点依靠异步机制进行数据同步;

c、弱一致性:集群保证leader数据更新成功之后就算是成功,其他节点依靠异步机制进行数据同步;

负载均衡

  • 数据负载均衡:任何的数据写入/删除都是通过client写入到leader,并由leader按照RAFT算法保证集群的数据一致性。但是,数据在读取的时候便不能请求到leader(负载均衡考虑),而是通过一致性哈希算法(保证每次请求都是同一个server节点)请求到其他的server节点,保证整个集群数据操作的负载均衡。当然,由于leader与其他节点之间的数据同步是有延迟的,因此,这里需要特别说明的是,数据在写入leader成功后,会在client节点进行数据缓存(限制缓存数据量大小,非内存大小,按照LRU算法进行数据缓存及淘汰),保证对于当前应用端来讲,数据读写是即时的。
  • 服务负载均衡:dister提供了独立的负载均衡接口来实现服务的负载均衡访问(负载均衡没有采用一致性哈希算法,而是通过服务的priority属性计算,应用端可自定义,灵活度更高),由于应用端与dister的集群通信采用的是本地进程间通信实现,因此,这种机制会比远程RPC的执行效率更加高效。为简便应用端接入和使用,dister仅提供了通用的REST接口方式来访问所有的API。此外,使用者可以选择性地对负载均衡结果进行缓存,减少请求数。

使用

配置

dister运行时可以指定配置文件路径,如果没有指定,那么默认会查找当前运行目录下的 dister.json 文件

./dister --cfg=/home/john/Document/dister.json

集群节点API

  • 节点查询

    GET http://127.0.0.1:4168/node
    
  • 节点添加/修改

INPUT/POST http://127.0.0.1:4168/node ["192.168.1.100","192.168.1.101","192.168.1.102"]
  • 节点删除
DELETE http://127.0.0.1:4168/node ["192.168.1.100"]

KV 数据管理API

  • KV数据查看(最多1000条)

    GET http://127.0.0.1:4168/kv
    
  • KV数据查询

    GET http://127.0.0.1:4168/kv?k=键名
    
  • KV数据添加/修改

    INPUT/POST http://127.0.0.1:4168/kv {"key":"value"}
    
  • KV数据删除

    DELETE http://127.0.0.1:4168/kv ["key1","key2"]
    

服务管理API

  • 服务查看(最多1000条)

    GET http://127.0.0.1:4168/service
    
  • 服务查询

    GET http://127.0.0.1:4168/service?name=服务名称
    
  • 服务添加/修改

     INPUT/POST http://127.0.0.1:4168/service
    
  • 服务删除

    DELETE http://127.0.0.1:4168/service ["服务名称1","服务名称2"]
    

负载均衡API

GET http://127.0.0.1:4168/balance?name=服务名称

实例

为简单起见,我们这个集群只有3个节点:192.168.2.15、192.168.2.63、192.168.2.114,名称分别设置为node1、node2、node3。

node1:

john@node1:~$ ./dister --Name=node1 --MinNode=3
dister version 1.0, start running...
==================================================================================
Host Id       : 053CE4246B1A82C99C6309814BFD525A
Host Role     : server
Host Name     : node1
Host Group    : default.group.dister
Host LogPath  : 
Host SavePath : /home/john/dister.db
Group MinNode : 3
==================================================================================
2017-09-21 15:42:49 score comparison: get success from node3
2017-09-21 15:42:49 score comparison: get success from node2
2017-09-21 15:42:49 set leader: node1
2017-09-21 15:42:49 role changed from candidate to leader

node2:

john@node2:~$ ./dister --Name=node2 --MinNode=3
dister version 1.0, start running...
==================================================================================
Host Id       : 781504634EFF09BDAD297575195B30FA
Host Role     : server
Host Name     : node2
Host Group    : default.group.dister
Host LogPath  : 
Host SavePath : /home/john/dister.db
Group MinNode : 3
==================================================================================
2017-09-21 15:42:45 successfully scan and add local ip: 192.168.2.15
2017-09-21 15:42:49 set leader: node1

node3:

节点

john@node3:~$ ./dister --Name=node3 --MinNode=3
dister version 1.0, start running...
==================================================================================
Host Id       : DBD540BE180C0DB03A2D89055F64A1BB
Host Role     : server
Host Name     : node3
Host Group    : default.group.dister
Host LogPath  : 
Host SavePath : /home/john/dister.db
Group MinNode : 3
==================================================================================
2017-09-21 15:42:49 successfully scan and add local ip: 192.168.2.63
2017-09-21 15:42:49 successfully scan and add local ip: 192.168.2.15
2017-09-21 15:42:49 set leader: node1
  • dister启动时会打印出当前节点的一些信息,我们需要注意的是节点名称、最小节点数以及数据保存路径,虽然我们没有设置数据保存路径,但是dister默认是保存到当前路径,并且创建了一个dister.db目录。

  • 每个节点启动的时候,它都能快速地发现当前局域网的其他dister节点,并迅速建立通信,因为默认情况下,dister会对当前所在的局域网进行异步扫描,这个过程非常快速。

  • 由于设置了集群最少节点为3个,因此只启动node1和node2时,集群并没有开始进行选举,但是一旦启动了node3,集群立即开始选举流程,并且迅速地选举出node1作为leader,其他两个节点降级为follower。

查看节点:

john@node2:~$ ./dister nodes
                            Name                          Group              Ip         Role     Status
                           node2          default.group.dister    192.168.2.63     follower      alive
                           node1          default.group.dister    192.168.2.15       leader      alive
                           node3          default.group.dister   192.168.2.114     follower      alive

添加/删除节点

john@node4:~$ ./dister --Name=node4 
dister version 1.0, start running...
==================================================================================
Host Id       : 7273D2FF741384E4FB7381682BF4AA08
Host Role     : server
Host Name     : node4
Host Group    : default.group.dister
Host LogPath  : 
Host SavePath : /home/john/dister.db
Group MinNode : 2
==================================================================================
2017-09-21 17:34:09 successfully scan and add local ip: 192.168.2.15
2017-09-21 17:34:09 successfully scan and add local ip: 192.168.2.63
2017-09-21 17:34:09 successfully scan and add local ip: 192.168.2.114
2017-09-21 17:34:10 receive data replication update from: node1
2017-09-21 17:34:10 receive service replication from node1
2017-09-21 17:34:10 set leader: node1

已经被自动发现了,因此我们在演示的时候应该关闭掉自动发现功能

john@node2:~$ ./dister addnode 192.168.2.121
ok
john@node2:~$ ./dister nodes
                            Name                          Group              Ip         Role     Status
                           node2          default.group.dister    192.168.2.63     follower      alive
                           node3          default.group.dister   192.168.2.114     follower      alive
                           node4          default.group.dister   192.168.2.121     follower       dead
                           node1          default.group.dister    192.168.2.15       leader      alive

KV数据操作

1、目前集群暂无任何的数据,调用 dister kvs 会提示当前数据为空,因此我们先在node3上通过命令行添加1条kv数据

john@node3:~$ ./dister kvs
it's empty
john@node3:~$ ./dister addkv name john
ok
john@node3:~$ ./dister kvs
K     : V
name2 : john2

2、紧接着我们去node2上进行查看,发现数据已经同步成功了,并且打印出了所有的数据;接着我们在node2上也添加1条数据,并通过&&立即查询并打印出刚才添加的数据,结果也能立即获取到,并没有任何延迟

john@node2:~$ ./dister kvs
K    : V
name : john
john@node2:~$ ./dister addkv name2 john2 && ./dister getkv name2
ok
john2
john@node2:~$ ./dister kvs
K     : V
name  : john
name2 : john2

3.在node2上删除name数据(这条数据是node3添加的),并在node3上查询所有KV数据结果

node2:

john@node2:~$ ./dister kvs
K     : V
name  : john
name2 : john2
john@node2:~$ ./dister delkv name
ok
john@node2:~$ ./dister kvs
K     : V
name2 : john2

node3:

john@node3:~$ ./dister kvs
K     : V
name2 : john2

服务管理操作

1.添加服务

这里我们只添加两个服务,1个web服务,1个mysql服务,配置文件内容如下:

[
    {
        "name" : "sites",
        "type" : "web",
        "node" : [
            {"url": "http://johng.cn/",         "interval" : "5000", "priority": "100"},
            {"url": "http://baidu.com/",        "interval" : "5000", "priority": "100"},
            {"url": "https://gitee.com/johng/", "interval" : "5000", "priority": "100"},
            {"url": "http://dead.link",         "interval" : "5000", "priority": "100"}
        ]
    }
]
[
    {
        "name" : "database",
        "type" : "mysql",
        "node" : [
            {"host":"192.168.2.15", "port": "3306", "user":"root", "pass":"123456", "database":"test", "priority": "100", "interval" : "2000"},
            {"host":"192.168.2.15", "port": "3306", "user":"root", "pass":"123456", "database":"user", "priority": "100", "interval" : "2000"}
        ]
    }
]
john@node2:~$ ./dister addservice ./db.service.json 
ok
john@node2:~$ ./dister addservice ./web.service.json 
ok

2.查看服务

john@node2:~$ ./dister services

也可以通过浏览器打开 http://127.0.0.1:4168/service 查看服务状态

dister getservice 查看指定服务的状态

john@node2:~$ ./dister getservice sites
{
    "name": "sites",
    "node": [
        {
            "interval": "5000",
            "priority": "100",
            "status": 1,
            "url": "http://johng.cn/"
        },
        {
            "interval": "5000",
            "priority": "100",
            "status": 1,
            "url": "http://baidu.com/"
        },
        {
            "interval": "5000",
            "priority": "100",
            "status": 1,
            "url": "https://gitee.com/johng/"
        },
        {
            "interval": "5000",
            "priority": "100",
            "status": 0,
            "url": "http://dead.link"
        }
    ],
    "type": "web"
}

3. 删除服务

dister delservice

john@node2:~$ ./dister delservice database
ok

负载均衡

john@node2:~$ ./dister balance sites

{
    "interval": "5000",
    "priority": "100",
    "status": 1,
    "url": "https://gitee.com/johng/"
}

http://127.0.0.1:4168/balance?name=sites

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×