1. nacos server 端接收请求
在 naming模块中的InstanceController中接收nacos客户端的注册实例的请求。
/**
* Register new instance.
*
* @param request http request
* @return 'ok' if success
* @throws Exception any error during register
*/
@CanDistro
@PostMapping
@Secured(action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils
.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
NamingUtils.checkServiceNameFormat(serviceName);
final Instance instance = HttpRequestInstanceBuilder.newBuilder()
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
// 注册实例信息
getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(), "", false, namespaceId,
NamingUtils.getGroupName(serviceName), NamingUtils.getServiceName(serviceName), instance.getIp(),
instance.getPort()));
return "ok";
}
InstanceOperator 是一个接口,它具有注册实例,移除实例,更新实例信息,查询实例信息,处理心跳信息等接口。实现类为 InstanceOperatorClientImpl。
注册实例的接口需要传入参数有:namespaceId, serviceName, instance
/**
* Register an instance to a service in AP mode.
*
* @param namespaceId id of namespace
* @param serviceName grouped service name group@@service
* @param instance instance to register
* @throws NacosException nacos exception when register failed
*/
void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException;
2. InstanceOperatorClientImpl 的实现
/**
* This method creates {@code IpPortBasedClient} if it don't exist.
*/
@Override
public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
boolean ephemeral = instance.isEphemeral();
String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
createIpPortClientIfAbsent(clientId);
//查询服务
Service service = getService(namespaceId, serviceName, ephemeral);
clientOperationService.registerInstance(service, instance, clientId);
}
ClientOperationService也是一个接口,它具有注册实例,批量注册实例,取消注册实例,订阅服务,取消订阅服务这些方法。
它的实现类包括ClientOperationServiceProxy, EphemeralClientOperationServiceImpl,PersistentClientOperationServiceImpl。其中ClientOperationServiceProxy的实现如下
@Override
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
final ClientOperationService operationService = chooseClientOperationService(instance);
operationService.registerInstance(service, instance, clientId);
}
它会根据实例是否为临时的选择对应的实现类,进行注册实例。
private ClientOperationService chooseClientOperationService(final Instance instance) {
return instance.isEphemeral() ? ephemeralClientOperationService : persistentClientOperationService;
}
3. EphemeralClientOperationServiceImpl
它的实现注册实例逻辑主要包括:
1. 根据 clientId 获取client
2. 根据 instance 获取 InstancePublishInfo
3. 调用 client.addServiceInstance(singleton, instanceInfo) 注册实例信息
@Override
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
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()));
}
Client client = clientManager.getClient(clientId);
if (!clientIsLegal(client, clientId)) {
return;
}
InstancePublishInfo instanceInfo = getPublishInfo(instance);
//注册实例
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
client.recalculateRevision();
NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
NotifyCenter
.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
}
InstancePublishInfo 包括实例名称,ip, port, 是否健康,cluster 名称, 还有扩展参数的map
/**
* get publish info.
*
* @param instance {@link Instance}
* @return {@link InstancePublishInfo}
*/
default InstancePublishInfo getPublishInfo(Instance instance) {
InstancePublishInfo result = new InstancePublishInfo(instance.getIp(), instance.getPort());
Map<String, Object> extendDatum = result.getExtendDatum();
if (null != instance.getMetadata() && !instance.getMetadata().isEmpty()) {
extendDatum.putAll(instance.getMetadata());
}
if (StringUtils.isNotEmpty(instance.getInstanceId())) {
extendDatum.put(Constants.CUSTOM_INSTANCE_ID, instance.getInstanceId());
}
if (Constants.DEFAULT_INSTANCE_WEIGHT != instance.getWeight()) {
extendDatum.put(Constants.PUBLISH_INSTANCE_WEIGHT, instance.getWeight());
}
if (!instance.isEnabled()) {
extendDatum.put(Constants.PUBLISH_INSTANCE_ENABLE, instance.isEnabled());
}
String clusterName = StringUtils.isBlank(instance.getClusterName()) ? UtilsAndCommons.DEFAULT_CLUSTER_NAME
: instance.getClusterName();
result.setHealthy(instance.isHealthy());
result.setCluster(clusterName);
return result;
}
Client 是一个接口 ,它包括接口有:
public interface Client {
/**
* Get the unique id of current client.
*
* @return id of client
*/
String getClientId();
/**
* Whether is ephemeral of current client.
*
* @return true if client is ephemeral, otherwise false
*/
boolean isEphemeral();
/**
* Set the last time for updating current client as current time.
*/
void setLastUpdatedTime();
/**
* Get the last time for updating current client.
*
* @return last time for updating
*/
long getLastUpdatedTime();
/**
* Add a new instance for service for current client.
*
* @param service publish service
* @param instancePublishInfo instance
* @return true if add successfully, otherwise false
*/
boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo);
/**
* Remove service instance from client.
*
* @param service service of instance
* @return instance info if exist, otherwise {@code null}
*/
InstancePublishInfo removeServiceInstance(Service service);
/**
* Get instance info of service from client.
*
* @param service service of instance
* @return instance info
*/
InstancePublishInfo getInstancePublishInfo(Service service);
/**
* Get all published service of current client.
*
* @return published services
*/
Collection<Service> getAllPublishedService();
/**
* Add a new subscriber for target service.
*
* @param service subscribe service
* @param subscriber subscriber
* @return true if add successfully, otherwise false
*/
boolean addServiceSubscriber(Service service, Subscriber subscriber);
/**
* Remove subscriber for service.
*
* @param service service of subscriber
* @return true if remove successfully, otherwise false
*/
boolean removeServiceSubscriber(Service service);
/**
* Get subscriber of service from client.
*
* @param service service of subscriber
* @return subscriber
*/
Subscriber getSubscriber(Service service);
/**
* Get all subscribe service of current client.
*
* @return subscribe services
*/
Collection<Service> getAllSubscribeService();
/**
* Generate sync data.
*
* @return sync data
*/
ClientSyncData generateSyncData();
/**
* Whether current client is expired.
*
* @param currentTime unified current timestamp
* @return true if client has expired, otherwise false
*/
boolean isExpire(long currentTime);
/**
* Release current client and release resources if neccessary.
*/
void release();
/**
* Recalculate client revision and get its value.
* @return recalculated revision value
*/
long recalculateRevision();
/**
* Get client revision.
* @return current revision without recalculation
*/
long getRevision();
/**
* Set client revision.
* @param revision revision of this client to update
*/
void setRevision(long revision);
}
它的实现类为一个抽象类 AbstractClient ,它里面实现了addServiceInstance这个方法。
4. AbstractClient 实现注册实例信息
protected final ConcurrentHashMap<Service, InstancePublishInfo> publishers = new ConcurrentHashMap<>(16, 0.75f, 1);
可以看到, 最终是把注册的实例信息保存在内存的hashMap中。key 为service, value为 instancePublishInfo. 可以根据服务信息查询到该服务的实例信息。
@Override
public boolean addServiceInstance(Service service, InstancePublishInfo instancePublishInfo) {
if (null == publishers.put(service, instancePublishInfo)) {
if (instancePublishInfo instanceof BatchInstancePublishInfo) {
MetricsMonitor.incrementIpCountWithBatchRegister(instancePublishInfo);
} else {
MetricsMonitor.incrementInstanceCount();
}
}
NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
Loggers.SRV_LOG.info("Client change for service {}, {}", service, getClientId());
return true;
}
Service 的属性包括: 命名空间, 分组名称,服务名称,是否临时的
public class Service implements Serializable {
private static final long serialVersionUID = -990509089519499344L;
private final String namespace;
private final String group;
private final String name;
private final boolean ephemeral;
private final AtomicLong revision;
private long lastUpdatedTime;
}