<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          有贊服務(wù)注冊與發(fā)現(xiàn)架構(gòu)演進(jìn)

          共 10781字,需瀏覽 22分鐘

           ·

          2021-10-28 22:34

          075fbb24176029b9402b375dfd555c49.webp

          點(diǎn)擊關(guān)注“有贊coder

          獲取更多技術(shù)干貨哦~

          6f3ad889358f0107f94fec9d9c320a07.webp作者:飄石

          部門:技術(shù)中臺(tái)/中間件


          一、概述

          近幾年,隨著有贊業(yè)務(wù)的快速發(fā)展,應(yīng)用數(shù)目與實(shí)例規(guī)模在快速地增加。有贊的服務(wù)注冊與發(fā)現(xiàn)架構(gòu)近幾年也一直在快速平穩(wěn)地演進(jìn),以支撐業(yè)務(wù)的發(fā)展。本文主要介紹有贊近幾年服務(wù)注冊與發(fā)現(xiàn)架構(gòu)的演進(jìn)過程。

          有贊的后臺(tái)業(yè)務(wù)應(yīng)用主要是基于 Dubbo 框架開發(fā)的,因此,服務(wù)注冊與發(fā)現(xiàn)的方案也都離不開對(duì) Dubbo 服務(wù)模型的支持。近幾年,Dubbo 社區(qū)也一直在演進(jìn)服務(wù)注冊與發(fā)現(xiàn)解決方案,但有贊的演進(jìn)路線跟 Dubbo 社區(qū)并不相同。有贊根據(jù)內(nèi)部獨(dú)特的歷史背景以及未來規(guī)劃走出了具有自己特色的演進(jìn)道路。

          本文將分為三個(gè)階段來介紹近幾年有贊服務(wù)注冊與發(fā)現(xiàn)架構(gòu)的演進(jìn):接口級(jí)服務(wù)注冊與發(fā)現(xiàn),接口級(jí)服務(wù)注冊與應(yīng)用級(jí)服務(wù)發(fā)現(xiàn),應(yīng)用級(jí)服務(wù)注冊與發(fā)現(xiàn)。為了聚焦,本文主要介紹 Dubbo 應(yīng)用相關(guān)的服務(wù)注冊與發(fā)現(xiàn),但實(shí)際上有贊的服務(wù)注冊與發(fā)現(xiàn)方案不僅僅支持 Dubbo 應(yīng)用。

          二、接口級(jí)服務(wù)注冊與發(fā)現(xiàn)

          2.1?架構(gòu)

          接口級(jí)服務(wù)注冊與發(fā)現(xiàn),也是開源社區(qū) Dubbo 2.7 版本之前的標(biāo)準(zhǔn)方案,有贊 2018 年 ~ 2019 年期間主要處于這種架構(gòu)階段。架構(gòu)如下圖所示:?068261962dd2dbe1e2f64982be9b3d18.webp模型上與 Dubbo 社區(qū)方案是一致的,注冊中心我們采用的是 Etcd v3。

          接口級(jí)模型示例:

          [
          {
          "interface":"com.youzan.java.demo.api.HelloService",
          "instances":[
          {
          "ip_address":"10.10.10.10",
          "port":5000,
          "protocol":"dubbo",
          "az":"qa",
          "weight":100,
          "labels":{
          "version":"stable"
          },
          "application":"java-demo",
          "methods":[
          "hello"
          ]
          }
          ]
          },
          {
          "interface":"com.youzan.java.demo.api.EchoService",
          "instances":[
          {
          "ip_address":"10.10.10.10",
          "port":5000,
          "protocol":"dubbo",
          "az":"qa",
          "weight":100,
          "labels":{
          "version":"stable"
          },
          "application":"java-demo",
          "methods":[
          "echo"
          ]
          }
          ]
          }
          ]

          2.2 問題

          接口級(jí)服務(wù)注冊與發(fā)現(xiàn)可以說是 Dubbo 框架獨(dú)有的模型,而業(yè)界主流的服務(wù)注冊與發(fā)現(xiàn)模型都是應(yīng)用級(jí)的,如 K8S、Spring Cloud、Consul 等。相比應(yīng)用級(jí)模型,接口級(jí)模型的主要問題是粒度太細(xì),服務(wù)注冊與發(fā)現(xiàn)的開銷太高。根據(jù)有贊的服務(wù)注冊與發(fā)現(xiàn)數(shù)據(jù)統(tǒng)計(jì),平均每個(gè)應(yīng)用實(shí)例的接口注冊數(shù)量和訂閱數(shù)量為幾十個(gè),同時(shí),該數(shù)量也在緩慢增長。粗略估算,在大規(guī)模場景中,接口級(jí)比應(yīng)用級(jí)服務(wù)注冊與發(fā)現(xiàn)的成本要高 1~2 個(gè)數(shù)量級(jí)。接口級(jí)服務(wù)注冊與發(fā)現(xiàn)的弊端業(yè)界也基本達(dá)成了共識(shí),Dubbo 社區(qū)從 Dubbo 2.7.5 開始支持應(yīng)用級(jí)服務(wù)注冊與發(fā)現(xiàn)。

          總結(jié)一下該架構(gòu)存在的痛點(diǎn):

          • 接口級(jí)別的服務(wù)注冊與發(fā)現(xiàn),大大增加了服務(wù)注冊與發(fā)現(xiàn)的壓力

          • 接口級(jí)別的服務(wù)注冊數(shù)據(jù)冗余度過高,同一個(gè)應(yīng)用實(shí)例的多個(gè)接口之間有大量的重復(fù)數(shù)據(jù);同一個(gè)應(yīng)用的不同實(shí)例之間同樣存在大量冗余數(shù)據(jù)

          • Etcd 作為強(qiáng)一致性的 CP 系統(tǒng),其水平伸縮能力不足,容易成為瓶頸

          • 服務(wù)注冊與發(fā)現(xiàn)由 SDK 支持,多語言應(yīng)用支持成本高


          三、接口級(jí)服務(wù)注冊與應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)

          3.1 架構(gòu)

          這一階段服務(wù)注冊維持不變,服務(wù)發(fā)現(xiàn)轉(zhuǎn)變?yōu)閼?yīng)用級(jí)別,有贊 2020 年期間主要處于這種架構(gòu)階段,該架構(gòu)屬于過渡階段架構(gòu)。架構(gòu)如下圖所示:?

          babc452283e03a79956cba9fe5f27d6e.webp

          服務(wù)發(fā)現(xiàn)方面主要有以下兩個(gè)變化:

          • 引入了Istio?Pilot 作為服務(wù)發(fā)現(xiàn)中心或中間層。由 Istio Pilot 對(duì)接各個(gè)注冊中心平臺(tái),抽象并統(tǒng)一服務(wù)發(fā)現(xiàn)模型,屏蔽注冊中心具體實(shí)現(xiàn)細(xì)節(jié),同時(shí)提升可伸縮能力。

          • 所有消費(fèi)端接入了 Sidecar?Tether,由 Tether 進(jìn)行服務(wù)發(fā)現(xiàn)、請求路由、負(fù)載均衡等,且以應(yīng)用維度進(jìn)行服務(wù)發(fā)現(xiàn)。

          下面將進(jìn)行詳細(xì)介紹。

          3.2應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)解析

          Istio Pilot 抽象并統(tǒng)一了服務(wù)發(fā)現(xiàn)模型,屏蔽掉了注冊中心具體實(shí)現(xiàn)細(xì)節(jié),使得消費(fèi)端應(yīng)用完全不需要關(guān)注服務(wù)提供端應(yīng)用是如何進(jìn)行服務(wù)注冊的。Istio Pilot 中間層避免了海量客戶端直連注冊中心,大大降低了注冊中心的壓力;同時(shí) Istio Pilot 是無狀態(tài)的,可以輕松擴(kuò)縮容,大大提升了可伸縮能力。Istio Pilot 通過 xDS API 向所有 Sidecar 推送服務(wù)發(fā)現(xiàn)、配置等數(shù)據(jù)。服務(wù)發(fā)現(xiàn) API 是 EDS(Endpoint Discovery Service),客戶端通過指定 Cluster 名稱(這里可以認(rèn)為對(duì)應(yīng)的是應(yīng)用名)列表來訂閱對(duì)應(yīng)的服務(wù)實(shí)例信息,當(dāng)服務(wù)實(shí)例信息有更新時(shí),Istio Pilot 推送給訂閱的客戶端。

          我們引入 Istio Pilot 不僅僅是作為服務(wù)發(fā)現(xiàn)中心,同時(shí)也是路由規(guī)則配置中心等。Istio Pilot 實(shí)際上是作為有贊 Service Mesh 的控制面角色來使用的,我們的數(shù)據(jù)面是自研組件 Tether。由于有贊整體業(yè)務(wù)規(guī)模龐大,以及 Dubbo 模型的復(fù)雜度,是很難直接落地為 Istio 社區(qū)那樣的 Service Mesh 形態(tài)的。因此,我們對(duì) Istio Pilot 進(jìn)行了大量擴(kuò)展與適配,來滿足內(nèi)部需求,以及逐步演進(jìn)的目標(biāo)。對(duì)于服務(wù)發(fā)現(xiàn)而言,我們擴(kuò)展支持了 Etcd Registry,同時(shí)實(shí)現(xiàn)了接口模型到應(yīng)用模型的轉(zhuǎn)換。為了支持 Dubbo 的服務(wù)發(fā)現(xiàn),使用原有的模型還不夠,因此我們通過xDS模型的擴(kuò)展字段來支持 Dubbo 的元數(shù)據(jù)。

          應(yīng)用級(jí)模型示例:

          {
          "application":"java-demo",
          "instances":[
          {
          "ip_address":"10.10.10.10",
          "port":5000,
          "protocol":"dubbo",
          "az":"qa",
          "weight":100,
          "labels":{
          "version":"stable"
          },
          "dubbo_rpc_metadata":[
          {
          "interface":"com.youzan.java.demo.api.HelloService",
          "methods":[
          "hello"
          ]
          },
          {
          "interface":"com.youzan.java.demo.api.EchoService",
          "methods":[
          "echo"
          ]
          }
          ]
          }
          ]
          }

          與前面提到的接口級(jí)模型對(duì)比,應(yīng)用級(jí)模型大大降低了數(shù)據(jù)冗余。

          我們通過Istio Pilot實(shí)現(xiàn)了應(yīng)用級(jí)的服務(wù)發(fā)現(xiàn),這時(shí)我們面臨一個(gè)問題,原先Dubbo框架通過訪問的接口直接進(jìn)行服務(wù)發(fā)現(xiàn),現(xiàn)在需要將訪問的接口映射為訪問的應(yīng)用,然后以應(yīng)用名進(jìn)行服務(wù)發(fā)現(xiàn)訂閱。

          Istio Pilot會(huì)根據(jù)應(yīng)用級(jí)的注冊信息在內(nèi)存中構(gòu)建一個(gè)接口到應(yīng)用的反向映射,我們擴(kuò)展了一個(gè)Interface Mapping接口,用于查詢哪些應(yīng)用暴露了這個(gè)接口。映射信息如下所示:

          [
          {
          "interface":"com.youzan.java.demo.api.HelloService",
          "providers":[
          "java-demo"
          ]
          },
          {
          "interface":"com.youzan.java.demo.api.EchoService",
          "providers":[
          "java-demo"
          ]
          }
          ]

          前面我們提到,由 SDK 進(jìn)行服務(wù)發(fā)現(xiàn),對(duì)于多語言應(yīng)用支持成本較高。在有贊,除了主流的 Dubbo RPC 應(yīng)用,還有 Node Web 應(yīng)用,PHP Web 應(yīng)用,ZanPHP RPC 應(yīng)用,這些應(yīng)用都需要進(jìn)行服務(wù)發(fā)現(xiàn)訪問其他后端應(yīng)用。所以,我們將這些基礎(chǔ)能力下沉到 Sidecar Tether,所有消費(fèi)端接入 Tether,由 Tether 進(jìn)行服務(wù)發(fā)現(xiàn)、請求路由、負(fù)載均衡等。接入 Tether 也開啟了有贊的 Service Mesh 之路。

          Dubbo 社區(qū)應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)方案中,為了使Dubbo盡可能的兼容和融入業(yè)界已有的應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)解決方案,元數(shù)據(jù)是通過一種服務(wù)自省的方式來獲取的。對(duì)于接口到應(yīng)用的映射,解決思路基本都是一致的。

          3.3優(yōu)化

          雖然當(dāng)前的架構(gòu)方案已經(jīng)大大緩解了服務(wù)發(fā)現(xiàn)的壓力,但是仍有幾個(gè)優(yōu)化點(diǎn)可以大大提升性能。下面簡單介紹一下。

          3.3.1服務(wù)發(fā)現(xiàn)延遲聚合推送

          Dubbo 實(shí)例在啟動(dòng)時(shí),是一個(gè)接口一個(gè)接口注冊的,因?yàn)槲覀儗⒔涌谧詳?shù)據(jù)轉(zhuǎn)換成了應(yīng)用實(shí)例注冊數(shù)據(jù),這也就意味著,每注冊一個(gè)接口,應(yīng)用實(shí)例數(shù)據(jù)(dubbo_rpc_metadata)就會(huì)變動(dòng)。如果每次變動(dòng)就進(jìn)行服務(wù)發(fā)現(xiàn)推送,那成本會(huì)很高,無論是對(duì)于 Istio Pilot 還是 Tether。根據(jù)統(tǒng)計(jì),一個(gè)實(shí)例一般在幾秒鐘內(nèi)會(huì)完成所有接口的注冊,因此,我們會(huì)對(duì)一段時(shí)間內(nèi)注冊事件響應(yīng)進(jìn)行延遲處理。比如,如果實(shí)例注冊數(shù)據(jù)有變動(dòng),延遲 3s 再推送,如果 3s 時(shí)間到達(dá)之前期間又有變動(dòng),再延遲 3s,最長不超過 10s。該方案大概率地把一個(gè)實(shí)例的多個(gè)接口注冊事件聚合成了一次推送,同時(shí),應(yīng)用發(fā)布過程一般是分批次進(jìn)行的,每個(gè)批次會(huì)有多個(gè)實(shí)例同時(shí)啟動(dòng),該方案也有很大概率把多個(gè)實(shí)例的注冊事件聚合成一次推送。

          3.3.2服務(wù)發(fā)現(xiàn)預(yù)加載

          最初 Tether 的服務(wù)發(fā)現(xiàn)是延遲加載的,即當(dāng)應(yīng)用的請求到達(dá) Tether 后,如果還沒有訂閱過目標(biāo)訪問應(yīng)用,進(jìn)行服務(wù)發(fā)現(xiàn)訂閱。剛啟動(dòng)的時(shí)候,訪問不同應(yīng)用的請求會(huì)陸陸續(xù)續(xù)到來,每個(gè)請求訪問一個(gè)本地服務(wù)發(fā)現(xiàn)數(shù)據(jù)不存在的應(yīng)用時(shí),就需要更新服務(wù)發(fā)現(xiàn)訂閱列表,發(fā)起新的 EDS 訂閱請求,會(huì)加大Istio Pilot 的負(fù)載,同時(shí)會(huì)一定程度增加請求的 RT。一個(gè)應(yīng)用的需要訪問的其他應(yīng)用的列表是比較穩(wěn)定的,我們稱之為服務(wù)依賴列表。我們通過 Tether 定時(shí)上報(bào)最近一段時(shí)間(如 30 分鐘)訪問過的應(yīng)用列表到 Istio Pilot 來實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)預(yù)加載。Tether 啟動(dòng)初始化階段拉取該應(yīng)用最近訪問過的應(yīng)用列表,然后一次性的完成服務(wù)發(fā)現(xiàn)訂閱,大大降低了應(yīng)用剛啟動(dòng)時(shí)首次請求的 RT。

          3.3.3客戶端接口與應(yīng)用映射關(guān)系構(gòu)建

          前面我們討論過,請求到來時(shí),我們需要根據(jù)接口查詢對(duì)應(yīng)的應(yīng)用,那是不是每個(gè)接口的首次請求都需要通過 Istio Pilot 的 Interface Mapping 接口查詢呢?其實(shí)沒必要的,當(dāng)我們拿到一個(gè)應(yīng)用的服務(wù)發(fā)現(xiàn)數(shù)據(jù)時(shí),本地可以根據(jù)該應(yīng)用的服務(wù)元數(shù)據(jù)構(gòu)建出來所有的接口到應(yīng)用的映射關(guān)系。根據(jù)局部性原理,如果一個(gè)應(yīng)用訪問了某個(gè)應(yīng)用的一個(gè)接口,短時(shí)間內(nèi)大概率也會(huì)訪問該應(yīng)用的其他接口。通過該優(yōu)化,實(shí)際上只會(huì)發(fā)生很少的 Interface Mapping 查詢請求。當(dāng)然,應(yīng)用的服務(wù)元數(shù)據(jù)都是在變化的,因此,我們也需要定期的異步刷新,異步刷新時(shí),只會(huì)刷新最近有請求的接口,且我們實(shí)現(xiàn)了批量處理的接口以提升性能。對(duì)于一段時(shí)間內(nèi)沒有訪問過的接口,當(dāng)新請求到來時(shí),會(huì)嘗試同步去請求 Interface Mapping。

          3.3.4接口元數(shù)據(jù)聚合分組

          一般來說,真實(shí)生產(chǎn)環(huán)境中,一個(gè)應(yīng)用的大部分實(shí)例的服務(wù)元數(shù)據(jù)是相同的,那么也就沒必要為每個(gè)應(yīng)用實(shí)例關(guān)聯(lián)一份完整的元數(shù)據(jù)。在有贊的場景中,每個(gè)機(jī)房,每個(gè)應(yīng)用一般最多有 2 個(gè)版本的服務(wù)元數(shù)據(jù),主要出現(xiàn)在發(fā)布過程中,如普通滾動(dòng)發(fā)布、灰度/藍(lán)綠發(fā)布。因此,我們可以進(jìn)行相應(yīng)的優(yōu)化。Istio Pilot 在推送服務(wù)發(fā)現(xiàn)數(shù)據(jù)前會(huì)對(duì)應(yīng)用實(shí)例服務(wù)元數(shù)據(jù)進(jìn)行聚合分組,以減少網(wǎng)絡(luò)帶寬 IO,以及客戶端解析開銷等。聚合示例:

          {
          "application":"java-demo",
          "instances":[
          {
          "ip_address":"10.10.10.10",
          "port":5000,
          "protocol":"dubbo",
          "az":"qa",
          "weight":100,
          "labels":{
          "version":"stable"
          },
          "dubbo_rpc_metadata":{
          "type":"metadata",
          "data":[
          {
          "interface":"com.youzan.java.demo.api.HelloService",
          "methods":[
          "hello"
          ]
          },
          {
          "interface":"com.youzan.java.demo.api.EchoService",
          "methods":[
          "echo"
          ]
          }
          ]
          }
          },
          {
          "ip_address":"10.10.10.20",
          "port":5000,
          "protocol":"dubbo",
          "az":"qa",
          "weight":100,
          "labels":{
          "version":"stable"
          },
          "dubbo_rpc_metadata":{
          "type":"metadata_reference",
          "data":{
          "ip_address":"10.10.10.10",
          "port":5000
          }
          }
          }
          ]
          }

          應(yīng)用實(shí)例10.10.10.10:500010.10.10.20:5000服務(wù)元數(shù)據(jù)完全一致,因此10.10.10.20:5000dubbo_rpc_metadata中并不需要保存完整的服務(wù)元數(shù)據(jù)信息,僅需要保存一個(gè)引用的應(yīng)用實(shí)例信息即可。客戶端在構(gòu)建時(shí),會(huì)根據(jù)引用關(guān)系,關(guān)聯(lián)到正確的服務(wù)元數(shù)據(jù)信息。

          該優(yōu)化將服務(wù)發(fā)現(xiàn)推送的網(wǎng)絡(luò) IO 降低到原來的 30% 以下。

          3.4 問題

          雖然該架構(gòu)解決了服務(wù)發(fā)現(xiàn)的一些問題,但仍然有以下問題:

          • 應(yīng)用與注冊中心耦合,多語言服務(wù)注冊支持成本高

          • 服務(wù)注冊數(shù)據(jù)維度過細(xì),注冊、健康檢查開銷與復(fù)雜度都較高

          • 服務(wù)注冊數(shù)據(jù)冗余度過高


          四、應(yīng)用級(jí)服務(wù)注冊與發(fā)現(xiàn)

          4.1架構(gòu)

          這是有贊確定的長期架構(gòu),從 2021 年開始,有贊轉(zhuǎn)換到該架構(gòu)。架構(gòu)圖如下所示:?

          469cd711335ee6d59d01c83aec6ba6d1.webp此架構(gòu)服務(wù)與前一階段架構(gòu)相比,客戶端服務(wù)發(fā)現(xiàn)沒有變化,只有服務(wù)注冊有變化。

          應(yīng)用服務(wù)注冊通過 Sidecar Tether 來完成,可以主動(dòng)調(diào)用 Tether 服務(wù)注冊接口,也可以由 Tether 主動(dòng)獲取實(shí)例服務(wù)注冊信息進(jìn)行注冊,目前我們優(yōu)先支持了前一種方式。

          Dubbo 啟動(dòng)時(shí),等待所有接口暴露完成,聚合成應(yīng)用級(jí)的實(shí)例信息,發(fā)起一次服務(wù)注冊請求到 Tether,Tether 判斷應(yīng)用部署環(huán)境,向 Istio Pilot 發(fā)起相應(yīng)的注冊請求。對(duì)于 VM 部署應(yīng)用,需要注冊完整的信息;對(duì)于 K8S 部署應(yīng)用,僅需要注冊服務(wù)元數(shù)據(jù)信息即可,其他實(shí)例信息、標(biāo)簽等可以由 Istio Pilot 根據(jù) K8S Service 以及 Pod 信息獲得。有贊業(yè)務(wù)應(yīng)用基本都實(shí)現(xiàn)了 K8S 部署,所以,這里只介紹 K8S 部署應(yīng)用的注冊流程。Istio Pilot 會(huì)將注冊請求中的服務(wù)元數(shù)據(jù),以 CRD 的方式存儲(chǔ)到K8S中。Istio Pilot 在服務(wù)發(fā)現(xiàn)時(shí),會(huì)根據(jù) Service/Endpoints/Pod/ServiceMetadata 信息,生成完整的服務(wù)發(fā)現(xiàn)數(shù)據(jù)。此過程中,Istio Pilot 與客戶端之間的服務(wù)發(fā)現(xiàn)數(shù)據(jù)模型完全沒有變化,因此,客戶端對(duì)于該服務(wù)注冊的變動(dòng)是完全無感知的。這樣,我們又平滑地演進(jìn)到了新的架構(gòu)。

          可能有人會(huì)考慮到運(yùn)行時(shí)動(dòng)態(tài)暴露接口的場景,會(huì)對(duì)該注冊方案有影響。我們通過統(tǒng)計(jì),發(fā)現(xiàn)沒有該使用場景,所有應(yīng)用都可以在啟動(dòng)的時(shí)候確定需要注冊的接口信息。同時(shí),我們通過 Dubbo 框架約束,一個(gè)實(shí)例的注冊數(shù)據(jù)一旦完成服務(wù)注冊后是不能變化的。如果后續(xù)確實(shí)出現(xiàn)了該場景,我們后續(xù)會(huì)再對(duì)該場景進(jìn)行支持,或者先使用老的注冊方式,畢竟 Istio Pilot 可以輕松支持多種注冊中心,而客戶端無感知。

          4.2服務(wù)元數(shù)據(jù)管理

          服務(wù)元數(shù)據(jù)管理這一塊有些細(xì)節(jié)值得介紹一下。

          初步考慮,可以將每個(gè)實(shí)例的服務(wù)元數(shù)據(jù)寫到到對(duì)應(yīng)的 K8S Pod 注解里。該方案每個(gè)實(shí)例注冊都需要寫一份完整的服務(wù)元數(shù)據(jù),但事實(shí)上大部分實(shí)例的服務(wù)元數(shù)據(jù)都是相同的,或僅存在非常少數(shù)的幾個(gè)版本。因此,存在極大的優(yōu)化空間。

          這里優(yōu)化的主要思路是,當(dāng)某個(gè)實(shí)例注冊元數(shù)據(jù)時(shí),可以先檢查一下對(duì)應(yīng)版本的服務(wù)元數(shù)據(jù)是否已存在,如果已存在,則不需要再寫入了。那如何確定服務(wù)元數(shù)據(jù)的版本呢?根據(jù) K8S Pod 的 Labels。因?yàn)橄嗤?Labels 的 Pod 實(shí)例的鏡像、配置等都是相同的,則他們的服務(wù)能力、服務(wù)元數(shù)據(jù)也必定一致。為什么呢?因?yàn)椋琇abels 相同的 Pod 都是由同一個(gè) ReplicaSet 創(chuàng)建的,按照云原生的理念它們的服務(wù)能力必定是一致的。既然每個(gè) ReplicaSet 產(chǎn)生的 Pod 它們的服務(wù)注冊元數(shù)據(jù)是一致的,那是不是該 ReplicaSet 創(chuàng)建的 Pod 的元數(shù)據(jù)可以寫入到 ReplicaSet 的注解里。這個(gè)方案是沒問題的。但是我們基于 K8S API Server 權(quán)限最小化的考慮,沒有采用該方案,畢竟 ReplicaSet 是 K8S 核心資源,最好不要放開權(quán)限。我們采用 CRD 單獨(dú)保存元數(shù)據(jù)的方式,即 ServiceMetadata CRD。一個(gè) ServiceMetadata 資源里,管理一個(gè)應(yīng)用的多個(gè)版本的服務(wù)元數(shù)據(jù)。

          服務(wù)元數(shù)據(jù)模型如下所示:

          {
          "subset_metadata":[
          {
          "subset_id":"1",
          "selector":{
          "pod-template-hash":"f845f5775",
          "app":"java-demo",
          "zone":"qa"
          },
          "dubbo_rpc_metadata":{
          "interfaces":[
          {
          "name":"com.youzan.java.demo.api.EchoService",
          "methods":[
          "echo"
          ]
          }
          ]
          }
          },
          {
          "subset_id":"2",
          "selector":{
          "pod-template-hash":"67bd5c9db9",
          "app":"java-demo",
          "zone":"qa"
          },
          "dubbo_rpc_metadata":{
          "interfaces":[
          {
          "name":"com.youzan.java.demo.api.EchoService",
          "methods":[
          "echo"
          ]
          },
          {
          "name":"com.youzan.java.demo.api.HelloService",
          "methods":[
          "hello"
          ]
          }
          ]
          }
          }
          ]
          }

          當(dāng)注冊請求達(dá)到 Istio Pilot 時(shí),Istio Pilot 通過本地 K8S Client Cache 查詢 ServiceMetadata 中是否包含對(duì)應(yīng)版本的服務(wù)元數(shù)據(jù)(通過對(duì)應(yīng)實(shí)例的 Pod Labels 與 ServiceMetadata 所有版本的 Selector 進(jìn)行匹配),如果存在,直接返回即可。不存在,向 K8S API Server 發(fā)起請求更新 ServiceMetadata,寫入對(duì)應(yīng)版本的服務(wù)元數(shù)據(jù)。如果 K8S API Server 返回版本沖突錯(cuò)誤,說明有其他注冊請求修改了 ServiceMetadata,則需要客戶端重試,重試時(shí)大概率會(huì)通過 K8S Client Cache 發(fā)現(xiàn)對(duì)應(yīng)版本的服務(wù)元數(shù)據(jù)已經(jīng)存在。這里我們可以發(fā)現(xiàn),通過該優(yōu)化,一個(gè) ReplicaSet 下的所有 Pod 實(shí)例只需要寫一次服務(wù)元數(shù)據(jù),即使有寫沖突,概率也是很低的。并且,一個(gè) Deployment 創(chuàng)建新版本的實(shí)例集時(shí),都是會(huì)分多個(gè)批次創(chuàng)建新的實(shí)例集的 Pod 的,取決于 MaxSurge 參數(shù),沖突也僅會(huì)出現(xiàn)在第一個(gè)批次。由于大部分場景都不需要直接跟 K8S API Server 直接交互,大大降低了服務(wù)注冊的開銷。

          老的版本的元數(shù)據(jù)如何刪除呢?因?yàn)槊總€(gè)版本的元數(shù)據(jù)和 ReplicaSet 是一一對(duì)應(yīng)的,所以,只要實(shí)現(xiàn)一個(gè) ReplicaSet 的自定義 Controller,當(dāng) ReplicaSet 對(duì)象被刪除時(shí),刪除對(duì)應(yīng)的版本的元數(shù)據(jù)即可。關(guān)聯(lián)關(guān)系我們采用 K8S 的 Selector 機(jī)制來處理。

          4.3多機(jī)房服務(wù)發(fā)現(xiàn)

          請求路由時(shí),我們一般都有本機(jī)房路由優(yōu)先原則,即如果本機(jī)房內(nèi)有對(duì)應(yīng)的服務(wù)實(shí)例,請求路由到本機(jī)房的實(shí)例。一般來說,每個(gè)機(jī)房內(nèi)的應(yīng)用部署是完備的,很少需要進(jìn)行跨機(jī)房訪問。如果有比較大的故障,一般也會(huì)切掉整個(gè)機(jī)房的流量到其他機(jī)房。但也有如下特殊情況:

          • 內(nèi)部控制臺(tái)應(yīng)用,無需多機(jī)房容災(zāi),只部署在一個(gè)機(jī)房;

          • 大數(shù)據(jù)應(yīng)用,成本太高,也有很多離線計(jì)算服務(wù)不需要高可用,基于成本考慮只部署在一個(gè)機(jī)房;

          • 某個(gè)機(jī)房應(yīng)用實(shí)例異常,或突發(fā)流量不均衡等,需要調(diào)度部分流量或全部流量到其他機(jī)房;

          • 機(jī)房遷移時(shí),短期內(nèi)無法全量部署所有應(yīng)用,需要有能力將部分應(yīng)用流量調(diào)度到其他機(jī)房。

          多機(jī)房服務(wù)發(fā)現(xiàn)的支持,一般有三種思路:

          • 注冊中心層支持,也就是注冊中心包含所有機(jī)房實(shí)例的注冊數(shù)據(jù),實(shí)現(xiàn)方案是實(shí)例啟動(dòng)的時(shí)候注冊到所有注冊中心。該方案有不具備可伸縮性,注冊中心很容易出現(xiàn)瓶頸。

          • 中間層支持,如 Istio Pilot,監(jiān)聽所有機(jī)房的注冊中心。同樣不具備可伸縮性。

          • 客戶端支持,如 Tether,監(jiān)聽所有機(jī)房的注冊中心或中間層,因?yàn)槊總€(gè)應(yīng)用需要訂閱的應(yīng)用數(shù)目相對(duì)是有限的,所以可伸縮性方面沒有瓶頸。

          有贊的多機(jī)房服務(wù)發(fā)現(xiàn)采用的是客戶端支持方案。架構(gòu)圖如下所示:?

          83a07e27011c488cc1bedf7b7a2911a6.webp

          應(yīng)用服務(wù)注冊只注冊到本機(jī)房注冊中心,Istio Pilot 只對(duì)接本機(jī)房注冊中心,Tether 對(duì)接多個(gè)機(jī)房的 Istio Pilot,默認(rèn)情況下只訪問本機(jī)房 Istio Pilot,當(dāng)因本機(jī)房應(yīng)用實(shí)例不存在或異常,需要將部分流量或全部流量切至其他機(jī)房實(shí)例時(shí),Tether 再訪問其他機(jī)房 Istio Pilot,獲取其他機(jī)房的服務(wù)實(shí)例,進(jìn)行后續(xù)的路由調(diào)度。該方案即實(shí)現(xiàn)了多機(jī)房服務(wù)發(fā)現(xiàn)的可伸縮能力,也避免了大部分場景下不必要的服務(wù)發(fā)現(xiàn)開銷。

          、總結(jié)

          本文介紹了有贊近幾年服務(wù)注冊與發(fā)現(xiàn)架構(gòu)演進(jìn)過程,主要包括三個(gè)階段:接口級(jí)服務(wù)注冊與發(fā)現(xiàn)、接口級(jí)服務(wù)注冊與應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)、應(yīng)用級(jí)服務(wù)注冊與發(fā)現(xiàn)。雖然這期間整體架構(gòu)變化比較大,但是我們做到了平穩(wěn)、平滑地演進(jìn),期間上層業(yè)務(wù)應(yīng)用無感知,所有功能由 Dubbo 框架、Service Mesh 等基礎(chǔ)組件來支持。雖然,有贊的演進(jìn)之路不一定適合其他公司場景,但也希望能為大家提供一種思路。

          感謝閱讀。

          參考資料
          • 阿里技術(shù)專家詳解 Dubbo 實(shí)踐、演進(jìn)及未來規(guī)劃,https://www.infoq.cn/article/IwZCAp3jo_H5fJFbWOZu 。

          • Dubbo 邁出云原生重要一步:應(yīng)用級(jí)服務(wù)發(fā)現(xiàn)解析,https://www.infoq.cn/article/GUvBbu5Mbv5uXfj1lLrL 。

          • 有贊灰度發(fā)布與藍(lán)綠發(fā)布實(shí)踐,https://tech.youzan.com/gray-deloyments-and-blue-green-deployments-practices-in-youzan/?。

          • Service Mesh在有贊的實(shí)踐與發(fā)展,https://tech.youzan.com/service-meshzai-you-zan-de-shi-jian-yu-fa-zhan/?。

          • Zan PHP Framework,http://zanphp.io/?。


          招募優(yōu)秀的你加入??





          ????
          瀏覽 35
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人干人人妻 | 日批视频| 日韩无码免费播放 | 777亚洲视频 | 免费国产h |