前言
本文素材來源朋友學習nacos2.1.1踩到的坑。直接上正菜
坑點一:出現端口被佔用
因為是學習使用,朋友就在物理機搭建了搭建了nacos偽集羣,即ip都一樣,端口分別為8848,8847,8849。然而啓動nacos服務器後,一台正常啓動,其他兩台都報了端口被佔用
出現這種情況的原因,官網有做了解釋
通過官網我們可以很容易得知,這個端口被佔用主要是因為grpc引起的,因為他端口的生成方式,是由主端口+1000、主端口+1001生成。
解決方法
集羣的端口不要採用相鄰數字,步長儘量搞大點。比如設置為7777、8888、9999之類的
坑二:微服務項目啓動出現com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTING異常
這個問題出現在朋友在項目中配置的nacos地址為nginx地址,配置示例如下
spring.cloud.nacos.discovery.server-addr=nginx ip
一開始朋友nginx的配置示例如下
upstream nacos-cluster {
server 127.0.0.1:7777;
server 127.0.0.1:8888;
server 127.0.0.1:9999;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nacos-cluster;
}
}
瀏覽器通過nginx訪問沒問題,但是項目中把nacos服務地址配置為nginx ip就報了
com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTING
這個異常信息,後面朋友查資料,官網上有寫
於是他就將轉發方式改為TCP,他的nginx版本是1.9+以上版本,默認就支持TCP代理了,不用額外安裝stream模塊。nginx配置TCP的示例形如下
stream {
upstream nacos-cluster-grpc{
# nacos2版本,grpc端口與要比主端口多1000,主端口為7777、8888、9999
server 127.0.0.1:8777;
server 127.0.0.1:9888;
server 127.0.0.1:10999;
}
server{
listen 9848;
proxy_pass nacos-cluster-grpc;
}
}
當朋友配置好nginx tcp代理轉發後,通過telnet命令
telnet 127.0.0.1 9848
來看是否能正常轉發給nacos服務端,經過驗證,網絡可以連通。接着朋友在微服務項目的nacos配置填寫如下地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:9848 #nginx代理tcp的地址
本來以為萬事大吉,結果項目一啓動,仍然報
com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTING
於是朋友懵了,啥情況?就來找我交流一下
其實在nacos官網的FAQ就有提到相應的解題思路了
因為我們在nginx配置的代理tcp端口為9848,這個端口可以看成是grpc的端口,因為grpc的端口 = nacos主端口 + 1000,因此我們套這個公式就可以得出,nacos的主端口為 = 9848 - 1000 = 8848,而我們微服務項目配置nacos端口,其實配置是主端口,因此實際上我們配置要寫成
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #nginx代理tcp端口 - 1000
配置這個後,果然成功註冊。這個思路是官網帶給我們的,但作為一個有點追求的程序員應該不會僅僅滿足與此,我們可以直接根據控制枱報出的異常來獲取答案
異常排查過程就省略了,直接貼出關鍵的解題代碼
1、首先解析主端口號的核心代碼
位置在
com.alibaba.nacos.common.remote.client.RpcClient#resolveServerInfo
ServerInfo private RpcClient.ServerInfo resolveServerInfo(String serverAddress) {
Matcher matcher = EXCLUDE_PROTOCOL_PATTERN.matcher(serverAddress);
if (matcher.find()) {
serverAddress = matcher.group(1);
}
String[] ipPortTuple = serverAddress.split(":", 2);
int defaultPort = Integer.parseInt(System.getProperty("nacos.server.port", "8848"));
String serverPort = (String)CollectionUtils.getOrDefault(ipPortTuple, 1, Integer.toString(defaultPort));
return new RpcClient.ServerInfo(ipPortTuple[0], NumberUtils.toInt(serverPort, defaultPort));
}
2、其次設置grpc端口的核心代碼
位置在:
com.alibaba.nacos.common.remote.client.grpc.GrpcClient#connectToServer
端口設置就是在截圖圈紅部分,然後從this.rpcPortOffset()我們可以發現
public int rpcPortOffset() {
return Integer.parseInt(System.getProperty("nacos.server.grpc.port.offset", String.valueOf(Constants.SDK_GRPC_PORT_DEFAULT_OFFSET)));
}
這個偏移量是可以通過nacos.server.grpc.port.offset進行修改,不修改默認就是1000。因此跟蹤源碼,我們可以得出另外一種解法。在微服務的nacos配置仍然填代理的nginx 的tcp地址,示例
spring.cloud.nacos.discovery.server-addr=127.0.0.1:9848 #nginx代理tcp的地址
同時啓動的時候,加上
-Dnacos.server.grpc.port.offset=0
或者在主啓動類硬編碼也 可以
System.setProperty("nacos.server.grpc.port.offset","0");
注: 這邊很重要的細節點就是:GRPC port = 主端口 + grpc端口偏移量,這個計算出來的端口值要和nginx代理tcp 端口值相等。
總結
因為朋友用的是目前最新版的nacos2,所以有些問題搜索引擎不是那麼好找答案,因此遇到這種問題,最好的解題思路就是官網和相應的github,還有就是源碼跟蹤了。
後面那個
Client not connected, current status:STARTING,其實還有一種解法,就是把客户端版本調低到1.x版本,因為這個問題本質上是連接不上grpc問題,因此我們可以不用grpc,直接用http就好了,而2.x服務端版本是同時支持http和grpc,因此客户端版本調成1.x,他就是以http的方式和服務端進行交互。不過是不建議這麼做,因為你升級了2.x,有一方面就是為高性能,如果把版本降低,那還不如直接使用1.x就好了。
還有文中的那兩種解法,我個人是建議不要改偏移量,直接通過主端口 + 1000這種方式去算就好了