Nacos的地址服务器功能源码浅析

地址服务模式

nacos官方有一个环境隔离实践的博文,在那篇博文中,阿里巴巴给出的例子是采用nginx以及一个组件实现根据客户端的IP信息路由到不同的nacos集群中去

官方博文——阿里巴巴基于 Nacos 实现环境隔离的实践

源码解析

地址服务器添加nacos-server节点

根据官方的介绍,只需要发起一个http请求即可动态的添加nacos-server节点

# Add IP to nacos cluster:
curl -X POST ‘$ADDRESS_SERVER:8080/nacos/v1/as/nodes?ips=1.1.1.1:8848,2.2.2.2:8848,3.3.3.3:8848’

# Remove IP from nacos cluster:

curl -X DELETE ‘$ADDRESS_SERVER:8080/nacos/v1/as/nodes?ips=1.1.1.1:8848,2.2.2.2:8848,3.3.3.3:8848’

这里巧妙的复用了nacos中服务发现的功能,将nacos-server也作为一个服务注册到nacos-server上,这样就可以实现动态的管理nacos节点

节点添加、删除源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity postCluster(@RequestParam(required = false) String product,
@RequestParam(required = false) String cluster,
@RequestParam(name = "ips") String ips) {

//1. prepare the storage name for product and cluster
String productName = addressServerGeneratorManager.generateProductName(product);
String clusterName = addressServerManager.getDefaultClusterNameIfEmpty(cluster);

//2. prepare the response name for product and cluster to client
String rawProductName = addressServerManager.getRawProductName(product);
String rawClusterName = addressServerManager.getRawClusterName(cluster);
Loggers.addressLogger.info("put cluster node,the cluster name is " + cluster + "; the product name=" + product + "; the ip list=" + ips);
ResponseEntity responseEntity;
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);

Cluster clusterObj = new Cluster();
clusterObj.setName(clusterName);
clusterObj.setHealthChecker(new AbstractHealthChecker.None());
serviceManager.createServiceIfAbsent(Constants.DEFAULT_NAMESPACE_ID, serviceName, false, clusterObj);
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = AddressServerParamCheckUtil.checkIps(ipArray);
if (AddressServerParamCheckUtil.CHECK_OK.equals(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
for (Instance instance : instanceList) {
serviceManager.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
responseEntity = ResponseEntity.ok("product=" + rawProductName + ",cluster=" + rawClusterName + "; put success with size=" + instanceList.size());
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}
} catch (Exception e) {
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return responseEntity;
}

通过上面这种操作以及nacos的服务数据同步,就可以将新增的nacos-server节点同步到所有的nacos-server节点上,并且依托nacos自带的健康检查功能,自动的判断不健康的nacos-server实例信息,这样,nacos-client只需要通过向地址服务器请求nacos-server这个服务,就可以自动的得知nacos-server节点变化的动态感知

客户端请求nacos-server服务信息

请求源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping(value = "/{product}/{cluster}", method = RequestMethod.GET)
public ResponseEntity getCluster(@PathVariable String product,
@PathVariable String cluster) {

String productName = addressServerBuilderManager.generateProductName(product);
String serviceName = addressServerBuilderManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
if (service == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + " not found.");
}

if (!service.getClusterMap().containsKey(cluster)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + ",cluster=" + cluster + " not found.");
}

Cluster clusterObj = service.getClusterMap().get(cluster);
return ResponseEntity.status(HttpStatus.OK).body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
}

这里的实现非常简单,客户端仅仅需要像请求服务一样去请求nacos-server服务即可