客户端如何发起服务注册?怎么发送服务心跳?(AP模式下)
首先服务注册是在服务启动的时候进行注册的,
我们的应用服务端的application.yml中配置了spring.cloud.nacos.discovery相关的参数:nacos服务端的地址,namespace,cluster-name等
我们的应用服务服务启动的时候,会加载application.yml并解析成NacosDiscoveryProperties类
NacosRegistration类的一个属性就是NacosDiscoveryProperties,所以 NacosRegistration也存放要注册的服务的相关配置信息
服务启动会调用NacosServiceRegistry.register方法:
1.获得服务名,group:有默认分组
2.getNacosInstanceFromRegistration将NacosRegistration封装成一个Instance
3.namingService.registerInstance(serviceId, group, instance) 真正的进行服务注册
4.NacosNamingService.registerInstance
下面展示一些 内联代码片
。
// 如果是临时实例,进行心跳检测
if (instance.isEphemeral()) {
BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
beatReactor.addBeatInfo(groupedServiceName, beatInfo);
}
//定时发送心跳
executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
// 进行注册
serverProxy.registerService(groupedServiceName, groupName, instance);
以上是客户端那边的流程
下面是服务端的流程:
1.Instancecontroller.register 服务端的注册入口
2.ServiceManager.registerInstance
首先存放服务的是一个双重Map
Map(namespace, Map(group::serviceName, Service))
service也是一个map,Map<String,cluster>
第一层map的key是一个拼起来的字符串,
createEmptyService----》createServiceIfAbsent—》putServiceAndInit—》service.init()—》HealthCheckReactor.scheduleCheck(clientBeatCheckTask)—》ClientBeatCheckTask.run()方法------在创建服务实例的时候进行服务的心跳检测(线程)
//核心代码
List<Instance> instances = service.allIPs(true);//获得所有临时实例
// first set health status of instances:
for (Instance instance : instances) {
if (System.currentTimeMillis() - instance.getLastBeat() > instance.getInstanceHeartBeatTimeOut()//当前时间与最后实例心跳时间的差值如果大于配置的心跳时间,表示该实例健康状态为false,默认的心跳时间是15s,然后以事件发布的形式通知客户端
) {
if (!instance.isMarked()) {
if (instance.isHealthy()) {
instance.setHealthy(false);
Loggers.EVT_LOG
.info("{POS} {IP-DISABLED} valid: {}:{}@{}@{}, region: {}, msg: client timeout after {}, last beat: {}",
instance.getIp(), instance.getPort(), instance.getClusterName(),
service.getName(), UtilsAndCommons.LOCALHOST_SITE,
instance.getInstanceHeartBeatTimeOut(), instance.getLastBeat());
getPushService().serviceChanged(service);
ApplicationUtils.publishEvent(new InstanceHeartbeatTimeoutEvent(this, instance));
}
}
}
}
代码一直往下走,得到真正的注册逻辑:就是把实例数据放到一个map中
DistroConsistencyServiceImpl.put方法
@Override
public void put(String key, Record value) throws NacosException {
onPut(key, value);//tasks.offer(Pair.with(datumKey, action));//放到一个队列里面
distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
globalConfig.getTaskDispatchPeriod() / 2);//然后同步到
}
//该run方法就是从队列中取数据进行处理
@Override
public void run() {
Loggers.DISTRO.info("distro notifier started");
for (; ; ) {
try {
Pair<String, DataOperation> pair = tasks.take();
handle(pair);
} catch (Throwable e) {
Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
}
}
}
// An highlighted block
var foo = 'bar';
// An highlighted block
var foo = 'bar';
服务端这边的心跳:
客户端向服务端这边发送心跳,服务端这边的处理逻辑:
ClientBeatProcessor类,有run方法
获取所有的临时实例,遍历,设置lastBeat,设置healthy属性,然后以事件发布的形式通知??????????????