SpringCloud、dubbo 和 druid 問題總結


背景:

  我們當前的微服務架構采用的是 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 來區分對待:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM