实例注册——服务端处理
RequestHandler
nacos所有request处理的父类,子类需要实现handle方法
package com.alibaba.nacos.core.remote;
/**
* Nacos based request handler.
*
*
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class RequestHandler<T extends Request, S extends Response> {
@Autowired
private RequestFilters requestFilters;
/**
* Handler request.
*/
public Response handleRequest(T request, RequestMeta meta) throws NacosException {
for (AbstractRequestFilter filter : requestFilters.filters) {
try {
Response filterResult = filter.filter(request, meta, this.getClass());
if (filterResult != null && !filterResult.isSuccess()) {
return filterResult;
}
} catch (Throwable throwable) {
Loggers.REMOTE.error("filter error", throwable);
}
}
return handle(request, meta);
}
/**
* Handler request.
*/
public abstract S handle(T request, RequestMeta meta) throws NacosException;
}
InstanceRequestHandler
RequestHandler的子类
需要留意这俩集合singletonRepository、namespaceSingletonMaps,这是v2版本中注册信息的数据结构,均是ConcurrentHashMap类型的集合
核心处理方法handle,是服务端InstanceRequest处理入口,会根据请求类型分别处理注册与注销。这里只看注册逻辑
registerInstance方法三块
- registerInstance 向服务注册实例
- publishEvent 发布RegisterInstanceTraceEvent
- 生成InstanceResponse返回
package com.alibaba.nacos.naming.remote.rpc.handler;
/**
* Instance request handler.
* 继承自 RequestHandler ,这是nacos处理reques的基类
* @author xiweng.yy
*/
@Component
public class InstanceRequestHandler extends RequestHandler<InstanceRequest, InstanceResponse> {
/**
* rpc的操作都是针对临时服务,http是持久服务
* v2中已将临时/持久提升到服务层级,而不再是实例级别
*/
private final EphemeralClientOperationServiceImpl clientOperationService;
public InstanceRequestHandler(EphemeralClientOperationServiceImpl clientOperationService) {
this.clientOperationService = clientOperationService;
}
@Override
@Secured(action = ActionTypes.WRITE)
public InstanceResponse handle(InstanceRequest request, RequestMeta meta) throws NacosException {
Service service = Service
.newService(request.getNamespace(), request.getGroupName(), request.getServiceName(), true);
//根据request类型分别处理注册与注销,其他抛异常
switch (request.getType()) {
case NamingRemoteConstants.REGISTER_INSTANCE:
return registerInstance(service, request, meta);
case NamingRemoteConstants.DE_REGISTER_INSTANCE:
return deregisterInstance(service, request, meta);
default:
throw new NacosException(NacosException.INVALID_PARAM,
String.format("Unsupported request type %s", request.getType()));
}
}
private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)
throws NacosException {
//注册实例
clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());
//由通知中心发布消息
NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),
meta.getClientIp(), true, service.getNamespace(), service.getGroup(), service.getName(),
request.getInstance().getIp(), request.getInstance().getPort()));
//生成InstanceResponse并返回
return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
}
private InstanceResponse deregisterInstance(Service service, InstanceRequest request, RequestMeta meta) {
//与注册基本相同,这里略过
......
}
}
1、EphemeralClientOperationServiceImpl.registerInstance
rpc的操作都是针对临时服务,http是持久服务,这里是rpc请求处理,所以是EphemeralClientOperationServiceImpl,而不是PersistentClientOperationServiceImpl
接口ClientOperationService是客户端操作服务(注册、批量注册、注销、订阅、取消订阅、实例转为发布实例),共有三个实现类,分别是临时、持久及临时与持久的组合(内部根据实例的 是否临时属性确定使用哪个)
package com.alibaba.nacos.naming.core.v2.service.impl;
/**
* Operation service for ephemeral clients and services.
*
* @author xiweng.yy
*/
@Component("ephemeralClientOperationService")
public class EphemeralClientOperationServiceImpl implements ClientOperationService {
private final ClientManager clientManager;
/**
* 直接指定 ClientManagerDelegate
* @param clientManager
*/
public EphemeralClientOperationServiceImpl(ClientManagerDelegate clientManager) {
this.clientManager = clientManager;
}
@Override
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
// 1 从缓存中取得服务
Service singleton = ServiceManager.getInstance().getSingleton(service);
if (!singleton.isEphemeral()) {
throw new NacosRuntimeException(NacosException.INVALID_PARAM,
String.format("Current service %s is persistent service, can't register ephemeral instance.",
singleton.getGroupedServiceName()));
}
// 2 从缓存中取得client
Client client = clientManager.getClient(clientId);
if (!clientIsLegal(client, clientId)) {
return;
}
// 3 将实例转为服务端实例,为当前client添加服务下实例
InstancePublishInfo instanceInfo = getPublishInfo(instance);
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
client.recalculateRevision();
// 4 发布事件 ClientRegisterServiceEvent
NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
// 4 发布事件 InstanceMetadataEvent
NotifyCenter
.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
}
@Override
public void batchRegisterInstance(Service service, List<Instance> instances, String clientId) {
//略
}
@Override
public void deregisterInstance(Service service, Instance instance, String clientId) {
//略
}
@Override
public void subscribeService(Service service, Subscriber subscriber, String clientId) {
//略
}
@Override
public void unsubscribeService(Service service, Subscriber subscriber, String clientId) {
//略
}
private boolean clientIsLegal(Client client, String clientId) {
if (client == null) {
return false;
}
if (!client.isEphemeral()) {
return false;
}
return true;
}
}
1.1、ServiceManager.getInstance().getSingleton(service)
这是nacos v2 中注册信息的数据结构,重点关注这俩集合singletonRepository、namespaceSingletonMaps。
package com.alibaba.nacos.naming.core.v2;
/**
* Nacos service manager for v2.
* 重点关注这俩集合singletonRepository、namespaceSingletonMaps
* 这是nacos v2 中注册信息的数据结构
*/
public class ServiceManager {
private static final ServiceManager INSTANCE = new ServiceManager();
/**
* singletonRepository的类型
*/
private final ConcurrentHashMap<Service, Service> singletonRepository;
/**
* namespaceSingletonMaps的类型,key为命名空间
*/
private final ConcurrentHashMap<String, Set<Service>> namespaceSingletonMaps;
private ServiceManager() {
//初始化集合size=1024
singletonRepository = new ConcurrentHashMap<>(1 << 10);
//初始化集合size=4
namespaceSingletonMaps = new ConcurrentHashMap<>(1 << 2);
}
public static ServiceManager getInstance() {
return INSTANCE;
}
public Set<Service> getSingletons(String namespace) {
return namespaceSingletonMaps.getOrDefault(namespace, new HashSet<>(1));
}
/**
* Get singleton service. Put to manager if no singleton.
*
* @param service new service
* @return if service is exist, return exist service, otherwise return new service
*/
public Service getSingleton(Service service) {
//如果singletonRepository中不存在当前service,则存入当前service
singletonRepository.putIfAbsent(service, service);
//取出singletonRepository中所存储的service(之前有就取出来,)
Service result = singletonRepository.get(service);
//如果namespaceSingletonMaps中没有service对应命名空间则存入当前service对应的命名空间
namespaceSingletonMaps.computeIfAbsent(result.getNamespace(), (namespace) -> new ConcurrentHashSet<>());
//将当前service对应命名空间存入namespaceSingletonMaps
namespaceSingletonMaps.get(result.getNamespace()).add(result);
return result;
}
//其他省略
......
}
1.2、ClientManagerDelegate.getClient
ClientManager 的委托代理,会根据方法 getClientManagerById 的结果决定使用哪个 ClientManager。具体实现很简洁
package com.alibaba.nacos.naming.core.v2.client.manager;
/**
* Client manager delegate.
* ClientManager 的委托代理,会根据方法 getClientManagerById 的结果决定使用哪个 ClientManager
* @author xiweng.yy
*/
@DependsOn({"clientServiceIndexesManager", "namingMetadataManager"})
@Component("clientManager")
public class ClientManagerDelegate implements ClientManager {
private final ConnectionBasedClientManager connectionBasedClientManager;
private final EphemeralIpPortClientManager ephemeralIpPortClientManager;
private final PersistentIpPortClientManager persistentIpPortClientManager;
public ClientManagerDelegate(ConnectionBasedClientManager connectionBasedClientManager,
EphemeralIpPortClientManager ephemeralIpPortClientManager,
PersistentIpPortClientManager persistentIpPortClientManager) {
this.connectionBasedClientManager = connectionBasedClientManager;
this.ephemeralIpPortClientManager = ephemeralIpPortClientManager;
this.persistentIpPortClientManager = persistentIpPortClientManager;
}
@Override
public boolean clientConnected(String clientId, ClientAttributes attributes) {
return getClientManagerById(clientId).clientConnected(clientId, attributes);
}
@Override
public boolean clientConnected(Client client) {
return getClientManagerById(client.getClientId()).clientConnected(client);
}
@Override
public boolean syncClientConnected(String clientId, ClientAttributes attributes) {
return getClientManagerById(clientId).syncClientConnected(clientId, attributes);
}
@Override
public boolean clientDisconnected(String clientId) {
return getClientManagerById(clientId).clientDisconnected(clientId);
}
@Override
public Client getClient(String clientId) {
return getClientManagerById(clientId).getClient(clientId);
}
@Override
public boolean contains(String clientId) {
return connectionBasedClientManager.contains(clientId) || ephemeralIpPortClientManager.contains(clientId)
|| persistentIpPortClientManager.contains(clientId);
}
@Override
public Collection<String> allClientId() {
Collection<String> result = new HashSet<>();
result.addAll(connectionBasedClientManager.allClientId());
result.addAll(ephemeralIpPortClientManager.allClientId());
result.addAll(persistentIpPortClientManager.allClientId());
return result;
}
@Override
public boolean isResponsibleClient(Client client) {
return getClientManagerById(client.getClientId()).isResponsibleClient(client);
}
@Override
public boolean verifyClient(DistroClientVerifyInfo verifyData) {
return getClientManagerById(verifyData.getClientId()).verifyClient(verifyData);
}
/**
* 这是最关键的,决定具体的 ClientManager
* @param clientId
* @return
*/
private ClientManager getClientManagerById(String clientId) {
if (isConnectionBasedClient(clientId)) {
return connectionBasedClientManager;
}
return clientId.endsWith(ClientConstants.PERSISTENT_SUFFIX) ? persistentIpPortClientManager : ephemeralIpPortClientManager;
}
//略
}
1.3、将实例转为服务端实例,为当前client添加服务实例
//3 将实例转为服务端实例,为当前client添加服务下实例
InstancePublishInfo instanceInfo = getPublishInfo(instance);
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
client.recalculateRevision();
调用IpPortBasedClient.addServiceInstance方法
//这里的client对应 IpPortBasedClient
@Override
public boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo) {
return super.addServiceInstance(service, parseToHealthCheckInstance(instancePublishInfo));
}
调用父类AbstractClient.addServiceInstance方法,这里又发布了一个事件 ClientChangedEvent
/**
* publishers 类型 ConcurrentHashMap<Service, InstancePublishInfo>
*/
protected final ConcurrentHashMap<Service, InstancePublishInfo> publishers = new ConcurrentHashMap<>(16, 0.75f, 1);
/**
* subscribers 类型 ConcurrentHashMap<Service, Subscriber>
*/
protected final ConcurrentHashMap<Service, Subscriber> subscribers = new ConcurrentHashMap<>(16, 0.75f, 1);
@Override
public boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo) {
// 将服务与服务端实例存入map,一个服务下只有一个实例的
if (null == publishers.put(service, instancePublishInfo)) {
// 做统计处理
if (instancePublishInfo instanceof BatchInstancePublishInfo) {
MetricsMonitor.incrementIpCountWithBatchRegister(instancePublishInfo);
} else {
MetricsMonitor.incrementInstanceCount();
}
}
// 发布 ClientChangedEvent
NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
Loggers.SRV_LOG.info("Client change for service {}, {}", service, getClientId());
return true;
}
1.4、NotifyCenter.publishEvent
通过统一事件通知中心发布事件,解耦+异步。nacos里有大量的事件发布,都是通过这个工具类实现的。
这里先后发布了两个事件: ClientRegisterServiceEvent、InstanceMetadataEvent
2、NotifyCenter.publishEvent
发布 RegisterInstanceTraceEvent 事件
3、InstanceResponse
生成InstanceResponse并返回
整体流程
之前的流程少了1.3部分,补上