文章目录
前言
当客户端的实例注册到nacos 集群中某一台节点后,此时需要给集群中其它的节点推送节点注册实例信息,从而保证数据的最终一致性协议。集群的节点之间通过建立grpc 连接实现消息的发送,本文对服务端nacos 集群间节点grpc 连接建立,进行介绍,服务端版本 3.0.13。
一、服务端 grpc 通道:
nacos 服务端集群内的节点,需要建立连接,从而保证节点中数据的一致性;nacos 对实例的注册和获取采用了是AP模式(可用性+分区容错性),要保证nacos 集群节点数据的最终一致性,在nacos 的内部实现中使用了distro协议。
distro协议是 Nacos 社区自研的一种 AP 分布式协议,是面向临时实例设计的一种分布式协议其保证了在某些 Nacos 节点宕机后,整个临时实例处理系统依旧可以正常工作。作为一种有状态的中间件应用的内嵌协议,Distro 保证了各个 Nacos 节点对于海量注册请求的统一协调和存储。
二、 grpc 通道建立过程:
集群内节点通道的建立是由 ClusterRpcClientProxy负责的;
2.1 ClusterRpcClientProxy bean 后置处理:
@Autowired
ServerMemberManager serverMemberManager;
/**
* init after constructor.
*/
@PostConstruct
public void init() {
try {
// 订阅者注册
NotifyCenter.registerSubscriber(this);
// 获取集群内除了自己的节点
List<Member> members = serverMemberManager.allMembersWithoutSelf();
// 建立grpc 连接
refresh(members);
Loggers.CLUSTER
.info("[ClusterRpcClientProxy] success to refresh cluster rpc client on start up,members ={} ",
members);
} catch (NacosException e) {
Loggers.CLUSTER.warn("[ClusterRpcClientProxy] fail to refresh cluster rpc client,{} ", e.getMessage());
}
}
2.2 refresh 通道建立:
获取到集群内的其它节点,然后进行遍历分别与其建连接,最后关闭之前建立的过时连接;
/**
* init cluster rpc clients.
*
* @param members cluster server list member list.
*/
private void refresh(List<Member> members) throws NacosException {
//ensure to create client of new members
for (Member member : members) {
// grpc 连接建立
createRpcClientAndStart(member, ConnectionType.GRPC);
}
//shutdown and remove old members.
// 关闭之前建立的旧连接
Set<Map.Entry<String, RpcClient>> allClientEntrys = RpcClientFactory.getAllClientEntries();
Iterator<Map.Entry<String, RpcClient>> iterator = allClientEntrys.iterator();
List<String> newMemberKeys = members.stream().map(this::memberClientKey).collect(Collectors.toList());
while (iterator.hasNext()) {
Map.Entry<String, RpcClient> next1 = iterator.next();
if (next1.getKey().startsWith("Cluster-") && !newMemberKeys.contains(next1.getKey())) {
Loggers.CLUSTER.info("member leave,destroy client of member - > : {}", next1.getKey());
RpcClient client = RpcClientFactory.getClient(next1.getKey());
if (client != null) {
RpcClientFactory.getClient(next1.getKey()).shutdown();
}
iterator.remove();
}
}
}
2.3 createRpcClientAndStart 通道建立:
获取到节点的ip 和端口,然后在client.start() 的 connectToServer(serverInfo) 进行通道的建立;
private void createRpcClientAndStart(Member member, ConnectionType type) throws NacosException {
Map<String, String> labels = new HashMap<>(2);
labels.put(RemoteConstants.LABEL_SOURCE, RemoteConstants.LABEL_SOURCE_CLUSTER);
// "Cluster-"+ip + ":" + port;
String memberClientKey = memberClientKey(member);
// 创建GrpcClusterClient 客户端
RpcClient client = buildRpcClient(type, labels, memberClientKey);
if (!client.getConnectionType().equals(type)) {
Loggers.CLUSTER.info("connection type changed,destroy client of member - > : {}", member);
RpcClientFactory.destroyClient(memberClientKey);
client = buildRpcClient(type, labels, memberClientKey);
}
if (client.isWaitInitiated()) {
Loggers.CLUSTER.info("start a new rpc client to member - > : {}", member);
//one fixed server
client.serverListFactory(new ServerListFactory() {
@Override
public String genNextServer() {
return member.getAddress();
}
@Override
public String getCurrentServer() {
return member.getAddress();
}
@Override
public List<String> getServerList() {
return CollectionUtils.list(member.getAddress());
}
});
// 连接建立
client.start();
}
}
2.3 client.start() 通道建立:
集群内节点连接的建立,同客户端与服务端连接建立过程相同,这里不在进行累述;
可通过:源码篇–Nacos服务–中章(5):Nacos客户端启动-实例注册-grpc连接建立,中的 2.3.2.2 start 长连接建立 ;
源码篇–Nacos服务–中章(6):Nacos客户端启动-grpc通道建立&客户端服务信息获取(故障转移)细节 查看连接的详细建立过程;
总结
本文对集群内节点之间通过建立grpc 连接过程进行介绍。