文章目录
前言
本文对Nacos 服务端的端口监听进行介绍。
一、BaseRpcServer 介绍:
在 Nacos 中,BaseRpcServer 是一个基础的远程过程调用(RPC)服务器组件,用于处理 Nacos 集群内部节点之间的远程通信和调用。其主要作用包括:
-
提供远程服务调用接口:BaseRpcServer 作为一个 RPC 服务器,提供了远程服务调用的接口,使得集群中的各个节点能够通过网络进行相互调用。通过 BaseRpcServer,节点之间可以实现远程调用服务的功能。
-
底层网络通信支持:BaseRpcServer 封装了底层的网络通信实现,处理了网络连接建立、消息的传输、数据的序列化和反序列化等操作。它负责管理和维护集群节点之间的通信通道,确保节点之间可以安全、可靠地进行通信。
-
处理远程调用请求:BaseRpcServer 接收来自其他节点的远程调用请求,并将请求转发给相应的服务处理器进行处理。它负责解析和分发远程调用请求,将请求分发给正确的服务实现,并返回调用结果。
-
集群节点通信协调:BaseRpcServer 在集群节点之间起到协调和调度的作用,通过 RPC 通信协议,实现集群中各个节点之间的信息交换和服务调用。它能够促进集群内部节点之间的协作和信息交流。
总的来说,BaseRpcServer 是 Nacos 集群中用于处理节点之间远程调用和通信的基础组件,承担着网络通信、远程调用、消息处理等功能。它起到了连接集群节点、协调节点之间工作、实现分布式服务调用等作用,是保证 Nacos 集群正常运行和通信的重要组件。
二、GrpcSdkServer 9848 端口监听:
GrpcSdkServer extends BaseGrpcServer 所以在构建 GrpcClusterServer bean 时 ,回先构建BaseGrpcServer 对象:
2.1 端口监听:
@PostConstruct
public void start() throws Exception {
// 获取实例化的bean名称 GrpcSdkServer/GrpcClusterServer
String serverName = getClass().getSimpleName();
Loggers.REMOTE.info("Nacos {} Rpc server starting at port {}", serverName, getServicePort());
// 启动 端口监听
startServer();
// 管理和刷新 RPC 服务器 SSL 上下文
if (RpcServerSslContextRefresherHolder.getInstance() != null) {
RpcServerSslContextRefresherHolder.getInstance().refresh(this);
}
Loggers.REMOTE.info("Nacos {} Rpc server started at port {}", serverName, getServicePort());
// jvm 退出 进行方法的回调 资源释放
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Loggers.REMOTE.info("Nacos {} Rpc server stopping", serverName);
try {
BaseRpcServer.this.stopServer();
Loggers.REMOTE.info("Nacos {} Rpc server stopped successfully...", serverName);
} catch (Exception e) {
Loggers.REMOTE.error("Nacos {} Rpc server stopped fail...", serverName, e);
}
}));
}
2.2 开启端口监听:
@Override
public void startServer() throws Exception {
// 创建多处理器监测对象
final MutableHandlerRegistry handlerRegistry = new MutableHandlerRegistry();
// 增加各种handler 处理器 ,用于处理客户端的请求
// getSeverInterceptors() 服务端的拦截器,addServices 添加服务端的请求处理器
addServices(handlerRegistry, getSeverInterceptors().toArray(new ServerInterceptor[0]));
// grpc构建要监听的 端口
// getServicePort() 8848 + 偏移量 GrpcClusterServer +1001 ; GrpcSdkServer +1000
// getRpcExecutor 获取GrpcClusterServer 或者 GrpcSdkServer 的线程池
NettyServerBuilder builder = NettyServerBuilder.forPort(getServicePort()).executor(getRpcExecutor());
// 创建grpc 调用存根
Optional<InternalProtocolNegotiator.ProtocolNegotiator> negotiator = newProtocolNegotiator();
if (negotiator.isPresent()) {
InternalProtocolNegotiator.ProtocolNegotiator actual = negotiator.get();
Loggers.REMOTE.info("Add protocol negotiator {}", actual.getClass().getCanonicalName());
builder.protocolNegotiator(actual);
}
// 添加处理服务器端传输层过滤器的组件,主要作用是在服务器端对传入的请求进行预处理和处理
for (ServerTransportFilter each : getServerTransportFilters()) {
builder.addTransportFilter(each);
}
// Server 端netty 初始化
server = builder.maxInboundMessageSize(getMaxInboundMessageSize()).fallbackHandlerRegistry(handlerRegistry)
.compressorRegistry(CompressorRegistry.getDefaultInstance())
.decompressorRegistry(DecompressorRegistry.getDefaultInstance())
.keepAliveTime(getKeepAliveTime(), TimeUnit.MILLISECONDS)
.keepAliveTimeout(getKeepAliveTimeout(), TimeUnit.MILLISECONDS)
.permitKeepAliveTime(getPermitKeepAliveTime(), TimeUnit.MILLISECONDS).build();
// 服务器监听端口
server.start();
}
2.2.1 客户端请求处理器:
(1) 客户端请求处理器添加 addServices:
private void addServices(MutableHandlerRegistry handlerRegistry, ServerInterceptor... serverInterceptor) {
// unary common call register. 注册普通的注册器
// unaryPayloadMethod 进行方法的定义
final MethodDescriptor<Payload, Payload> unaryPayloadMethod = MethodDescriptor.<Payload, Payload>newBuilder()
.setType(MethodDescriptor.MethodType.UNARY).setFullMethodName(MethodDescriptor
.generateFullMethodName(GrpcServerConstants.REQUEST_SERVICE_NAME,
GrpcServerConstants.REQUEST_METHOD_NAME))
.setRequestMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();
// 定义处理器,客户端调用服务端 交由payloadHandler 处理器处理请求
final ServerCallHandler<Payload, Payload> payloadHandler = ServerCalls.asyncUnaryCall(
(request, responseObserver) -> grpcCommonRequestAcceptor.request(request, responseObserver));
// 定义一个 Request 服务名称 并绑定unaryPayloadMethod 方法对应的处理器是 payloadHandler
final ServerServiceDefinition serviceDefOfUnaryPayload = ServerServiceDefinition
.builder(GrpcServerConstants.REQUEST_SERVICE_NAME).addMethod(unaryPayloadMethod, payloadHandler)
.build();
// 将定义好的方法处理绑定到grpc server 上
handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfUnaryPayload, serverInterceptor));
// bi stream register. 注册双向流的 处理器
final ServerCallHandler<Payload, Payload> biStreamHandler = ServerCalls.asyncBidiStreamingCall(
(responseObserver) -> grpcBiStreamRequestAcceptor.requestBiStream(responseObserver));
// 定义方法描述
final MethodDescriptor<Payload, Payload> biStreamMethod = MethodDescriptor.<Payload, Payload>newBuilder()
.setType(MethodDescriptor.MethodType.BIDI_STREAMING).setFullMethodName(MethodDescriptor
.generateFullMethodName(GrpcServerConstants.REQUEST_BI_STREAM_SERVICE_NAME,
GrpcServerConstants.REQUEST_BI_STREAM_METHOD_NAME))
.setRequestMarshaller(ProtoUtils.marshaller(Payload.newBuilder().build()))
.setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();
// 定义一个 BiRequestStream 服务名称 biStreamMethod 方法对应的处理器是 biStreamHandler
final ServerServiceDefinition serviceDefOfBiStream = ServerServiceDefinition
.builder(GrpcServerConstants.REQUEST_BI_STREAM_SERVICE_NAME).addMethod(biStreamMethod, biStreamHandler)
.build();
// 将定义好的方法处理绑定到grpc server 上
handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfBiStream, serverInterceptor));
}
(2)grpc 请求存根:
nacos_grpc_service.proto:
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
import "google/protobuf/any.proto";
import "google/protobuf/timestamp.proto";
option java_multiple_files = true;
option java_package = "com.alibaba.nacos.api.grpc.auto";
message Metadata {
string type = 3;
string clientIp = 8;
map<string, string> headers = 7;
}
message Payload {
Metadata metadata = 2;
google.protobuf.Any body = 3;
}
// 普通请求处理对应 payloadHandler 处理器
service Request {
// Sends a commonRequest 调用 payloadHandler # request
rpc request (Payload) returns (Payload) {
}
}
// 流请求 处理对应 biStreamHandler
service BiRequestStream {
// Sends a biStreamRequest 调用 BiRequestStream # requestBiStream
rpc requestBiStream (stream Payload) returns (stream Payload) {
}
}
2.2.2 监听端口启动:
public ServerImpl start() throws IOException {
synchronized(this.lock) {
// 获取锁
// 正在启动 & 服务没有停掉 状态监测
Preconditions.checkState(!this.started, "Already started");
Preconditions.checkState(!this.shutdown, "Shutting down");
// 创建监听器
// 服务器端监控和处理各种事件的发生,以及向客户端发送事件通知 监听
ServerListenerImpl listener = new ServerListenerImpl();
// netty 端口监听
this.transportServer.start(listener);
this.executor = (Executor)Preconditions.checkNotNull((Executor)this.executorPool.getObject(), "executor");
this.started = true;
return this;
}
}
2.2.3 netty 端口的绑定:
this.transportServer.start(listener) 方法中,进行端口绑定的关键方法;
Future<Map<ChannelFuture, SocketAddress>> bindCallFuture = this.bossExecutor.submit(new Callable<Map<ChannelFuture, SocketAddress>>() {
public Map<ChannelFuture, SocketAddress> call() {
Map<ChannelFuture, SocketAddress> bindFutures = new HashMap();
Iterator var2 = NettyServer.this.addresses.iterator();
while(var2.hasNext()) {
SocketAddress address = (SocketAddress)var2.next();
// 0.0.0.0/0.0.0.0:9848 / 0.0.0.0/0.0.0.0:9849 端口的监听
ChannelFuture future = b.bind(address);
NettyServer.this.channelGroup.add(future.channel());
bindFutures.put(future, address);
}
return bindFutures;
}
});
三、GrpcClusterServer 9849 端口监听
GrpcClusterServer extends BaseGrpcServer 所以在构建 GrpcClusterServer bean 时 ,回先构建BaseGrpcServer 对象:同GrpcSdkServer 流程相同,不同的是开通 9849 进行端口的监听;
总结:
Nacos 服务端在启动时 实际上会对3个端口进行监听:
- 8848+ 1000 = 9848 GrpcsdkServer 客户端与服务端连接的端口,用于客户端向服务端发起连接和请求;
- 8848+ 1001 = 9849 GrpcClusterServer 服务端gRPC请求服务端端口,用于服务间同步等;
- 8848- 1000 = 7848 jraft请求服务端端口,用于处理服务端间的Raft相关请求;