本文将从一个服务注册示例入手,通过阅读客户端、服务端源码,分析服务注册、服务发现原理。
使用的2.0.2的版本。
客户端
创建NacosNamingService对象
NacosNamingService nacosNamingService = new NacosNamingService(NACOS_HOST);
NacosNamingService提供两个构造方法:
public NacosNamingService(String serverList) throws NacosException {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
init(properties);
}
public NacosNamingService(Properties properties) throws NacosException {
init(properties);
}
第二个方法的properties的key在PropertyKeyConst常量类可以找到,如:
- namespace
- username
- password
- serverAddr
- clusterName
- 其他
构造方法中会初始化一些参数和组件:
-
初始化namespace参数
-
创建InstancesChangeNotifier对象,它实现了Subscriber接口,监听InstancesChangeEvent事件
public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> { // key使用serviceName + groupName + clusters组合而成 // value是监听器集合 private final Map<String, ConcurrentHashSet<EventListener>> listenerMap; // 锁 private final Object lock = new Object();
-
向NotifyCenter注册InstancesChangeEvent事件,注册之前创建的InstancesChangeNotifier对象监听服务实例变化
NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384); NotifyCenter.registerSubscriber(changeNotifier); // NotifyCenter维护着EventPublisher集,Subscriber会被注册到EventPublisher上 // EventPublisher提供publish方法向Event队列推送事件 // EventPublisher是一个Thread类,run方法从Event队列取事件通知Subscriber来处理
-
创建NamingClientProxyDelegate对象,用于与服务端通信,它是一个代理,内部使用其他的NamingClientProxy实现:
- NamingHttpClientProxy
- NamingGrpcClientProxy - 默认使用该实现类,其中有healthCheck检测服务端是否健康,服务端直接响应成功无操作
服务注册
NacosNamingService nacosNamingService = new NacosNamingService(NACOS_HOST);
nacosNamingService.registerInstance(ORDER_SERVICE, "192.168.0.100", 9999);
提供多个重载的registerInstance方法,最终使用这个方法:
public void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName)
throws NacosException {
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setWeight(1.0);
instance.setClusterName(clusterName);
registerInstance(serviceName, groupName, instance);
}
public void registerInstance(String serviceName, String groupName, Instance instance)
throws NacosException {
// 此处clientProxy是NamingClientProxyDelegate对象
clientProxy.registerService(serviceName, groupName, instance);
}
NamingClientProxyDelegate的registerService方法会选择一个具体的NamingClientProxy对象与服务端通信,默认使用NamingGrpcClientProxy对象。
NamingGrpcClientProxy的registerService方法构建InstanceRequest请求对象,之后使用RpcClient对象发送请求并接收响应。
RpcClient内部通过GrpcConnection对象使用GRPC来访问服务端。
内部的GRPC代码是使用protoc和protobuf-maven-plugin生成的,通信细节此处不做介绍。
服务下线
nacosNamingService.deregisterInstance(ORDER_SERVICE, "192.168.0.100", 9999);
deregisterInstance服务下线:
public void deregisterInstance(String serviceName,
String groupName,
String ip,
int port,
String clusterName) throws NacosException {
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setClusterName(clusterName);
deregisterInstance(serviceName, groupName, instance);
}
public void deregisterInstance(String serviceName,
String groupName,
Instance instance) throws NacosException {
clientProxy.deregiste