>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…
A. The preface
It is important to understand the whole process of the Nacos Client when some operation exceptions directly break down during Nacos requests.
The main process of Nacos is divided into the following parts:
- Start and initialize the Nacos Client
- Nacos Client service registration
- Nacos Client service discovery
2. Start and initialize the Nacos Client
The automatic assembly class of Nacos is divided into two parts:
- NacosConfigAutoConfiguration
- NacosDiscoveryAutoConfiguration
The previous Nacos configuration loading process and priority already see the configuration process, this article focuses on NacosDiscoveryAutoConfiguration
2.1 Nacos Discovery auto-assembly class
During the startup of Nacos, the following objects are initialized in the configuration class:
- new NacosServiceManager()
- newNacosServiceDiscovery(discoveryProperties, nacosServiceManager) : get the list from the cache -new NacosDiscoveryClient(nacosServiceDiscovery)
Copy the code
2.1.1 Processing of NacosWatch
// C- NacosWatch
public void start(a) {
if (this.running.compareAndSet(false.true)) {
// Step 1: Build the EventListener object
EventListener eventListener = listenerMap.computeIfAbsent(buildKey(),
event -> new EventListener() {
@Override
public void onEvent(Event event) {
if (event instanceofNamingEvent) { List<Instance> instances = ((NamingEvent) event).getInstances(); Optional<Instance> instanceOptional = selectCurrentInstance(instances); instanceOptional.ifPresent(currentInstance -> { resetIfNeeded(currentInstance); }); }}});// Step 2: Prepare the NamingService object by NacosProperties -> 2.1.2 Step 2
NamingService namingService = nacosServiceManager
.getNamingService(properties.getNacosProperties());
try {
namingService.subscribe(properties.getService(), properties.getGroup(),
Arrays.asList(properties.getClusterName()), eventListener);
}
catch (Exception e) {
log.error("namingService subscribe failed, properties:{}", properties, e);
}
this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
this::nacosServicesWatch, this.properties.getWatchDelay()); }}Copy the code
2.1.2 Initialization Process
Step1: NacosWatch initiates monitoring
// NamingService init process
private void init(Properties properties) throws NacosException {
ValidatorUtils.checkInitParam(properties);
this.namespace = InitUtils.initNamespaceForNaming(properties);
InitUtils.initSerialization();
initServerAddr(properties);
// Initialize the Web container
InitUtils.initWebRootContext();
// Initialize the cache directory
initCacheDir();
// Initialize the log path
initLogName(properties);
this.eventDispatcher = new EventDispatcher();
// The proxy object is used to call the remote Server
this.serverProxy = new NamingProxy(this.namespace, this.endpoint, this.serverList, properties);
// Used to send heartbeat of registered service to Nacos server
this.beatReactor = new BeatReactor(this.serverProxy, initClientBeatThreadCount(properties));
// HostReactor Is used to obtain, save, and update Service instance information
this.hostReactor = new HostReactor(this.eventDispatcher, this.serverProxy, beatReactor, this.cacheDir,
isLoadCacheAtStart(properties), initPollingThreadCount(properties));
}
Copy the code
Step 2: NamingFactory Builds the NamingService
// The final instance object is actually produced by reflectionClass<? > driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
Constructor constructor = driverImplClass.getConstructor(Properties.class);
NamingService vendorImpl = (NamingService) constructor.newInstance(properties);
// Workspace
private String namespace;
//
private String endpoint;
// The Server address corresponding to the service list is localhost:8848
private String serverList;
// Local cache address
private String cacheDir;
// Log name: usually naming.log
private String logName;
private HostReactor hostReactor;
private BeatReactor beatReactor;
private EventDispatcher eventDispatcher;
private NamingProxy serverProxy;
Copy the code
Step 3: Add listeners to EventDispatcher
public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
throws NacosException {
// Update the Service with a listener
eventDispatcher.addListener(hostReactor
.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ",")),
StringUtils.join(clusters, ","), listener);
}
public void addListener(ServiceInfo serviceInfo, String clusters, EventListener listener) {
// Build an EventListener collection
List<EventListener> observers = Collections.synchronizedList(new ArrayList<EventListener>());
observers.add(listener);
// ConcurrentMap<String, List<EventListener>> observerMap
// There is a Notifier thread that continues processing instances through a while loop
// /nacos/v1/ns/instance
observers = observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(), clusters), observers);
if(observers ! =null) {
observers.add(listener);
}
// Refresh Service when change
serviceChanged(serviceInfo);
}
Copy the code
HostReactor. GetServiceInfo results:
3. Nacos Client service registration
Service registration involves the following processes:
NacosRegistration
: Saves basic service dataNacosServiceRegistry
: Implements service registrationNacosServiceRegistryAutoConfiguration
: Nacos automatic configuration class
Nacos service @ EnableDiscoveryClient is the starting point of registration, it will eventually call NacosAutoServiceRegistration:
- AbstractAutoServiceRegistration
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
// The default is true, and AutoServiceRegistration will be invoked when enabled
boolean autoRegister(a) default true;
}
Copy the code
3.1 start
Different registry, will have different implementation class, here is the corresponding Nacos NacosAutoServiceRegistration
// C- NacosAutoServiceRegistration
public void start(a) {
// If not enabled, return directly
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get()) {
this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
/ / call the Registry by registration: enclosing serviceRegistry. Register (getRegistration ());
register();
if (shouldRegisterManagement()) {
registerManagement();
}
this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));
this.running.compareAndSet(false.true); }}Copy the code
3.2 NacosServiceRegistry initiates registration
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
return;
}
// Build the current ServiceId and Group
NamingService namingService = namingService();
String serviceId = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
// Includes IP, port, assigned name, and metadata
Instance instance = getNacosInstanceFromRegistration(registration);
try {
// Register the current instance and add the heartbeat
// serverProxy.registerService(groupedServiceName, groupName, instance);
namingService.registerInstance(serviceId, group, instance);
}
catch (Exception e) {
log.error("nacos registry, {} register failed... {},", serviceId,
registration.toString(), e);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132rethrowRuntimeException(e); }}Copy the code
4. Discovery of services
We looked at it a little bit earlier in Nacos basics, but we’re just going to look at it again
Different versions of Nacos are acquired in different ways. Here we will focus on spring-cloud-starter-Alibaba-Nacos-Discovery: version 2.2.5.
4.1 Discovery of Nacos Server
Step 1: Initiate the starting point
private List<NacosServer> getServers(a) {
String group = discoveryProperties.getGroup();
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, group, true);
return instancesToServerList(instances);
}
Copy the code
Step 2: Main process of discovery
At this point, the logic is concatenated, followed by a reverse call to the interface provided in Nacos Server
// C- NacosNamingService
public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy,
boolean subscribe) throws NacosException {
ServiceInfo serviceInfo = hostReactor
.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ","));
return selectInstances(serviceInfo, healthy);
}
Copy the code
ServiceInfo: Map
serviceInfoMap
public void updateServiceNow(String serviceName, String clusters) {
ServiceInfo oldService = getServiceInfo0(serviceName, clusters);
try {
// Invoke the proxy class again
String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);
if(StringUtils.isNotEmpty(result)) { processServiceJson(result); }}catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to update serviceName: " + serviceName, e);
} finally {
if(oldService ! =null) {
synchronized(oldService) { oldService.notifyAll(); }}}}// Initiate a remote call
public String queryList(String serviceName, String clusters, int udpPort, boolean healthyOnly)
throws NacosException {
final Map<String, String> params = new HashMap<String, String>(8);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
params.put("clusters", clusters);
params.put("udpPort", String.valueOf(udpPort));
params.put("clientIP", NetUtils.localIP());
params.put("healthyOnly", String.valueOf(healthyOnly));
// You can see the API here:
return reqApi(UtilAndComs.nacosUrlBase + "/instance/list", params, HttpMethod.GET);
}
Copy the code
conclusion
This article is a little simple, not deep understanding, but it should be very useful, when there is a problem at the core of the break point, can save a lot of time
TODO: I will not draw the flow chart today, but I will have time to fill in one later