选举
在RAFT算法领域中,有三种基本的状态(角色):follower、candidate、leader。
- 处于follower状态的server不会发起任何的request,只是被动的响应leader和candidate。
- 处于leader状态的server会主动的发送心跳包给各个follower,并且接收client所有的request。
- 而candidate是一种过渡状态,只有整个cluster在进行新的选举的时候,才会出现此种状态的server。
问题解决
稳定性需求:
- 任何一个节点挂了,都不影响 服务的注册/网关获取
- 所有节点挂了,已有的服务不影响.
- 注册中心的自身性能保障与告警
- 任意一个节点支持随时可以重启/扩容/缩容 不影响其他节点
1、支持
2、支持
3、引入hystris进行熔断
4、注册中心节点支持随意扩容
业务性需求:
- 注册/订阅/视图
- 5秒一次心跳+3~4000/5===>qps:1000
- 合理使用缓存提供业务需求
- 节点之间如何通信/要不要通信
- 服务节点下线如何通知到网关/注册中心
[x] 4、节点间不需要通信
[x] 5、服务上线需要开发手动点击上线再进行上线和目前的上线到nginx保持一致,下线同样,存在的问题下线不能及时通知到网关。可以拓展对网关进行一次通知
需求点
用途
- 注册IP和端口怎么定?
- tomcat
- SpringBoot
- 自定义jar包
- 实现服务治理还需要注册哪些信息?
- 是否开启TLS
- 权重
- 是否开启(上下线)
- 生产环境/灰度环境
- 机房标签/流量路由
- 如何优雅的进行服务上下线
- 上线是可控的,人为控制
- 下线是不可控,出现异常问题,人为操作问题等等,能不能在出现问题时及时下线并通知到网关层
- 注册服务的健康检查
- 心跳功能
- 客户端心跳
- 服务端心跳
- 心跳功能
- 服务节点加入或者退出或者新的节点加入时,订阅者能不能及时通知到
- 基于
socket的长链接,如zk - 基于http的长轮训
- 基于
- 能不能方便的查看某个应用发布和订阅了哪些服务,以及所订阅的服务有哪些节点
性能
- 服务端性能
- 服务发现的容灾策略
- 应用和服务发现出现网路问题如何处理
- 注册中心宕机一台或者全宕机对我有没有影响
- 服务注册和服务发现安全吗
radar 开发指南
- radar-core 包含一些公用的方法和公用的dto对象。是所有项目的基础
- radar-biz , 项目注册中心radar-rest 和 portal 界面的业务逻辑层,里面包含数据库实体和dal访问对象,供radar-rest 和 radar-ui使用
- radar-dependency-rest
- radar-dependency-ui
- radar-rest radar-rest注册中心
- radar-ui portal界面
- radar-client\radar-client-core 此项目是radar的原生客户端,基本不依赖任何第三方jar包,除了http访问,比较轻量级,封装了一些客户端接口
- radar-client\radar-client-spring 此项目是在原生客户端的基础上,做了一些spring 封装,以简化操作,和提供了一些统计接口
- radar-client-springboot 此项目是在spring客户端的基础上,为springboot做了一些自动化加载配置
- radar-client-springboot-ribbon 相当于一个rpc客户端,当服务端注册到radar上后,可以直接利用radar ribbon客户端访问服务端提供的服务,默认负载是轮询
zuul引入记录
1、EnableZuulProxy引入了,ZuulProxyMarkerConfiguration.class
注意,大部分的Enable都是通过使用@Import注解实现的,引入一个具体的@Configuration 这里使用过该注解,引入一个类,而Zuul通过ConditionMissBean引入
Nacos
spring-cloud-alibaba-nacos-discovery 模块
1、依赖nacos spring-cloud-common,cloud-context,cloud-starter-netflix-ribbon ,cloud-config-client,cloud-config-server
服务注册流程
注册实例流程
- 获取服务地址,共2种方式
第一个:直接设置server_addr=127.0.0.1:1111,127.0.0.1:2222,127.0.0.1:3333
第二个:设置endpoint: 127.0.0.1
内部请求地址:127.0.0.1:8080 ===> 获取配置的127.0.0.1:1111,127.0.0.1:2222,127.0.0.1:3333
注意:这里的8080是代码写死,endpoint只需要设置IP地址即可,设置endpoint会覆盖server_addr
- 注册
调用NacosNamingService#registerInstance, 该对象为发射获取,如果是临时实例(默认临时),设置发起心跳的定时任务. 随后进行注册
注册逻辑:随机选取n台服务器中的一台发起http请求
心跳逻辑:选取一台,5s中后发起一次心跳请求,然后根据心跳请求中的值发起下次请求,例如心跳返回值为1秒,1秒后发起请求,为5s,5s后发起请求
List<String> azz = Arrays.asList("1", "2", "#", "$");Random random = new Random(System.currentTimeMillis());int index = random.nextInt(azz.size());for (int i = 0; i < azz.size(); i++) {String server = azz.get(index);System.out.println(server);index = (index + 1) % azz.size();}
定时同步数据
- 初始化,DataSyncer#startTimedSync将TimedSync注册为一个每隔5s同步一次的定时任务
- 同步逻辑,获取全部的key,「过滤掉」自己不能处理的key,将剩下的key同步给其他服务器,NamingProxy#syncCheckSums 对比checksum,由目标服务器进行key校验,如果不符合,到目标服务器进行同步
对比接口:/v1/ns/distro/checksum ===> DistroConsistencyServiceImpl#onReceiveChecksums ===> 整理key
同步接口:/v1/ns/distro/datum ===> 同步完成后处理 DistroConsistencyServiceImpl#processData
/*** 如何确定自己是否能处理这个key* @return true serviceName 能被localServer处理,false转发 {@link DistroMapper#mapSrv(String)} 处理*/public boolean responsible(String serviceName) {if (!switchDomain.isDistroEnabled() || SystemUtils.STANDALONE_MODE) {return true;}if (CollectionUtils.isEmpty(healthyList)) {// means distro config is not ready yetreturn false;}//index==lastIndex ==> trueint index = healthyList.indexOf(NetUtils.localServer());if (index < 0) {return true;}int target = distroHash(serviceName) % healthyList.size();return target == index;}
同步新提交数据
3.1 时序图,注册临时实例
InstanceController#register--> ServiceManager#registerInstance--> ServiceManager#addInstance--> ConsistencyService#put--> DistroConsistencyServiceImpl#put--> taskDispatcher#putaddTask--> TaskScheduler#addTask(入队列)--> DataSyncer#submit(异步执行,一定条件下触发)--> NamingProxy#syncData(异步执行,put请求,发送给其他服务节点)
服务监听
1、服务注册时会加入一个定时任务,定时移除
不健康的实例, 分别是15s后标记为不健康的实例,30s后将该实例删除掉。删除规则:向自己发起一个http请求delete http://nacos.superboss.cc/nacos/v1/ns/instance?ip=x&port=x&ephemeral=true&cluster&service&namespace=x
2、处理删除请求,
InstanceController, 移除实例,实际保存的数据也发生了变化,实际数据=以前的数据-这次删除的实例数据 ,实际数据对上次的进行覆盖,并且触发一个onChange的监听器事件,触发自己变更,在队列中加入一个事件,该事件是用来批量同步数据到其他服务节点的,获取到这些变更数据,然后发送给其他的服务器,发送链接为 /v1/ns/distro/datum put请求, 同时这个节点数据只有自己能处理的数据才会被处理掉
网关改造
1、如何让ServerList和定时路由之间的同步
- 启动
- 服务定时同步,这个量不会很大,定时全量同步也不会对服务端有什么大的影响, 影响接口 /nacos/v1/ns/service/list 获取服务列表 作为路由
- 更新
