服务的下线相比服务的注册主要少了客户端创建及客户端的健康检查任务和客户端发布事件的功能,初次之外,服务端跟客户端的逻辑基本都是再相同的处理类里面,如果很好的理解了服务注册的流程和逻辑,服务下线的流程就很容易理解。
目录
流程图
请求处理入口
public String deregister(HttpServletRequest request) throws Exception {
//根据请求参数构建Instance
Instance instance = HttpRequestInstanceBuilder.newBuilder().
setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).
setRequest(request).build();
//获取命名空间id
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
Constants.DEFAULT_NAMESPACE_ID);
//带有groupname的服务名
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
//检查服务吗是不是带有groupname groupName@@serviceName
NamingUtils.checkServiceNameFormat(serviceName);
//这里 getInstanceOperator() 得到的是 InstanceOperatorClientImpl 类型对象
getInstanceOperator().removeInstance(namespaceId, serviceName, instance);
return "ok";
}
服务下线处理入口
public class InstanceOperatorClientImpl implements InstanceOperator {
...
@Override
public void removeInstance(String namespaceId, String serviceName, Instance instance) {
boolean ephemeral = instance.isEphemeral();
String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
//如果客户端管理器没有这个client 直接返回
if (!clientManager.contains(clientId)) {
Loggers.SRV_LOG.warn("remove instance from non-exist client: {}", clientId);
return;
}
//构建服务对象
Service service = getService(namespaceId, serviceName, ephemeral);
//clientOprationService 这里的类型时 ClientOperationServiceProxy 代理类
clientOperationService.deregisterInstance(service, instance, clientId);
}
...
}
public class ClientOperationServiceProxy implements ClientOperationService {
...
@Override
public void deregisterInstance(Service service, Instance instance, String clientId) {
//服务管理器中是否存在该服务
//还记得服务管理器中胡服务是怎么放进去吗
//在EphemeralClientOperationServiceImpl胡服务注册胡逻辑里第一行代码就是交给
//服务管理器管理服务
if (!ServiceManager.getInstance().containSingleton(service)) {
Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", service);
return;
}
//这里同注册服务的原理一样选择持久化还是临时处理类
//ephemeralClientOperationService persistenceClientOperationService
final ClientOperationService operationService =
chooseClientOperationService(instance);
//接下来进入具体的persistenceClientOperationService处理逻辑
operationService.deregisterInstance(service, instance, clientId);
}
...
}
服务下线核心逻辑
// EphemeralClientOperationServiceImpl 临时客户端管理器 这个类我们又见面了 哈哈
// 后面我们有好多复杂的、重要的类反复出现再不同的篇章中
// 逐步加深对他们的印象 所谓一回生两会熟
public class EphemeralClientOperationServiceImpl implements ClientOperationService {
@Override
public void deregisterInstance(Service service, Instance instance, String clientId) {
//二次校验服务是否存在
if (!ServiceManager.getInstance().containSingleton(service)) {
Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", service);
return;
}
//这里从服务管理拿到服务
Service singleton = ServiceManager.getInstance().getSingleton(service);
//这里从客户端管理器拿到客户端
Client client = clientManager.getClient(clientId);
if (!clientIsLegal(client, clientId)) {
return;
}
//客户端移除服务
InstancePublishInfo removedInstance = client.removeServiceInstance(singleton);
//设置最近更新时间
client.setLastUpdatedTime();
if (null != removedInstance) {
//发布客户端下线事件 从ClientServiceIndexesManager 列表表删除服务下该client
//的发布信息 和 服务元数据变更事件
NotifyCenter.publishEvent(new
ClientOperationEvent.ClientDeregisterServiceEvent(singleton,
clientId));
//把该实例的元数据过期 参考 NamingMetadataManager
NotifyCenter.publishEvent(
new MetadataEvent.InstanceMetadataEvent(singleton,
removedInstance.getMetadataId(), true));
}
}
}
总结
真正的服务下线的核心逻辑包括
1、客户端移除该服务的发布信息
需要注意的是这里并不是移除客户端而是客户端里面的对该服务的发布记录要移除掉
那么如果一个客户端下既没有发布的服务又么有订阅的服务,什么时候要清理呢。这个前面将客户端的时候其实已经讲了 EphemeralIpPortClientManager又一个定时清理任务 ExpiredClientCleaner 5秒钟执行一次 如果记不起来回头去看下
2、事件通知 ClientServiceIndexesManager 移除该服务的实例信息
3、在ClientServiceIndexesManager移除服务实例信息后又发布了ServiceEvent.ServiceChangedEvent 事件[该事件的处理逻辑参考前一篇文章],注意通过upd或者grpc方式通知该服务的订阅方。
4、事件通知 移除该实例的元数据信息 这块流程在前面关于注册事件的注册事件的篇章中