技术分享:浅谈Service Mesh在瓜子的实践
作者 | zeyaries
過去三年,微服務(wù)成為業(yè)界的技術(shù)熱點(diǎn),大量互聯(lián)網(wǎng)公司都在做微服務(wù)架構(gòu)落地,新一代微服務(wù)開發(fā)技術(shù)悄然興起,Service Mesh 便是其中之一,該技術(shù)起初由 Linkerd 的 CEO William 提出,其中文翻譯為服務(wù)網(wǎng)格,功能在于處理服務(wù)間通信,負(fù)責(zé)實(shí)現(xiàn)請求的可靠傳遞。本文,瓜子效能團(tuán)隊(duì)分享了在 K8S 的基礎(chǔ)上,通過 Sidecar 模式進(jìn)行 Service Mesh 的實(shí)踐經(jīng)歷。
一、背景??
起初,瓜子內(nèi)部各業(yè)務(wù)線團(tuán)隊(duì)為了方便、快速地開發(fā)后端服務(wù),使用了各種傳統(tǒng)后端開發(fā)框架,順利保障各項(xiàng)業(yè)務(wù)上線。隨著時間的推移,瓜子的系統(tǒng)規(guī)模越來越大,架構(gòu)復(fù)雜度也越來越高。為了更好的應(yīng)對傳統(tǒng)開發(fā)方式帶來的挑戰(zhàn),瓜子開始落地微服務(wù)化,后端項(xiàng)目不斷拆分。在這個過程中,微服務(wù)化給我們帶來了更好的靈活性、擴(kuò)展性,良好的故障彈性以及不受技術(shù)棧限制等優(yōu)勢。
但是,隨著瓜子業(yè)務(wù)的高速發(fā)展,業(yè)務(wù)開發(fā)范圍進(jìn)一步增大,微服務(wù)的缺點(diǎn)逐漸暴露出來。綜合前期的技術(shù)框架以及微服務(wù)架構(gòu),主要存在如下不足:
當(dāng)前通信框架過多、依賴版本眾多,維護(hù)及后續(xù)擴(kuò)展存在諸多不便,比如加入 SSO 驗(yàn)簽中間件、黑白名單中間件時,需要針對不同的框架進(jìn)行開發(fā),效率及維護(hù)都有很大挑戰(zhàn);
前期框架在服務(wù)治理方面能力較弱,沒有服務(wù)注冊與服務(wù)發(fā)現(xiàn),不便于后續(xù)微服務(wù)架構(gòu)推行;
服務(wù)實(shí)例快速增長,請求在各服務(wù)間穿梭變得越來越復(fù)雜,每個服務(wù)出現(xiàn)問題都可能造成整個項(xiàng)目出現(xiàn)異常,并且不容易定位到具體問題,給運(yùn)維加大了難度;
每個微服務(wù)都需要重復(fù)實(shí)現(xiàn)一些基礎(chǔ)功能,比方說鑒權(quán)管理、負(fù)載均衡、熔斷等,對代碼侵入性強(qiáng),重復(fù)工作的同時提升后續(xù)技術(shù)替換成本。
根據(jù)上述不足,瓜子內(nèi)部開始考慮實(shí)踐 Service Mesh,這給瓜子帶來了如下好處:
業(yè)務(wù)團(tuán)隊(duì)更加專注核心業(yè)務(wù)邏輯和功能,不用過多關(guān)注基礎(chǔ)設(shè)施;
一套基礎(chǔ)設(shè)施能夠靈活支持多種語言的業(yè)務(wù)開發(fā),很好的解決服務(wù)異構(gòu)化程度較高的場景;
業(yè)務(wù)團(tuán)隊(duì)與基礎(chǔ)架構(gòu)團(tuán)隊(duì)解耦,基礎(chǔ)設(shè)施與業(yè)務(wù)應(yīng)用代碼解耦。
二、Service Mesh 實(shí)踐??
2.1 整體架構(gòu)??
作為一種基礎(chǔ)設(shè)施,K8S 的 pod 天然可以支持多個 Container,能夠非常方便地運(yùn)行 sidecar 模式。因此,我們決定在 K8S 的基礎(chǔ)上,通過 sidecar 模式進(jìn)行 Service Mesh 實(shí)踐。
具體架構(gòu)圖如下所示:
圖 1 Service Mesh 框架圖在 Sidecar 部署方式中,每個應(yīng)用容器都會部署一個伴生容器。對于 Service Mesh,sidecar 接管進(jìn)出應(yīng)用程序容器的所有網(wǎng)絡(luò)流量。
基于 sidecar,我們可以實(shí)現(xiàn)服務(wù)之間的調(diào)用攔截,服務(wù)之間的的所有流量都會經(jīng)過 sidecar,并通過其進(jìn)行轉(zhuǎn)發(fā)。所有 sidecar 組成了一個服務(wù)網(wǎng)格,再通過統(tǒng)一的地方(這里的“地方”兩個字有點(diǎn)模糊,可以理解為統(tǒng)一的入口)與各 sidecar 交互,就能控制網(wǎng)格中的流量運(yùn)轉(zhuǎn)。
2.2 gRPCx(Service Mesh 實(shí)現(xiàn)的載體)??
我們采用 gRPC 作為通信框架,在原生 gRPC 的基礎(chǔ)上,結(jié)合瓜子業(yè)務(wù)情況對其進(jìn)行增強(qiáng),幫助用戶更加方便的使用 gRPC 相關(guān)功能。同時,整合并收斂前期 web 框架,解決前期框架過多維護(hù)及擴(kuò)展困難的問題。gRPCx 提供可插拔的中間件,用戶在使用過程中能夠方便地加入埋點(diǎn)、驗(yàn)簽、鑒權(quán)、監(jiān)控等功能。支持上下文穿透,gRPCx 能夠?qū)?traceID、用戶 ID 等信息合并到 gRPC 請求中,一起發(fā)給服務(wù)端。另外,gRPCx 較為完整地滿足服務(wù)開發(fā)及治理的基礎(chǔ)功能,包括優(yōu)雅的服務(wù)注冊、發(fā)現(xiàn)及下線,服務(wù)端負(fù)載均衡及高可用等功能。基于服務(wù)注冊與服務(wù)發(fā)現(xiàn),服務(wù)在 K8S 上部署時可以沒有域名,直接通過 IP 訪問服務(wù),減少 DNS 服務(wù)的壓力。
gRPCx 是我們實(shí)現(xiàn) Service Mesh 的關(guān)鍵所在,其框架如下圖所示:
圖 2 gRPCx 框架圖gRPCx 相關(guān)組件可以被定義為在微服務(wù)拓?fù)浣Y(jié)構(gòu)中處理各個服務(wù)之間通信的基礎(chǔ)設(shè)施層,不僅能夠幫助降低微服務(wù)體系結(jié)構(gòu)的相關(guān)復(fù)雜性,同時也能夠提供服務(wù)治理等功能。
Registry:使用 ETCD 作為注冊中心,用于服務(wù)注冊及發(fā)現(xiàn);
gRPC server:使用 gRPCx 框架實(shí)現(xiàn),用于提供業(yè)務(wù)服務(wù)功能;
gRPC bridge:與 gRPC server 通過 sidecar 的方式部署在 K8S 的同一個 pod 中,用于獲取 gRPC server 的服務(wù)信息,并將其注冊到 Registry 中。同時提供 HTTP 橋接功能,將 HTTP 請求轉(zhuǎn)換為 gRPC 請求發(fā)送給 gRPC server;
gRPC proxy:作為 gRPC 請求的入口,根據(jù) gRPC 請求的服務(wù)信息在 Registry 中查找服務(wù)信息進(jìn)行服務(wù)發(fā)現(xiàn),然后將 gRPC 請求轉(zhuǎn)發(fā)到目標(biāo)業(yè)務(wù)服務(wù)器,從而訪問 gRPC 服務(wù);
gRPC gateway:作為 HTTP 請求的入口,根據(jù)請求的服務(wù)信息在 Registry 中查找服務(wù)信息進(jìn)行服務(wù)發(fā)現(xiàn),然后將 HTTP 請求轉(zhuǎn)換為 gRPC 請求發(fā)往目標(biāo)業(yè)務(wù)服務(wù)器上,從而使得 HTTP 請求能夠訪問 gRPC 服務(wù)。
2.3 服務(wù)治理??
基于 K8S 的 sidecar 模式,我們將復(fù)雜的服務(wù)治理從業(yè)務(wù)服務(wù)中分離出來,并將這部分功能放入到 sidecar 中進(jìn)行處理。sidecar 中的服務(wù)代理提供諸如流量及熔斷控制、服務(wù)注冊與發(fā)現(xiàn)、監(jiān)控、驗(yàn)簽以及安全埋點(diǎn)等功能特性,開發(fā)人員在使用時只關(guān)注自己的業(yè)務(wù)功能開發(fā)即可。同時,通過 sidecar 與 gRPCx 結(jié)合的方式,我們實(shí)現(xiàn)了 gRPC 應(yīng)用提供 HTTP 以及 gRPC 兩種訪問接口,使用起來較為靈活。
?? ?2.3.1 HTTP 請求橋接
圖 3 gRPC bridge 請求橋接工作流程圖基于服務(wù)調(diào)用方可以通過 HTTP 方式訪問 gRPC 服務(wù),gRPC bridge 會將 HTTP 請求轉(zhuǎn)換為 gRPC 請求,然后再發(fā)往 gRPC server。這種方式使 gRPC server 也具備提供 HTTP 服務(wù)的能力,方便需要使用 HTTP 請求的調(diào)用。
?? ?2.3.2 服務(wù)注冊
圖 4 服務(wù)注冊工作流程圖服務(wù)發(fā)布
gRPC server 使用 gRPCx 框架創(chuàng)建服務(wù)后,將提供服務(wù)信息獲取接口。我們基于 K8S 將 gRPC bridge 作為 sidecar 與 gRPC server 部署在同一個 pod 中,gRPC bridge 通過配置信息獲取 gRPC server 的端口信息,然后監(jiān)聽 gRPC server 服務(wù)信息獲取接口,當(dāng) gRPC server 服務(wù)啟動后,將服務(wù)信息注冊到 Registry 中。
服務(wù)下線
gRPC bridge 提供服務(wù)下線功能,當(dāng) gRPC server 服務(wù)停止后,其會從 Registry 摘除對應(yīng)節(jié)點(diǎn)信息,并通過監(jiān)聽 gRPC server 服務(wù)信息獲取接口,當(dāng) gRPC server 服務(wù)信息更新后,會更新 Registry 中對應(yīng)節(jié)點(diǎn)的信息。
用戶能夠通過 Registry 的 web UI,方便查看其服務(wù)被注冊的具體情況。
?? ?2.3.3 服務(wù)發(fā)現(xiàn)
考慮到 K8S 的服務(wù)發(fā)現(xiàn)基于 DNS 尋址實(shí)現(xiàn),部署到 K8S 上面的服務(wù)會生成一條 DNS 記錄指向其被分配的的 cluster IP,其他服務(wù)在通過 K8S namespace+ 服務(wù)名去調(diào)用服務(wù)。我們基于 gRPC 實(shí)現(xiàn)的服務(wù)發(fā)現(xiàn)的粒度更細(xì),能夠使用具體接口(service name+method name)進(jìn)行服務(wù)發(fā)現(xiàn),并且支持 HTTP 與 gRPC 兩種調(diào)用的服務(wù)發(fā)現(xiàn),使用起來更加靈活方便。而且服務(wù)發(fā)現(xiàn)會有降級策略,Registry 宕機(jī)后,服務(wù)發(fā)現(xiàn)將會基于內(nèi)存中存儲的信息進(jìn)行。因此,我們并沒有使用 K8S 的服務(wù)發(fā)現(xiàn)。
基于 gRPC proxy 的服務(wù)發(fā)現(xiàn)
圖 5 gRPC proxy 服務(wù)發(fā)現(xiàn)工作流程圖當(dāng) gRPC 請求發(fā)往 gRPC proxy(該服務(wù)地址確定,后續(xù)不會發(fā)生變化)后,proxy 根據(jù)服務(wù)信息進(jìn)行服務(wù)發(fā)現(xiàn),獲取 Registry 中對應(yīng)的服務(wù)地址,然后會將 gRPC 請求轉(zhuǎn)發(fā)到目標(biāo) gRPC server 上。
基于 gRPC gateway 的服務(wù)發(fā)現(xiàn)
圖 6 gRPC gateway 服務(wù)發(fā)現(xiàn)工作流程圖當(dāng) HTTP 請求發(fā)往 gRPC gateway(該服務(wù)地址確定,后續(xù)不會發(fā)生變化)后,gateway 根據(jù)服務(wù)信息進(jìn)行服務(wù)發(fā)現(xiàn),獲取 Registry 中對應(yīng)的服務(wù)地址,然后會將 HTTP 請求轉(zhuǎn)換為 gRPC 請求并發(fā)送到目標(biāo) gRPC server 上。
當(dāng)服務(wù)部署多個實(shí)例時,gRPC gateway 跟 gRPC proxy 會采用 RoundRobin 負(fù)載均衡策略,最終路由到其中一個服務(wù)實(shí)例上。
2.4 健康檢查與容災(zāi)??
?? ?2.4.1 健康檢查
使用 gRPCx 框架創(chuàng)建服務(wù)后,gRPC server 將提供 heartbeat 的 gRPC 接口。我們的健康檢查是基于宿主機(jī)提供的 HTTP 形式的心跳檢查,將心跳檢查發(fā)送給 gRPC bridge,由 gRPC bridge 將 HTTP 形式的心跳檢查轉(zhuǎn)換為 gRPC 形式的心跳檢查,gRPC bridge 并將 gRPC 的返回轉(zhuǎn)換為 HTTP 的返回,發(fā)給心跳發(fā)起服務(wù)。
Liveliness
在服務(wù)啟動成功后心跳檢測間隔時間,如果檢測的 StatusCode 非 200 會自動重啟服務(wù)所在容器。
Readiness
屬性在服務(wù)啟動成功后心跳檢測間隔時間,連續(xù) 3 次檢查失敗后,會將當(dāng)前流量摘除,應(yīng)用不會重啟。當(dāng)下一次檢測正常時,就會恢復(fù)流量。在滾動更新實(shí)例時,會先將其中一個老實(shí)例摘除流量并終止老實(shí)例,同時起一個新實(shí)例。在 readiness 檢測正常后,就會分配流量給新實(shí)例,同時更新下一個老實(shí)例。這樣就會保證流量不丟失。
服務(wù)關(guān)閉或者服務(wù)不可用時,gRPC bridge 會從 Registry 中摘除服務(wù)對應(yīng)的相關(guān)信息;服務(wù)啟動或者可用時,gRPC bridge 會將服務(wù)對應(yīng)的 IP 及 API 信息注冊到 Registry 中。
?2.4.2 容災(zāi)
單獨(dú)通過 gRPC bridge 服務(wù)主動探測也存在隱患,當(dāng) gRPC bridge 出現(xiàn)問題或者是 gRPC bridge 到 gRPC server 網(wǎng)絡(luò)存在問題時,其無法調(diào)用 gRPC server 接口,從而無法到 Registry 中更新與摘除相關(guān)服務(wù)。此時,我們通過一個獨(dú)立運(yùn)行的 gRPC monitor 實(shí)例監(jiān)控 gRPC server 服務(wù)的可用性,若 gRPC server 服務(wù)存在問題不可用時,gRPC monitor 會到 Registry 中摘除相關(guān)節(jié)點(diǎn)信息,調(diào)用方能夠及時感知服務(wù)下線,進(jìn)一步保障服務(wù)注冊與下線功能的完整性。
Registry 采用的是 ETCD 集群,隨著業(yè)務(wù)發(fā)展,服務(wù)進(jìn)一步增多,Registry 的壓力會越來越大。由于 ETCD 使用 Raft 協(xié)議維護(hù)集群內(nèi)各個節(jié)點(diǎn)狀態(tài)的一致性,通過水平擴(kuò)展 Registry 的節(jié)點(diǎn)數(shù)量來提升讀性能,但是會降低集群的寫性能,這是我們后續(xù)需要優(yōu)化的一個點(diǎn)。
圖 7 Registry 不可用時, 服務(wù)發(fā)現(xiàn)工作流程圖我們的服務(wù)發(fā)現(xiàn)采用本地內(nèi)存緩存作為降級方案,當(dāng) Registry 集群完全宕機(jī)或者 Registry 集群連接不可達(dá)時,不會影響服務(wù)的正常調(diào)用。此外,基于 ETCD 的 watch 機(jī)制,當(dāng) Registry 中的服務(wù)信息發(fā)生變化時,能夠及時更新內(nèi)存中存儲的服務(wù)信息。
出于對系統(tǒng)穩(wěn)定性及安全性考慮,我們在服務(wù) sidecar 中的 gRPC bridge 加入了熔斷機(jī)制,當(dāng)滿足一定條件后,gRPC bridge 直接將請求熔斷,并不會將請求轉(zhuǎn)發(fā)給 gRPC server,減輕了服務(wù)端壓力。接下來,我們會圍繞 sidecar 中的 gRPC bridge 擴(kuò)展出更多實(shí)用功能,方便開發(fā)人員使用。
2.5 日志與安全??
圖 8 日志全鏈路追溯示意圖在微服務(wù)架構(gòu)中,隨著服務(wù)數(shù)量的增多,各節(jié)點(diǎn)之前的調(diào)用關(guān)系變得越來復(fù)雜,對我們查找問題帶來了挑戰(zhàn)。我們有時會為了追溯一個問題,統(tǒng)計(jì)幾個甚至幾十個服務(wù)日志信息,然后再進(jìn)行問題查找,這樣使用起來非常不方便,不能快速、準(zhǔn)確的定位問題。gRPCx 框架服務(wù)在其他服務(wù)調(diào)用請求傳入時就可通過 gRPCx 中間件自動加上標(biāo)簽 (traceID,如果傳入的請求已經(jīng)存在標(biāo)簽,則后續(xù)使用已存在的標(biāo)簽),該 traceID 與請求一起傳入到后臺服務(wù)中,后臺服務(wù)從 context 中獲取該 traceID,與瓜子日志組件聯(lián)合使用,在日志收集時自動加上 traceID,方便追蹤全鏈路上與該請求相關(guān)的調(diào)用。如果涉及到多個服務(wù)之間的調(diào)用,通過該 traceID 能夠很好地串聯(lián)請求調(diào)用鏈,使開發(fā)人員非常容易的進(jìn)行問題查找及追溯,減少與微服務(wù)結(jié)構(gòu)相關(guān)的復(fù)雜性。
同時,基于 gRPCx 中間件,方便實(shí)現(xiàn)鑒權(quán)、驗(yàn)簽、安全統(tǒng)一埋點(diǎn)等功能。我們在中間件提供了鑒權(quán)、驗(yàn)簽等功能,統(tǒng)一接入瓜子 SSO,避免開發(fā)人員在業(yè)務(wù)代碼中重復(fù)加入這些功能,將鑒權(quán)、驗(yàn)簽等功能從業(yè)務(wù)代碼中剝離出來,減少與業(yè)務(wù)代碼的耦合,讓業(yè)務(wù)代碼更加干凈。基于中間件,可以方便地進(jìn)行安全埋點(diǎn),將請求數(shù)據(jù)中需要收集的信息發(fā)送至 Kafka,并通過 Kafka 存入 Hive,方便后續(xù)分析使用。
三、總結(jié)與展望??
在 K8S 的基礎(chǔ)上,瓜子通過 sidecar 模式,使用一個與主服務(wù)獨(dú)立的代理服務(wù)(使用 gRPC 與主服務(wù)進(jìn)行通信),讓服務(wù)之間的通信更加簡單、高效。在 sidecar 中運(yùn)行的 gRPC bridge 不僅能夠提供業(yè)務(wù)之外的功能,比如路由、監(jiān)控、日志收集和訪問控制等,而且還能作為一個透明的基礎(chǔ)結(jié)構(gòu)層,存在于微服務(wù)與外部網(wǎng)絡(luò)之間。在 gRPC bridge 的幫助下,一套 gRPC 服務(wù)代碼能夠同時提供 HTTP、gRPC 的服務(wù)接口,方便開發(fā)人員使用,也方便將業(yè)務(wù)拆分。調(diào)用方使用 gRPC gateway、gRPC proxy 能夠更加方便、快捷的調(diào)用各個微服務(wù),再輔以鑒權(quán)、驗(yàn)簽以及安全埋點(diǎn)等中間件,配合可靠的全鏈路日志追溯、優(yōu)雅的服務(wù)治理、成熟的健康檢查機(jī)制等,瓜子整個微服務(wù)體系變得更加完善。
現(xiàn)階段,瓜子的 Service Mesh 實(shí)踐還處于起步階段,存在諸多不足。未來,瓜子將結(jié)合復(fù)雜的業(yè)務(wù)環(huán)境,在不斷完善現(xiàn)有 gRPCx 生態(tài)的基礎(chǔ)上,圍繞 Service Mesh 開展工作,例如,更加完善的微服務(wù)監(jiān)控體系、故障注入和容錯、高級服務(wù)路由。服務(wù)熔斷與降級、更加完備的容災(zāi)、高可用策略等,降低單個應(yīng)用自身復(fù)雜度,并在 K8S 的支撐下,簡化部署、管理、監(jiān)控、維護(hù)等較為繁瑣性的工作。我們的開發(fā)人員只用在此基礎(chǔ)上享受基于 gRPCx 生態(tài)的 Service Mesh 帶來的使用便利。
作者介紹
zeyaries,瓜子效能團(tuán)隊(duì)一員,效能團(tuán)隊(duì)致力于提升瓜子技術(shù)團(tuán)隊(duì)的研發(fā)效率,為瓜子研發(fā)相關(guān)人員提供工具支撐。通過對前沿技術(shù)不斷地探索與研究,落地應(yīng)用到實(shí)際中,幫助業(yè)務(wù)團(tuán)隊(duì)提升交付速率以及交付質(zhì)量。
總結(jié)
以上是生活随笔為你收集整理的技术分享:浅谈Service Mesh在瓜子的实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一条简单的 SQL 执行超过1000ms
- 下一篇: 一次服务器CPU占用率高的定位分析