Ⅰ 微服務架構 | *3.5 Nacos 服務注冊與發現的源碼分析
參考資料 :
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服務原理與實戰》
《B站 尚矽谷 SpringCloud 框架開發教程 周陽》
為方便理解與表達,這里把 Nacos 控制台和 Nacos 注冊中心稱為 Nacos 伺服器(就是 web 界面那個),我們編寫的業務服務稱為 Nacso 客戶端;
Nacos 客戶端將自己注冊進 Nacos 伺服器。《1. 服務如何注冊進 Nacos 注冊中心》主要從 Nacos 客戶端角度解釋如何發送信息給 Nacos 伺服器;《2. Nacos 伺服器注冊服務》主要從 Nacos 伺服器角度解釋注冊原理;
《3. 客戶端查詢所有服務實例》將從服務消費者和提供者的角度,解釋服務消費者如何獲取提供者的所有實例。服務消費者和提供者都是 Nacos 的客戶端;
《4. 客戶端監聽 Nacos 伺服器以動態獲取服務實例》從消費者客戶端角度出發監聽 Nacos 伺服器,以動態獲知提供者的變化;
Ⅱ Spring Cloud 整合Grpc-注冊中心(Eureka/Consul)
Spring Cloud分布式微服務應用,通常在微服務之間採用的Feign進行通信,實現簡單快捷的調用,底層採用的HTTP形式;相對於gRPC或RPC協議調用來說,性能相對低下,因此我們可以採用開源技術框架gRPC來實現。
微服務開發中,服務間的調用一般有兩種方式:Feign或RestTemplate,但在實際使用過程中,尤其是Feign,存在各種限制及局限性,如:HTTP請求方式、返回類型等限制等。服務間調用是非常普遍頻繁的,其性能也不是特別理想。
為了解決上述問題,我們採用gRPC方式實現服務間調用,其顯著特點就是性能之高(通信採用Netty),通過proto文件定義的介面也是非常清晰而又靈活。
gRPC是谷歌開源的一個高性能的、通用的RPC框架。和其他RPC一樣,客戶端應用程序可以直接調用遠程服務的方法,就好像調用本地方法一樣。它隱藏了底層的實現細節,包括序列化(XML、JSON、二進制)、數據傳輸(TCP、HTTP、UDP)、反序列化等,開發人員只需要關自業務本身,而不需要關注RPC的技術細節。與其他RPC框架一樣,gRPC也遵循定義服務(類似於定義介面的思想)。gRPC客戶端通過定義方法名、方法參數和返回類型來聲明一個可以被遠程調用的介面方法。由服務端實現客戶端定義的介面方法,並運行一個gRPC服務來處理gPRC 客戶端調用,gRPC客戶端和服務端共用一個介面方法。
新建common項目,存放proto文件,服務端和客戶端都依賴此項目。
* pom依賴
* 新建helloworld.proto文件,放在:src/main/proto/helloworld.proto
* pom.xml依賴
* 新建GrpcServerService
}
* yml配置
* pom.xml依賴配置
* 新建GrpcClientService
* yml配置
Consul和Eureka區別在於替換pom依賴、yml注冊地址修改、啟動類修改。
源碼: 提取碼: 28qs
源碼:spring-boot-rpc
提取碼: 28qs
Ⅲ Kitex 源碼解析 —— 將服務注冊進入注冊中心的細節
Kitex為 位元組跳動 內部的 Golang 微服務 RPC 框架,具有 高性能 、 強可擴展 的特點,在位元組內部已廣泛使用。如果對微服務性能有要求,又希望定製擴展融入自己的治理體系,Kitex 會是一個不錯的選擇。
這次我們可以從 官方示例 中的 easy_note 這個demo 開始分析,因為它基本展示了 Kitex 的基本使用方法。
下面圖例為官方在 demo 中展示的架構圖,通過簡單的分析可得, note , user 通過 注冊中心 (Etcd) 進行注冊 , api 通過 注冊中心 來發現 note , user 兩個 rpc 服務, 並進行業務處理。
從 kitex-examples/hello 這個最簡單示例分析,從 cloudwego/kitex 的快速上手可知,這里用了最簡單的 直鏈 來鏈接 server 和 client。而這次的 easy_note 中使用了 注冊中心 來作為 服務之間的 橋梁 (middleware), 為什麼不使用之前的方式而是使用了注冊中心?
我們搜索一下注冊中心的作用,可知: 服務注冊中心的主要作用就是「服務的注冊」和「服務的發現」
我們將服務交給注冊中心管理,雖然可以避免處理復雜的手動管理,我們也許需要還要考慮更多問題,例如:
這次目標之一就是來解析解析服務是如何在服務啟動時進行 注冊 ( Register ) 這個操作的, 這次我們從 easy_note/cmd/user 這個服務開始分析, 因為它是被 注冊 進入 Etcd 的服務之一。
我們從其中的 main.go 開始下手,以下的內容是經過簡化後的文件,是實現配置服務,啟動服務的文件
由注釋可知 WithRegister() 為配置 注冊信息 的函數 ,那為什麼直接就看這個函數呢?
一是因為主要配置注冊的主要邏輯在其中,二是因為 With... 的函數結構都是大同小異,十分相似的。
再然後我們進入 kitex/server/option.go ,先看看 di.Push(fmt.Sprintf("WithRegistry(%T)", r)) 這一行,
這個 *util.Slice 是什麼 ?進去看看?
進入 kitex/pkg/utils/slice.go , 我發現它很簡短。但是它好眼熟,它好像是一個非常常見的數據結構 —— Stack (棧) !
在這個文件之下有它的 slice__test.go 文件 ,看到這里的朋友可以去試驗一下是否這個 Slice 和我的想法是否一致,大家看文章是要思考的嘛!最好可以動動手!
我們再進入 o.Registry = r 這一行,可以得知 Options 用於初始化 server, Option 用於配置 Options (我覺得這種命名方式很巧妙,我感覺基本達到了 見名知意 的作用),裡面東西很多,我們今天只看 Register 部分
到了這里我們可以暫停思考一下,到達這一步是怎麼個過程呢?是通過 main.go/user.NewServer() 的方法進來的。
那 NewServer() 的作用是什麼?是用於配置初始化伺服器的 可選參數 ,
配置完了參數什麼時候生效呢 ( Register 是什麼時候發生的呢) ?其實配置的實現就在 main.go NewServer() 的下一句, Run() !
進入Run方法的實現,可以得知 register 是發生在 server 啟動成功後 的,停止也是會向 Etcd 進行注銷操作的 (大家可以在同文件的 Stop() 中查看)
至此 服務完成了向 Etcd 的注冊,我忽略了許多其他細節,這些細節也很有意思,希望大家可以自己試著探索
這次文章其實向大家分析了如何配置服務,以及向注冊中心進行注冊的方法和時機。
雖然省略了許多細節,但是通過這篇文章可以學到什麼呢?
Ⅳ Eureka源碼淺讀---自我保護機制
Eureka源碼採用1.7.2版本
本人小白,此文為本人閱讀源碼筆記,如果您讀到本文,您需要自己甄別是否正確,文中的說明只代表本人理解,不一定是正確的!!!
自我保護機制設計的初衷是防止服務注冊服務因為本地網路故障,長時間未接受到心跳請求,造成錯誤的移除大量服務實例,其實調用服務還是可用的
自我保護機制是和自動故障移除聯系在一起的,針對的移除實例也是自動故障移除
在服務故障移除的方法中有這樣一個判斷,當返回false時候,直接返回,不進行故障實例的摘除
進入該方法
關於獲取上一分鍾心跳總數,Eureka Server內部採用的是定時線程進行統計,使用兩個AtomicLong進行保存當前和上一分鍾的心跳總數
該方法初始化了運行了定時調度的線程進行統計,默認執行間隔為1min,執行流程:
那麼當前的心跳總數是怎麼計算的呢,直接看心跳的renew()方法,是否嵌入了計數器累計操作
如上所示,當接收到心跳時,當前心跳計數器進行了遞增操作
而getNumOfRenewsInLastMin()獲取上一分鍾心跳總數就是獲取lastBucket數量,再找下該定時任務啟動的入口
和自動故障移除的定時同時啟動的,那麼lastBucket代表了上一分鍾的心跳總數
接下來,我們需要看看期望每分鍾最小心跳總數的由來:
numberOfRenewsPerMinThreshold最開始的初始化計算是在Eureka Server初始化計算的,使用當前Server拉取到的服務實例總數 * 0.85
在openForTraffic()方法中使用初始化拉取的服務實例總數作為基數標准進行計算,(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()) -> count * 2 * 0.85,
集群模式下,count為其他節點中已注冊的服務實例總數,單節點就為0
下面我們看看在注冊中心接收到注冊,下線等請求執行時,維護numberOfRenewsPerMinThreshold
注冊,當前實例數量+2,下線,當前實例數量-2,然後再次*0.85,計算期望每分鍾最小心跳數
在Eureka Server中有專門的定時任務進行更新numberOfRenewsPerMinThreshold,默認每15min執行一次
主要流程如下:
注意,自動服務故障移除沒有進行numberOfRenewsPerMinThreshold的更新
<font color= 'blue'>服務故障實例的摘除需要判斷當前是否處於自我保護模式,而自我保護模式的默認是開啟(isSelfPreservationModeEnabled),需要判斷上一分鍾的心跳總數是否大於期望每分鍾最小心跳數,如果在15分鍾內,累計丟失了15%以上的節點心跳,那麼Eureka Server就會認為當前所處的網路環境異常,從而處於自動保護模式,故障實例將不會移除,再等待15min後,進行expectedNumberOfRenewsPerMin的基於當前服務實例的重新計算後,自我保護模式才會關閉!</font>
自我保護服務開啟模擬:
Ⅳ springboot 2.4.13 無法從nacos獲取配置,但是可以注冊到nacos
springboot 2.4.13,集成了nacos,啟動後,nacos注冊中心有服務,但是,發現,配置沒有生效。於是,開啟了一段源碼查找的過程。
首先,是pom引入的nacos配置
然後,application.yml添加nacos配置
啟動後,發現注冊中心有服務,但是,服務的配置不是從nacos配置中心獲取的,而是本地的。
查找一下nacos源碼,找到nacos配置自動注入那塊兒:
然後發現,是這個NacosPropertySourceLocator實現的配置導入的
查詢源碼,可以發現,相關的配置,是通過這個方法,載入的,這個方法是總入口。
於是,嘗試加斷點,查看配置信息,看看為什麼沒有導入配置。然而,程序根本就沒有進入這個方法裡面!!!
根據介面實現,可以發現NacosPropertySourceLocator 是PropertySourceLocator的實現類,這個方法的調用執行,不是nacos自己去做的,而是通過spring去做的。
spring cloud 通過BootstrapApplicationListener,以監聽器的方式,通過監聽springboot啟動過程中的事件,通過onApplicationEvent方法處理事件,導入spring cloud相關配置。
通過加斷點,可以發現,這里的方法bootstrapEnabled()返回值是false,直接就不執行後續的載入了。
因此,需要保證bootstrapEnabled返回值是true。
查看PropertyUtils源碼,可以發現,需要配置項 spring.cloud.bootstrap.enabled=true 並且存在 org.springframework.cloud.bootstrap.marker.Marker 類的時候,spring cloud 才會去載入spring cloud的配置。
因此,pom中需要添加marker所在的組件依賴:
此時,需要在 bootstrap.yml 中添加spring cloud配置:
(至於為什麼是bootstrap.yml而不是application.yml,這又是另一個問題了)
有了上面的配置,程序啟動後,就能正常的從nacos配置中心獲取配置了。
Ⅵ 如何更好地學習bbo源代碼
1、Dubbo與Spring的整合 Dubbo在使用上可以做到非常簡單,不管是Provider還是Consumer都可以通過Spring的配置文件進行配置,配置完之後,就可以像使用 spring bean一樣進行服務暴露和調用了,完全看不到bbo api的存在。這是因為bbo使用了spring提供的可擴展Schema自定義配置支持。在spring配置文件中,可以像、這樣進行配置。 META-INF下的spring.handlers文件中指定了bbo的xml解析類:DubboNamespaceHandler。像前面的被解 析成ServiceConfig,被解析成ReferenceConfig等等。 2、jdk spi擴展 由於Dubbo是開源框架,必須要提供很多的可擴展點。Dubbo是通過擴展jdk spi機制來實現可擴展的。具體來說,就是在META-INF目錄下,放置文件名為介面全稱,文件中為key、value鍵值對,value為具體實現類 的全類名,key為標志值。由於bbo使用了url匯流排的設計,即很多參數通過URL對象來傳遞,在實際中,具體要用到哪個值,可以通過url中的參 數值來指定。 Dubbo對spi的擴展是通過ExtensionLoader來實現的,查看ExtensionLoader的源碼,可以看到Dubbo對jdk spi做了三個方面的擴展:
(1)jdk spi僅僅通過介面類名獲取所有實現,而ExtensionLoader則通過介面類名和key值獲取一個實現;
(2)Adaptive實現,就是生成一個代理類,這樣就可以根據實際調用時的一些參數動態決定要調用的類了。
(3)自動包裝實現,這種實現的類一般是自動激活的,常用於包裝類,比如Protocol的兩個實現類:ProtocolFilterWrapper、ProtocolListenerWrapper。 3、url匯流排設計 Dubbo為了使得各層解耦,採用了url匯流排的設計。我們通常的設計會把層與層之間的交互參數做成Model,這樣層與層之間溝通成本比較大,擴展起來也比較麻煩。因此,Dubbo把各層之間的通信都採用url的形式。比如,注冊中心啟動時,參數的url為: registry://0.0.0.0:9090?codec=registry&transporter=netty 這就表示當前是注冊中心,綁定到所有ip,埠是9090,解析器類型是registry,使用的底層網路通信框架是netty。