在 nacos-client:2.x 中,如果启动了naocs2.x的服务不修改任何端口的情况下是可以正常连接的。
在docker下运行了 nacos 并且指定跟主机绑定 “8848:8848” 端口
cloud 中配置
spring.cloud.nacos.discovery.server-addr=http://172.1.6.41:8848spring.cloud.nacos.config.server-addr=http://172.1.6.41:8848
在nacos服务启动正常下,Spring Cloud 连接会抛出一个异常为:
c.a.n.c.remote.client.grpc.GrpcClient :Server check fail, please check server 172.1.6.41 ,port 9848 is available , error ={}java.util.concurrent.ExecutionException: com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
那是因为Nacos2.x版本相比1.X新增了gRPC的通信方式,因此需要增加2个端口。新增端口是在配置的主端口(server.port)基础上,进行一定偏移量自动生成
端口 | 与主端口的偏移量 | 描述 |
---|---|---|
9848 | 1000 | 客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求 |
9849 | 1001 | 服务端gRPC请求服务端端口,用于服务间同步等 |
那只是因为docker映射的端口缺少了,把剩下两个也补齐就正常了
ports: - "8848:8848" - "9848:9848" - "9849:9849"
如果需要修改 8848 的端口,比如尝试把 8848修改成38848
ports: - "38848:8848" - "39848:9848" - "39849:9849"
修改成这样之后连接配置就变成了38848 也是没有问题的
spring.cloud.nacos.discovery.server-addr=http://172.1.6.41:38848spring.cloud.nacos.config.server-addr=http://172.1.6.41:38848
如果39848 端口被其他应用占用,则需要设置一个其他端口
ports: - "38848:8848" - "39849:9848" - "39849:9849"
但是此时cloud连接nacos之后client 会根据 38848 进行偏移1000,而我们端口已经改成了39849,rpc是连接不上的,所以我们可以看看rpc的偏移到底是如何实现
我们可以从错误信息中获取到他是 c.a.n.c.remote.client.grpc.GrpcClient 这个类型下抛出来的错误。把这个类型名字直接放入IDEA,让智能提示帮我们找到这个类型是 import com.alibaba.nacos.common.remote.client.grpc.GrpcClient;,从结构上看一共有以下这些方法
com.alibaba.nacos.common.remote.client.grpc.GrpcClient#GrpcClient(java.lang.String)com.alibaba.nacos.common.remote.client.grpc.GrpcClient#GrpcClient(java.util.Properties)com.alibaba.nacos.common.remote.client.grpc.GrpcClient#GrpcClient(com.alibaba.nacos.common.remote.client.grpc.GrpcClientConfig)com.alibaba.nacos.common.remote.client.grpc.GrpcClient#GrpcClient(com.alibaba.nacos.common.remote.client.grpc.GrpcClientConfig, com.alibaba.nacos.common.remote.client.ServerListFactory)com.alibaba.nacos.common.remote.client.grpc.GrpcClient#GrpcClient(java.lang.String, java.lang.Integer, java.lang.Integer, java.util.Map<java.lang.String,java.lang.String>)com.alibaba.nacos.common.remote.client.grpc.GrpcClient#getConnectionTypecom.alibaba.nacos.common.remote.client.grpc.GrpcClient#createGrpcExecutorcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#shutdowncom.alibaba.nacos.common.remote.client.grpc.GrpcClient#createNewChannelStubcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#createNewManagedChannelcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#shuntDownChannelcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#serverCheckcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#bindRequestStreamcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#sendResponsecom.alibaba.nacos.common.remote.client.grpc.GrpcClient#connectToServercom.alibaba.nacos.common.remote.client.grpc.GrpcClient#LOGGERcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#clientConfigcom.alibaba.nacos.common.remote.client.grpc.GrpcClient#grpcExecutor
找到 public Connection connectToServer(ServerInfo serverInfo)方法
@Override public Connection connectToServer(ServerInfo serverInfo) { try { if (grpcExecutor == null) { this.grpcExecutor = createGrpcExecutor(serverInfo.getServerIp()); } int port = serverInfo.getServerPort() + rpcPortOffset(); ManagedChannel managedChannel = createNewManagedChannel(serverInfo.getServerIp(), port); RequestGrpc.RequestFutureStub newChannelStubTemp = createNewChannelStub(managedChannel); if (newChannelStubTemp != null) { Response response = serverCheck(serverInfo.getServerIp(), port, newChannelStubTemp); if (response == null || !(response instanceof ServerCheckResponse)) { shuntDownChannel(managedChannel); return null; } BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc .newStub(newChannelStubTemp.getChannel()); GrpcConnection grpcConn = new GrpcConnection(serverInfo, grpcExecutor); grpcConn.setConnectionId(((ServerCheckResponse) response).getConnectionId()); //create stream request and bind connection event to this connection. StreamObserver<Payload> payloadStreamObserver = bindRequestStream(biRequestStreamStub, grpcConn);
可以看到 port 是通过serverInfo.getServerPort() + rpcPortOffset(); 拼接起来的,serverInfo.getServerPort()就是通过配置文件读取过来的,那就只需要知道 rpcPortOffset(); 方法是获取值就可以了,它是一个抽象方法
public abstract int rpcPortOffset();
这个方法由 GrpcSdkClient 和 GrpcClusterClient 两个类型分别实现
GrpcClusterClient @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(GrpcConstants.NACOS_SERVER_GRPC_PORT_OFFSET_KEY, String.valueOf(Constants.CLUSTER_GRPC_PORT_DEFAULT_OFFSET))); }
GrpcSdkClient @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(GrpcConstants.NACOS_SERVER_GRPC_PORT_OFFSET_KEY, String.valueOf(Constants.SDK_GRPC_PORT_DEFAULT_OFFSET))); }
两个类型实现都是先从环境变量的 GrpcConstants.NACOS_SERVER_GRPC_PORT_OFFSET_KEY = nacos.server.grpc.port.offset 进行获取偏移量,如果获取不到则设置成常量Constants.SDK_GRPC_PORT_DEFAULT_OFFSET =1000
public static final Integer SDK_GRPC_PORT_DEFAULT_OFFSET = 1000;
所以只需要设置一下nacos.server.grpc.port.offset 配置即可,偏移量就是RPC端口 39849- 38848 的出来的数值,nacos.server.grpc.port.offset = RPC端口 - Nacos端口
来源地址:https://blog.csdn.net/Dizzilys/article/details/129883720