前幾年我在做微服務部件升級時,將Dubbo的注冊中心從Zookeeper切換到Nacos。切換的原因是有2點:
切換完之后,奇怪的事情發生了,出現2個現象:
出現這種問題時,剛開始有點抓瞎,但是我們只能從常規的手段一點點排查,急不來。通過表面的現象,我們來逐步分析。
現象一:微服務啟動很慢很慢,一直在打印大量的nacos請求日志。日志如下:
現象二:JVM的線程數高達4000左右。線程情況如下:
基于以上現象,我們只能初步判斷是nacos的問題(當然結論不是nacos的問題)。
我們先來猜測:可能由于某種原因,產生了大量的nacos線程,每個線程又在不停的發送http請求。
那接下來繼續分析Nacos。
我們知道Nacos客戶端注冊和訂閱服務流程大概如下:
所以,一般nacos-client有4個重要線程:
根據以上線程的名稱和原理流程圖,我們可以在nacos源碼里找到對應的位置,代碼如下:
翻看每個線程里執行的任務,確實能找到他們都在向nacos-server發送對應的的http的api請求:
既然找到了創建線程和發起http調用的原因,那就繼續查看是哪里調用的init方法。
此時會自然想到dubbo了,因為dubbo采用nacos作為注冊中心,自然要依賴nacos-client創建出nacos注冊中心相關的類,然后從nacos注冊中心類中獲取到微服務的元數據信息。
在翻看Dubbo源碼之前,先回顧下Dubbo是怎樣基于 引用配置文件 或者 引用配置注解創建Proxy的,大致流程如下:
ReferenceAnnotationBeanPostProcessor#doGetInjectedBean
?
ReferenceAnnotationBeanPostProcessor#buildReferenceBeanIfAbsent
?
ReferenceBeanBuilder#build
?
ReferenceBean#afterPropertiesSet
?
ReferenceConfig#init
至此完成了referenceProxy的創建。
重點看ReferenceConfig#init方法,方法里有一行代碼:ref = createProxy(map);,順著這行代碼往里走,如下:
RegistryProtocol#refer
?
AbstractRegistryFactory#getRegistry
重點來了,重點來了,重點來了,核心代碼和注釋見下圖。
總之是:因為在上面ReferenceConfig#init方法里引入了timestamp參數,同時又因為NacosRegistryFactory又自己實現了一套createRegistryCacheKey方法,這個方法里沒有截掉timestamp參數,所有就會導致從緩存里取不到注冊中心信息,所有就會不停的去創建,從而又創建了更多的線程,從而發送了很多http請求。
再次查看ReferenceConfig#init方法的源碼,確實是加入了timestamp參數:
至此問題的原因已經找到了,接下來就是如何解決了。
解決方法也很簡單,就是在Dubbo的NacosRegistryFactory類里面截掉timestamp參數。
遺憾的是,我當時發現了這個問題時,打算給Dubbo官方發issue的,發現已經有網友搶先一步發了issue,并且已經合并到2.7.9分支里了。
以下是解決方法的代碼截圖:
兩個版本處理URL的結果如下:
2.7.8版本:nacos://10.20.1.13:8848,10.20.1.14:8848,10.20.1.15:8848/org.apache.dubbo.registry.RegistryService?application=ehome-cloud&application.version=1.0&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&namespace=dev-jzj&owner=ehome-cloud-owner&pid=21335&qos.enable=false&release=2.7.8×tamp=17125458564892.7.9版本:nacos://10.20.1.13:8848,10.20.1.14:8848,10.20.1.15:8848/org.apache.dubbo.registry.RegistryService?namespace=dev-jzj
這個問題是在dubbo的2.7.8版本出現的,最后通過將2.7.9的修復class替換了2.7.8的NacosRegistryFactoryclass類,然后重新打了dubbo依賴包,問題得以解決。
有朋友會問:為啥不是引用2.7.9呢?因為我擔心2.7.9有其他問題,所以做個class替換,然后繼續用2.7.8是個較好的方式。
本文主要梳理了Dubbo使用Nacos注冊中心的坑,同時也講述了,出現問題時,如何一步一步排查。透過現象結合源碼,逐步找到問題的真相。
當然在排查之前,就需要對Dubbo和Nacos有一定的了解。所以各位朋友,在平時還是要多積累,多深入原理,這樣遇到問題才能順利解決。
本文鏈接:http://www.tebozhan.com/showinfo-26-82749-0.html深度剖析:Dubbo使用Nacos注冊中心的坑
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
下一篇: 深入理解C/C++指針的算術運算