Dubbo-go應用維度註冊模型

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo 3.0 將至。其最重要的一點就是服務自省,其基礎即是應用維度的註冊模型,作爲目前與 Dubbo 在功能上完全對齊的 Dubbo-go,已於 本年【2020 年】7 月份發佈了其 v1.5.0 版本,實現了該模型,爲年底實現與 Dubbo 3.0 對齊的新版本奠定了基礎。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo-go 作爲 Dubbo 的 Go 語言版本,因跨語言之故,二者針對同一模型的實現必然有較大差異,故本文注重討論 Dubbo-go 社區自身對該模型的理解和實現,以及其與 Dubbo 之間的差異。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1 引語"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 v1.5 以前,Dubbo-go 註冊模型都是以服務爲維度的,直觀的理解可認爲其是接口維度。譬如註冊信息,按照服務維度模型其示例如下:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\"com.xxx.User\":[\n {\"name\":\"instance1\", \"ip\":\"127.0.0.1\", \"metadata\":{\"timeout\":1000}},\n {\"name\":\"instance2\", \"ip\":\"127.0.0.2\", \"metadata\":{\"timeout\":2000}},\n {\"name\":\"instance3\", \"ip\":\"127.0.0.3\", \"metadata\":{\"timeout\":3000}}, \n]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種模式的好處是不言而喻的,簡單直觀,提供了細粒度的服務控制手段。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而近兩年,隨着雲時代的到來,這種模式就暴露了不足:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"主流的註冊模型都是應用維度的;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"以服務維度來註冊,那麼規模與服務數量成正比,大規模集羣之下,註冊中心壓力非常大;"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2 Dubbo-go v1.5.0 的新註冊模型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這次 Dubbo-go 支持了新的註冊模型,也就是應用維度的註冊模型。簡單而言,在應用維度註冊下,其註冊信息類似:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\"application1\": [\n {\"name\":\"instance1\", \"ip\":\"127.0.0.1\", \"metadata\":{}},\n {\"name\":\"instance2\", \"ip\":\"127.0.0.2\", \"metadata\":{}},\n {\"name\":\"instanceN\", \"ip\":\"127.0.0.3\", \"metadata\":{}}\n]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在此模式之下,可以看到註冊信息將會大幅度減少,集羣規模只與實例數量相關。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與此同時,在實現這一個功能的時候,Dubbo-go 還希望保持兩個目標:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"對用戶完全兼容,用戶遷移無感知;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"保持住原本服務粒度上精細控制的能力——即保留現有的服務維度的元數據;"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此 Dubbo-go 要着力解決以下幾點:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"目前 Consumer 的配置是以接口爲準的,如何根據接口找到該接口對應的應用?例如,用戶配置了 "},{"type":"codeinline","content":[{"type":"text","text":"com.xxx.User"}]},{"type":"text","text":" 服務,那麼,Dubbo-go 怎麼知道這個服務是由哪個應用來提供的呢?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"在知道了是哪個應用之後,可以從註冊中心拿到應用的註冊信息,如實例信息等;那怎麼知道 "},{"type":"codeinline","content":[{"type":"text","text":"com.xxx.User"}]},{"type":"text","text":" 服務自身的元數據呢?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了解決這兩個問題,在已有的註冊模型的基礎上,Dubbo-go 引入兩個額外的組件:ServiceNameMapping 和 MetadataService。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前者用於解決服務-應用之間的映射,後者用於獲取服務的元數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由此,Dubbo-go 的應用維度註冊模型就變爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b8/b86af66e002bb713472d3fd4a490f371.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1 ServiceNameMapping"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ServiceNameMapping 並不複雜。考慮到一般人在 Consumer 側想要調用一個服務,其十有八九是知道這個服務是哪個應用提供的,於是 Dubbo-go 引入了新的配置項 "},{"type":"codeinline","content":[{"type":"text","text":"provideBy"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9c/9c632d958fb8edf2be50c35bfe8f48ad.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,所謂 “十有八九”就是說有些時候確實不知道是服務是誰提供的,所以 Dubbo-go 還支持了基於配置中心的 ServiceNameMapping 實現。Dubbo-go 會用服務名作爲 Key 從配置中心裏面讀出對應的應用名。這意味着, Provider 啓動的時候,也會在配置中心將自身的 服務-應用名映射 寫入配置中心。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.2 MetadataService"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MetadataService 稍微要複雜一點,有 "},{"type":"codeinline","content":[{"type":"text","text":"remote"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"local"}]},{"type":"text","text":" 兩種模式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類似於前面的 ServiceNameMapping,Dubbo-go 提供了基於配置中心的 MetadataService 的實現,即 "},{"type":"codeinline","content":[{"type":"text","text":"remote"}]},{"type":"text","text":" 模式。Provider 啓動的時候,就會將服務的元數據寫進去。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外一種模式是 "},{"type":"codeinline","content":[{"type":"text","text":"local"}]},{"type":"text","text":" 模式。Dubbo-go 可以直接將 MetadataService 看做是一個普通的微服務,而後由 "},{"type":"codeinline","content":[{"type":"text","text":"Provider"}]},{"type":"text","text":" 所提供。類似於:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/44/4436d868b1ebc2268363ac55bae7ef70.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由此帶來一個問題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然 Dubbo-go 將 MetadataService 看做是一個普通的服務,那麼 MetadataService 的元數據,Consumer 該怎麼獲得呢?這是一個典型的雞生蛋蛋生雞的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo-go 的方案非常簡單粗暴,Provider 啓動的時候,不僅僅往註冊中心裏面寫入應用本身的信息,還要把它的 MetadataService 信息寫入。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是一個應用的註冊信息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/14/14a3c9e0c0d4aa016e6bcfb30bcb8c1b.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#595959","name":"user"}},{"type":"bgcolor","attrs":{"color":"#FAFAFA","name":"user"}}],"text":"本質上來說,應用維度註冊信息 + 服務元數據 = 服務維度註冊信息。或者說,應用維度註冊,只是一種重新組織這些信息的方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3 差異與改進"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo-go v1.5.x 對標 Dubbo 2.7.5,可以認爲是參照 Dubbo 2.7.5 直接實現其 Go 源碼,但是考慮到 Java 和 Go 之間的語言差異,導致二者之間的實現不可能完全對等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1 修訂版本號revision比對"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo v2.7.x 在 MetadataService 註冊時,會對其 provider 應用的所有服務接口的 hash 值做爲修訂版本號寫入元數據中心,此 revision 是對所有接口的方法以及其參數總體的計算結果。其目的是減少 consumer 端到註冊中心的拉取次數。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Go中用的計算 revision 的 hash 算法與 Java 是不一致的,而且 Go 與 Java 的方法簽名信息是不相同的,所以計算出來的 hash 值一定是不一樣的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此不一致會導致如果Go應用和Java應用同時發佈同一個服務的時候,Go服務和Java服務的修訂版本號必定是不相同的,Consumer需要分別緩存這兩個修訂版本的元數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2 應用註冊時機"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo-go v1.5.0 實現時,其中一個考量是全面向後兼容 v1.4.x。Dubbo-go v1.5.x 應用 consumer 既可以調用 Dubbo-go v1.4.x 應用的服務,也可以調用 Dubbo v2.6.x 應用的服務,當然也可以調用其對標的 v2.7.x 應用的服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了達到兼容性,Dubbo-go v1.5.x 實現時面臨一個問題:Dubbo-go provider 應用啓動時有一個服務啓動成功,把應用信息註冊到元數據中心之後,就會把實例註冊到註冊中心,而 Dubbo 2.7.x 的 provider 應用則是在其所有服務接口的信息註冊到元數據中心後纔會註冊實例!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個問題的後果就是:Dubbo-go v1.5.0 的 provider 每次發佈接口到元數據中心的同時,都會觸發Dubbo-go v1.5.0 / Dubbo v2.7.x 的 consumer 應用拉取 Dubbo-go v1.5.0 應用信息,當provider 發佈的服務過多時 consumer 側性能損耗非常明顯!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Dubbo-go 在 v1.5.1 中已經修復了這個問題,provider 在啓動時先將其全部服務接口發佈到元數據中心,然後註冊實例到註冊中心,減少了 consumer 拉取元數據的次數。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"本文作者: 白澤(蔣超),Github ID "},{"type":"link","attrs":{"href":"https://github.com/Patrick0308","title":null},"content":[{"type":"text","text":"@Patrick0308"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":",開源愛好者。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"歡迎加入 dubbo-go 社區"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2e/2eed39141b505434163babffce53146d.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章