背景:
我們當前的微服務架構采用的是 SpringCloud 全家桶 + dubbo + druid + apllo 等技術集成的。
1、多服務實例相同端口沖突問題
目前線上服務器內容動輒 128 ~ 256GB,我們一個服務最大內存設置不超過 32GB,那么為了有效利用服務器資源,我們都會在一台服務器上啟動多個服務實例。那此時如果配置文件中配置寫死了一個固定的 port 就會發生 dubbo 服務端口沖突。需要將 dubbo 的端口設置為 隨機端口,具體如下所示:
dubbo: scan: base-packages: com.search.bs protocol: name: dubbo port: -1 #20881,將原來寫死的 20881 改為隨機,默認端口為 20880 serialization: hessian2
2、mysql 加載超時問題
鏈接 mysql 我們使用的是 druid 的數據庫連接池,我們當前業務涉及到正排加載,而有的業務線數據量較大,且得到對應需要的正排內容加載查詢的時候會很慢,導致前一個加載完成后緊接着加載第二個內容的時候,此時 mysql 鏈接不可用,或者當前的鏈接耗時太長也導致不可用狀態:
druid: #初始化大小,最小,最大 initial-size: 10 max-active: 300 min-idle: 5 #配置獲取連接等待超時的時間 max-wait: 300000 #檢測連接是否有效的sql validation-query: "select '1'" validation-query-timeout: 2000 #從連接池里面獲取連接時都會測試連接的有效性。這個是獲取一個穩定連接最簡單有效的手段,前提是如果你的性能要求不是非常高 test-on-borrow: true test-on-return: false #對已經取到的connection進行連接有效性的檢測 test-while-idle: true #配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 time-between-eviction-runs-millis: 60000 #配置一個連接在池中最小生存的時間,單位是毫秒 min-evictable-idle-time-millis: 300000 remove-abandoned: true
其中最重要的是將:test-on-borrow 設置為 true,因為我們只是在初始化的時候加載正排,所以無所謂性能要求。
3、服務注冊回調異常
有一同事的 mac 升級為最新版本,導致最近的整個微服務架構啟動不起來了,一直卡在某個錯誤上,先來看一段警告信息:
[2020-04-14 18:19:49,391][dev][WARN][main][] o.a.d.c.AbstractConfig - [DUBBO] Connection refused (Connection refused), dubbo version: 2.7.3, current host: 172.18.18.95 java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at org.apache.dubbo.config.ServiceConfig.findConfigedHosts(ServiceConfig.java:698) at org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:560) at org.apache.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:457) at org.apache.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:415) at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:378) at org.apache.dubbo.config.spring.ServiceBean.export(ServiceBean.java:336) at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:114) at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:60) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:140) at com.mfw.search.bs.SearchBsBootstrap.main(SearchBsBootstrap.java:23)
此時該服務在 nacos 注冊中心是已經注冊成功的,但是對應的服務 ip 為:127.0.0.1,而從日志中報出來的信息當前 ip 為:172.18.18.95,從異常信息中直觀的可以看到是 socke 拒絕連接,也就是說:
在本地啟動dubbo時,服務注冊在 nacos 上,但是注冊IP卻不是本地的iP。產生問題,導致consumer 找不到provider ,訪問不了服務。
- 例如 本地IP為 172.18.18.95 ,但是 nacos 上的注冊 ip 可能是 127.0.0.1
從網上查了好多說修改 /etc/hosts,但是並沒有解決這個問題,而且明明之前是好使的,周邊沒有升級的小伙伴使用他當前 git 分支代碼啟動也是一點問題都沒有,這就奇怪了,難道真的是mac 電腦升級導致的嗎?
但是不管是不是升級導致的,這個問題還是需要解決的。首先我們需要明確問題的原因:
1. 客戶端向 nacos 發起請求注冊成功
2. 通過服務端回調的時候通過 127.0.0.1 無法回調回去(因為你的真實 ip 為 172.18.18.95),導致 socket 拒絕連接
debug dubbo 代碼發現,在 NetUtils
中的 getLocalAddress0
這個方法,獲取到的 ip 為 localhost/127.0.0.1,而且設置完對應的 hosts 也不受影響,所以我們的想法也很簡單,需要改動 dubbo 的相關配置來約束相應的 ip 地址:(只有本地環境可能會發生這種問題,線上不會存在,所以在一定程度上可以這么做)
dubbo: scan: base-packages: com.mfw.search.bs protocol: name: dubbo port: -1 serialization: hessian2 host: 172.18.18.95 #指定好當前本機 ip 地址
相應的 spring相關配置也需要指定當前注冊的服務的 ip 地址為某個段內的,可以將 127.0.0.1 屏蔽掉:
spring: autoconfigure: exclude: - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration application: name: search-bs-lyx #應用名。很重要!是注冊中心的主鍵,gateway路由也需要靠它 main: allow-bean-definition-overriding: true cloud: nacos: #采用nacos注冊中心 discovery: enabled: true register-enabled: true namespace: 6947fa15-b976-45f4-b121-4c05e802e8xx endpoint: 'nacosendpoint.mtech.svc.ab:8098' inetutils: preferred-networks: 172 #限定選擇前綴為 172 的 ip
這樣就能解決以上問題,一般情況下 dubbo 是不需要指定 ip 的,但是如果不指定解決不了再指定一定會解決掉問題,這個主要就是綁定 nacos 注冊的時候使用的 ip 地址
而 spring 規范的前綴 ip,這個主要是指定 nacos 注冊的服務分配的 ip,具體如下圖的一個服務啟動在 nacos 中的服務注冊情況,可以對照 dubbo 和 spring 配置的 ip 來區分對待: