#分布式系统架构
现在很多公司都是使用dubbo或者类似dubbo的rpc调用。说说我对dubbo的理解 dubbo 存活检测感觉分为下面三个层面 服务端与注册中心的链接状态 通常注册中心是zookeeper,服务端注册临时节点,客户端注册这个节点的watch事件,一但服务端失联, 客户端将把该服务从自己可用服务列表中移除。(一个服务通常有多个提供者,只是把失联的提供者移除)。 zookeeper是通过心跳发现服务提供者失联的,心跳实际上就是以固定的频率(比如每秒)发送检测的数据包;
客户端与注册中心的链接状态 客户端与zookeeper失联,会暂时使用自己缓存的服务提供者列表。如果每个提供者多次调不通,把它移除。
客户端与服务单的链接状态 服务端提供类似于echo的方法,客户定时调用。部分返回正常,认为服务处于亚健康状态,如果超过阀值,会被降级 从服务提供者列表移除。被移除的方法可能会在超过一定时间后,拿回来重试,可以恢复成正常服务,也可能继续降级。
##概要设计 0. Master重启期间不允许,新增worker
- 服务器分为Master和Worker.
- Master为中心节点每次启动都会有一个惟一的instanceid来代表当前实例.
- Worker为工作节点,每次启动后,由Master分配一个惟一instanceid来代表当前实例.
- 所有类型服务器个数,在开服前确定
- 整体存活的服务器个数不会超过开服前设定的服务器个数
- 服务器之间逻辑层无链接(底层使用TCP仅仅是为了数据传输可靠性)
- 服务器存活仅依靠心跳判断
- Master会提供telnet/http接口来显示服务器的状态
- 已经处理down状态下的实例,在有新实例替换后,不可以再次复活(需要运维保证)
###服务状态 up ready run down
###Worker服务类型 gate xn role xn citywar xn auth x1 chat x1 scene x1 league x1
###服务发现机制
- Master作为第一个进程启动
- Worker启动后会循环向Master进行up_r来申请运行
- Master等待所有Worker都启动完毕(收到所有Worker的up_r或run_r,如果有多个down状态下的实例,则会统计所有非down的个数和)
- 向当前所有启动的实例,同步一次当前实例列表
- 开始分配hashid, instanceid, 然后返回成功
- Worker拿到返回的注册数据后,开始执行初始化逻辑, 初始化完成之后,会再次循环向Master发送run_r来申请工作.
- MASTER在收到run_r之后检查是否所有实例都已经处理run状态
- Worker收到成功之后,开始真正注册处理逻辑
###Master存活检测
- Worker每10s会向Master发送心跳, Master会向Worker返回一个当前MID.
- Worker会校验当前WID与上次拿到的WID不同,说明Master被重启,丢失集群信息.主动上报自己信息.
###Worker存活检测
- Master每10s会向所有Worker发送心跳.
- 如果心跳超时,则将其标记为DOWN. 但并不会集群广播(因为已经失联了,其他集群也超时了,广播不广播用处不大,并且有可能仅仅和worker失联).
- 如果在此服务没有被踢掉(被新来的register_r挤掉)之前,如果心跳恢复,则状态恢复到ALIVE
###服务器类型
Master x1 <-> Auth, Role, Scene, Chat
Auth x1 <-> Gate, Master
Gate xN <-> Role, Scene, Chat
Role xN <-> Gate, Chat, Citywar
CityWar xN <-> Gate, Chat, Role
Chat x1 <-> CityWar, Role, Gate
League x1 <-> Gate, Role, Chat
Scene x1 <-> Gate
首先启动Master
Master启动后,会自动加载所有uid和cityid,
根据预定义RoleServer的个数预处理为M个slot为每个来注册的RoleServer分配一个slot中所包含的uid 根据预定义CitywarServer的个数预处理为M个slot为每个注册的CitywarServer分配一个slot所包含的cityid
服务注册与发现
每个服务采用register_r
向Master注册服务,当Master服务收到register_r
时
Master根据相应类型向此服务颁发其应该负责的ID. 然后会通过welcome_r
来通知所有已经注册过的服务器,'欢迎'已注册过的服务器.
每个服务器收到服务器之后.根据需要,通过query_r
向MasterServer拉到其责任ID,然后通过hello_r
来进行握手进行互联.
认证
- Client->AuthServer 发送**认证协议(比如挑战式认证)**进行认证
- AuthServer首先确认当前Account是否存在,如果不存在则直接创建,如果存在则验证登陆信息是否正确
- 如果正确,则查看是否有正在登陆玩家,如果有先踢下线,然后挑选出负载最低的GateServer
- 然后通过RPC向GateServer索取登陆token, 然后将此uid, token, GateServer的监听端口一并返回给客户端
- 客户端拿着uid, token向GateServer进行登陆
ps. AuthServer会定时向所有GateServer进行轮询, 检查当前负载数量
登陆
TODO:
###协议定义 error_code [ 0x00 --> OK 0x01 --> Fitting ] stabilize_r 0x0001 { instance { .type:string 1 .status:string 2 .listen:string 3 .slotid:integer 4 .instanceid:integer 5 } .instances:instance[] 1 } stabilize_a 0x0002 {
}
up_r 0x0003 {
.type:string 1
.listen:string 2
.slotid:integer 3
.instanceid:integer 4
}
up_a 0x0004 {
.result:integer 1
.status:string 2
.slotid:integer 3
.instanceid:integer 4
}
run_r 0x0005 {
.type:string 1
.listen:string 2
.slotid:integer 3
.instanceid:integer 4
}
run_a 0x0006 {
.result:integer 1
.status:string 2
}
heartbeat_r 0x0007 {
.type:string 1
.instanceid:integer 2
}
heartbeat_a 0x0008 {
.type:string 1
.instanceid:integer 2
}