點(diǎn)擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)”
回復(fù)”669“獲取獨(dú)家整理的精選資料集
回復(fù)”加群“加入全國(guó)服務(wù)端高端社群「后端圈」
2021 年是小米中國(guó)區(qū)電商部門變動(dòng)調(diào)整較大的一年,小米中國(guó)區(qū)早期電商、服務(wù)體系建立在 Go 語(yǔ)言構(gòu)建的微服務(wù)體系之上,由內(nèi)部自研的 Go 語(yǔ)言微服務(wù)框架 koala 支撐起數(shù)以千計(jì)的微服務(wù)應(yīng)用。隨著業(yè)務(wù)的發(fā)展,新零售體系的成立以及業(yè)務(wù)中臺(tái)普及與推廣,我們更傾向于擁有豐富生態(tài)的 Java 為主的微服務(wù)體系技術(shù)選型,新項(xiàng)目及服務(wù)大多基于 Apache Dubbo、Spring Cloud 的微服務(wù)生態(tài)。
考慮到服務(wù)遷移的巨大成本以及服務(wù)穩(wěn)定性的保障,我們最終決定在大范圍投入與使用以 Apache Dubbo 為主的服務(wù)體系的同時(shí),保留原有 Go 微服務(wù)項(xiàng)目。由于原有跨部門的技術(shù)選型差異,留存的服務(wù)包含基于 Thrift、gRPC 等不同協(xié)議服務(wù),我們希望多套微服務(wù)體系能夠無(wú)縫穩(wěn)定地融合。在經(jīng)過大量調(diào)研之后,確定了以 Dubbo+Nacos+etcd+sidecar+mirpc+Dubbo-go 的為核心的一套互通的微服務(wù)體系。
mione 是一套由小米公司新零售效能團(tuán)隊(duì)開源的“項(xiàng)目創(chuàng)建->開發(fā)->測(cè)試->發(fā)布->運(yùn)維” 端到端的系統(tǒng)服務(wù)和研發(fā)工具,支持物理機(jī)部署、docker 部署、K8s、dockerFile 部署等多種部署形態(tài),通過人工智能、自動(dòng)化技術(shù)的應(yīng)用助力開發(fā)者提升研發(fā)效能,持續(xù)快速交付有效價(jià)值。詳細(xì)了解可以通過官網(wǎng):http://mone.xiaomiyoupin.com/index#/index目前內(nèi)部基于 Java Dubbo 生態(tài)的微服務(wù)基本上都托管于 mione,并以 Nacos 為注冊(cè)中心,這些服務(wù)作為 consumer 基本上通過 Apache Dubbo、side-car 兩種方式實(shí)現(xiàn)調(diào)用。
koala 是小米內(nèi)部自研的 Go 語(yǔ)言的微服務(wù)框架,基于 etcd 的注冊(cè)中心以及 Thrift 協(xié)議。作為服務(wù)的提供方,服務(wù)注冊(cè)將自身元數(shù)據(jù)等信息注冊(cè)到 etcd 中,并對(duì)外提供 Thrift 的服務(wù)。Java Dubbo 的 consumer 服務(wù)則通過 side-car 兼容 Thrift/gRPC 協(xié)議,基于 etcd 進(jìn)行服務(wù)發(fā)現(xiàn)調(diào)用。sidecar 同樣是小米內(nèi)部自研的用于服務(wù)注冊(cè)及發(fā)現(xiàn),支持跨服務(wù)調(diào)用的組件,名為 soa-agent ,以 side-car 的方式同服務(wù)部署于 mione 容器中,服務(wù)借助該組件實(shí)現(xiàn)兼容協(xié)議的 RPC 調(diào)用,具體技術(shù)細(xì)節(jié)這里不做詳細(xì)介紹。
我們以 side-car 的方式解決了 Java 服務(wù)的 consumer 到 Go 服務(wù)基于 Thrift/gRPC 的調(diào)用,而 Go 服務(wù)到新項(xiàng)目,即基于Apache Dubbo 生態(tài)的 Java 服務(wù)的調(diào)用,在經(jīng)過大量調(diào)研與參考后,決定使用還在不斷進(jìn)行迭代的 Apache Dubbo-go。Apache Dubbo-go 是當(dāng)前 Apache Dubbo 多語(yǔ)言支持中較為熱門的項(xiàng)目,社區(qū)也較為活躍。Apache Dubbo-go 由 Go 語(yǔ)言實(shí)現(xiàn),繼承了?Apache Dubbo 的設(shè)計(jì)理念與架構(gòu),擁有較好的可擴(kuò)展性。它能夠架起 Java 和 Go 之間的橋梁,與 gRPC/Apache Dubbo 生態(tài)互聯(lián)互通,這正式對(duì)于是我們當(dāng)前痛點(diǎn)較好的解決方案,所支持的 Nacos 注冊(cè)中心也與我們當(dāng)前中間件的技術(shù)選型契合。???????Apache Dubbo-go的應(yīng)用
經(jīng)過調(diào)研后,我們選用了當(dāng)時(shí)較為穩(wěn)定的 v1.5.7 版本進(jìn)行接入。Apache Dubbo 官方文檔中提供了使用 Apache Dubbo-go 的一般調(diào)用方式,如下:https://dubbo.apache.org/zh/docs/languages/golang/dubbo-go-1.5/quick-start/但該方式需要業(yè)務(wù)方調(diào)用方嚴(yán)格遵守切合服務(wù)方提供的接口格式、數(shù)據(jù)格式,因此我們選擇使用泛化的方式進(jìn)行調(diào)用。
對(duì)于一個(gè) Java 的 Apache Dubbo 服務(wù)提供的接口如下:public interface DubboHealthService {
List health(); String ping(String param,int param2); AaRes health1(List list); Health health2(AaReq aaReq);
}
@Service(timeout = 1000, group = "dev", version = "4.0")public class DubboHealthServiceImpl implements DubboHealthService { ......}
在 Apache Dubbo-go 的 client 配置文件中,需要的核心配置如下:registries: "demoNacos": protocol: "nacos" timeout: "3s" address: "xxx.xxx.xxx" username: "****" password: "****" references: "UserProvider": registry: "demoNacos" protocol: "dubbo" interface: "com.xiaomi.youpin.test0930.api.service.DubboHealthService" cluster: "failover" version: "4.0" group: "dev" generic: true methods: - name: "health" retries: 0 timeout: "0.5s" ......
首先配置對(duì)應(yīng)注冊(cè)中心,包括選型及地址,Nacos/zookeeper 等,其次配置需要調(diào)用的具體接口,方法、超時(shí)時(shí)間等信息。由于我們使用泛化調(diào)用,需要進(jìn)行配置 generic: true。這里我們?cè)谑褂?v1.5.7 版本時(shí)發(fā)現(xiàn)了關(guān)于泛化調(diào)用下方法級(jí)別超時(shí)時(shí)間并不生效的情況,進(jìn)行了修復(fù),詳細(xì)可以參考該 pr: https://github.com/apache/dubbo-go/pull/1336
配置完成后,泛化調(diào)用的方式我們進(jìn)行了一定的封裝:var paramTypes []stringvar paramVals []interface{}for _, param := range req.Params { paramTypes = append(paramTypes, param.GetKey()) paramVals = append(paramVals, param.GetVal())}m := make(map[string]string)m["xxx(generic_flag)"] = "xxx(flag)"m["xxx(return_flag)"] = "true" ctx = context.WithValue(context.Background(), constant.DubboCtxKey("attachment"), m)response, err = config.GetRPCService(req.AppName).(*config.GenericService).Invoke(ctx, []interface{}{req.MethodName, paramTypes, paramVals})if err != nil { err = fmt.Errorf("dubbo call request appName: %s methodName: %s rpc invoke failed,err:%+v", req.AppName, req.MethodName, err) return}
這里實(shí)際上業(yè)務(wù)只需要傳入需要調(diào)用的 Apache Dubbo 方法,參數(shù)列表例如 ?["java.lang.String"] 以及參數(shù)值即可。
為了切合業(yè)務(wù)需要,我們?cè)趦?nèi)部維護(hù)的 Java Dubbo 版本中也做了一定程度的兼容與改造,Apache Dubbo-go 中通過 context,即 attachment 可以帶上兩個(gè)特殊標(biāo)識(shí),服務(wù)端的 Java Dubbo 版本中將根據(jù)該特殊標(biāo)識(shí)接收處理與返回以 json 格式的數(shù)據(jù)。
這樣一來,留存的 Go 服務(wù)就能夠使用 Apache Dubbo 協(xié)議與 Java Dubbo 生態(tài)的服務(wù)達(dá)到互聯(lián)互通,同時(shí)也由于 Apache Dubbo 的優(yōu)勢(shì),也具備了一定程度的服務(wù)治理能力。
在線上運(yùn)行該版本 Apache Dubbo-go 時(shí),也發(fā)現(xiàn)了 Apache Dubbo-go 提供的像黑名單機(jī)制等的一些不太合理之處,例如該機(jī)制下,當(dāng)服務(wù)端出現(xiàn)報(bào)錯(cuò)后,調(diào)用方會(huì)將該服務(wù)端的 ip 記錄黑名單,再進(jìn)行調(diào)用時(shí)可能出現(xiàn) no provider 的情況,而實(shí)際上服務(wù)端可能僅是針對(duì)某個(gè)請(qǐng)求的處理報(bào)錯(cuò),服務(wù)實(shí)際上能夠正常運(yùn)行,那么這時(shí)候該機(jī)制便有待商榷,我們實(shí)際使用時(shí)也是進(jìn)行了摘除。詳細(xì)細(xì)節(jié)可見該 pr:https://github.com/apache/dubbo-go/pull/1605
目前小米新零售已經(jīng)基于上述 mione 的體系以及上述介紹的這一部分組件,建立了一套較為完善的,包括微服務(wù)標(biāo)準(zhǔn)化、可持續(xù)集成部署、以及可見可控的觀測(cè)性平臺(tái)的服務(wù)治理體系。在傳統(tǒng)的微服務(wù)體系下,我們通常需要滿足兩個(gè)服務(wù)治理的基本的需求:一站式的服務(wù)治理平臺(tái)、普適性的服務(wù)開發(fā)框架。前者我們通過 mione 實(shí)現(xiàn)了包括但不限于基于容器化的 CICD、服務(wù)的標(biāo)準(zhǔn)化定義、服務(wù)的生命周期管理(服務(wù)上下線、擴(kuò)縮容等)、服務(wù)的基本通信和鏈路治理(如重試、限流降級(jí)熔斷等);而后者我們借助了 Apache Dubbo 、Apache Dubbo-go 等開源 RPC 框架,結(jié)合像 Springboot 這樣的傳統(tǒng)開發(fā)框架提供了較為標(biāo)準(zhǔn)化的服務(wù)搭建開發(fā)流程。同時(shí),我們內(nèi)部自研了一套可見可觀測(cè)性體系,幫助我們獲取更多有價(jià)值的數(shù)據(jù)來反饋于服務(wù)治理,對(duì)服務(wù)做到更全面準(zhǔn)確的把控。這實(shí)際上包括了 3 個(gè)層次的工具集合:Logging(日志系統(tǒng))、Metric(度量系統(tǒng)) 以及 Tracing(分布式鏈路追蹤系統(tǒng))我們通過上述的架構(gòu)與設(shè)計(jì)實(shí)際上已經(jīng)基本上滿足了傳統(tǒng)方式下對(duì)微服務(wù)治理需求,然而,這還不夠。Service Mesh 與 Serverless
首先什么是 Service Mesh?Service Mesh 是一個(gè)致力于解決服務(wù)間通信的基礎(chǔ)設(shè)施層,它負(fù)責(zé)在現(xiàn)代云原生應(yīng)用的復(fù)雜服務(wù)拓?fù)湎聦?shí)現(xiàn)請(qǐng)求的可靠傳遞,它通常實(shí)現(xiàn)為一組輕量級(jí)的網(wǎng)絡(luò)代理,與應(yīng)用服務(wù)部署在一起,對(duì)應(yīng)用服務(wù)透明。我們上面架構(gòu)組件中的 sidecar soa-agent 實(shí)際上就是一個(gè) service mesh 的雛形,這個(gè)組件目前承擔(dān)了包括服務(wù)發(fā)現(xiàn)、配置托管等一些能力,當(dāng)然,他能夠做到的應(yīng)當(dāng)更多。對(duì)于業(yè)務(wù)應(yīng)用服務(wù)的透明以及零侵入是 service mesh 的一大優(yōu)勢(shì),也是當(dāng)前它正備受推崇的主要原因。綜合來看,Service Mesh 主要能夠解決當(dāng)下傳統(tǒng)微服務(wù)體系的幾大痛點(diǎn):1、完善的微服務(wù)基礎(chǔ)設(shè)施 service mesh 能夠?qū)⑽⒎?wù)的通信下沉到基礎(chǔ)設(shè)施層,它屏蔽了微服務(wù)處理各種通信問題的復(fù)雜度。對(duì)于業(yè)務(wù)開發(fā)者來說,實(shí)際上他并不關(guān)心像 Rpc 通信、服務(wù)注冊(cè)與發(fā)現(xiàn)這樣的非功能性細(xì)節(jié)。但傳統(tǒng)微服務(wù)下,拿 Thrift 舉例,作為開源的一套性能較高的 Rpc 框架,由于它缺乏一些基本的服務(wù)治理能力,Thrift 很多時(shí)候并無(wú)法做到開箱即用,在早期小米電商的基礎(chǔ)架構(gòu)團(tuán)隊(duì)就對(duì) Thrift 做了定制化的二次開發(fā),在生成的樁代碼中加入了服務(wù)發(fā)現(xiàn)、打點(diǎn)等功能,這些代碼再與自研的開發(fā)框架 koala 耦合來實(shí)現(xiàn)服務(wù)的閉環(huán)調(diào)用。而這些框架代碼以及生成的樁代碼,與業(yè)務(wù)代碼也并沒有明顯的隔離與區(qū)分,甚至業(yè)務(wù)能夠直接修改框架代碼以及樁代碼,實(shí)際上埋下了較大的隱患,也造成后續(xù)升級(jí)困難、嚴(yán)重阻塞等問題。而 service mesh 則可以完美的解決像這樣的痛點(diǎn),通過對(duì)這些能力的下沉,他們將對(duì)業(yè)務(wù)服務(wù)屏蔽實(shí)現(xiàn)細(xì)節(jié),業(yè)務(wù)服務(wù)也就不再需要關(guān)心包括服務(wù)發(fā)現(xiàn)、負(fù)載均衡、流量調(diào)度、限流降級(jí)熔斷、監(jiān)控統(tǒng)計(jì)等一切細(xì)節(jié)。2、語(yǔ)言無(wú)關(guān)的通信和鏈路治理實(shí)際上 service mesh 在功能上并沒有提供對(duì)于服務(wù)治理的任何新的特性和能力,它所能夠提供的能力在 service mesh 之前其實(shí)都能夠找到。service mesh 改變的是通信和服務(wù)治理能力的提供方式,它將這些能力從業(yè)務(wù)層面解耦,下沉到基礎(chǔ)設(shè)施中,以更加標(biāo)準(zhǔn)化和通用的方式來提供,這樣一來它便能屏蔽不同語(yǔ)言、不同平臺(tái)的差異性,在多語(yǔ)言、多技術(shù)棧的團(tuán)隊(duì)環(huán)境中,它能夠提供膠水般的融合與協(xié)同能力。這也是我們上面小米電商微服務(wù)調(diào)用架構(gòu)圖中 sidecar 所做到的,為跨語(yǔ)言的調(diào)用提供了解決方案。
3、通信和服務(wù)治理的標(biāo)準(zhǔn)化通過標(biāo)準(zhǔn)化,帶來一致的服務(wù)治理體驗(yàn),減少多業(yè)務(wù)之間由于服務(wù)治理標(biāo)準(zhǔn)不一致帶來的溝通和轉(zhuǎn)換成本,提高全局服務(wù)治理的效率。鑒于以上 service mesh 帶來的好處,小米電商微服務(wù)的架構(gòu)在未來會(huì)進(jìn)一步在已有基礎(chǔ)上更多的調(diào)研、參考以及參與該技術(shù)落地。但是,硬幣總有正反面,service mesh 也絕不是僅有優(yōu)點(diǎn)的萬(wàn)能膏藥。實(shí)際上,引入多一層的組件代理轉(zhuǎn)發(fā)請(qǐng)求,本身就不可避免地帶來更多的資源消耗,在一定程度上會(huì)降低系統(tǒng)的通信性能。其次,基礎(chǔ)功能與服務(wù)解耦有解耦的絕對(duì)優(yōu)勢(shì),但侵入式框架反而在支持業(yè)務(wù)的定制與擴(kuò)展能力上反而有先天優(yōu)勢(shì),這點(diǎn)在系統(tǒng)的設(shè)計(jì)中也應(yīng)當(dāng)考慮。第三,系統(tǒng)中對(duì)于組件的引入本身也帶來一定的風(fēng)險(xiǎn),業(yè)務(wù)將及其依賴 service mesh 的穩(wěn)定性,在保障 service mesh 的穩(wěn)定性上將帶來更多的技術(shù)考驗(yàn)。目前我們對(duì)于 service mesh 的用法實(shí)現(xiàn)設(shè)計(jì)如下圖所示,我們通過 Sidecar 的方式,將服務(wù)發(fā)現(xiàn)、負(fù)載均衡、集群策略、健康檢查以及部分的監(jiān)控打點(diǎn)等下沉到該組件中,該組件對(duì)于不同的服務(wù)部署方式部署方式稍有不同。例如對(duì)于早期的裸物理機(jī)部署的老服務(wù)來說,該組件與服務(wù)部署在同一臺(tái)物理機(jī),而對(duì)于例如 K8s 這樣的容器部署方式,只需要部署在同一個(gè) Pod ,即共享同一個(gè) ip 即可。Sidecar 中開放了一些 OpenAPI,部署在一起的服務(wù)只需要訪問 localhost 對(duì)應(yīng)端口的 OpenAPI 即可達(dá)到相應(yīng)的服務(wù)治理能力。未來小米新零售效能團(tuán)隊(duì)也將在大量的考量與取舍中,更進(jìn)一步地參與與適配該技術(shù)的落地,其中關(guān)鍵的一步也將會(huì)有對(duì)于 Apache Dubbo、Apache Dubbo-go 等底層框架的適配與融合,必要地情況下將進(jìn)行一些定制化的改造。
什么是 Serverless? Serverless(無(wú)服務(wù)器架構(gòu))指的是由開發(fā)者實(shí)現(xiàn)的服務(wù)端邏輯運(yùn)行在無(wú)狀態(tài)的計(jì)算容器中,它由事件觸發(fā), 完全被第三方管理,其業(yè)務(wù)層面的狀態(tài)則被開發(fā)者使用的數(shù)據(jù)庫(kù)和存儲(chǔ)資源所記錄。這也是當(dāng)下比較熱門的方向。Serverless 是云原生技術(shù)發(fā)展的高級(jí)階段,使開發(fā)者更聚焦在業(yè)務(wù)邏輯,而減少對(duì)基礎(chǔ)架構(gòu)的關(guān)注。它與我們之前說的 service mesh 實(shí)際上并不在同一理念上,service mesh 傾向于將基礎(chǔ)能力下沉,業(yè)務(wù)服務(wù)與代理一同部署。而 Serverless 則干脆希望開發(fā)者不再關(guān)注服務(wù)器,不再關(guān)注服務(wù)所需資源,這些資源與能力將由 Serverless 的廠商來提供。開發(fā)者只需要編寫業(yè)務(wù)函數(shù)即可(函數(shù)即服務(wù) FaaS)。相同的是,兩者的目的都是為了業(yè)務(wù)開發(fā)能夠僅專心于業(yè)務(wù)邏輯。目前我們小米新零售效能團(tuán)隊(duì)也正在嘗試對(duì)一些服務(wù)進(jìn)行 Serverless 化,并提供了一些基礎(chǔ)的能力。這些 Serverless 化的服務(wù)在開發(fā)中同樣不需要再關(guān)心底層的協(xié)議,無(wú)論是 Apache Dubbo、Apache Dubbo-go 都會(huì)在我們后端的 Serverless 系統(tǒng)中進(jìn)行兼容與適配,同樣以上的一些列服務(wù)治理的能力也將由 Serverless 系統(tǒng)全權(quán)托管。上圖就是我們目前對(duì)于服務(wù) Serverless 化的一個(gè)基本的支持邏輯,我們定義了成為 Serverless 服務(wù)的 Function 必須實(shí)現(xiàn)的接口 execute :public interface Handler { Result execute(Event var1, Context var2);
default void init(Object... objs) { }
default String version() { return "0.0.1"; }}
業(yè)務(wù)僅需要實(shí)現(xiàn)該接口,并通過平臺(tái)配置管理該服務(wù)的 git 庫(kù)等信息,就可以以 Serverless 的方式開始提供服務(wù),Serverless 系統(tǒng)將自動(dòng)拉取該 Function 的代碼信息,編譯打包等,提交到核心池中等待執(zhí)行。并且同時(shí),服務(wù)將無(wú)感知地接入系統(tǒng)提供的服務(wù)治理、可觀測(cè)性等能力。
Dubbo 作為一個(gè)老牌的、強(qiáng)大的微服務(wù)框架與體系,提供了跨語(yǔ)言的支持,這幫助我們將內(nèi)部不同的技術(shù)棧實(shí)際上形成了閉環(huán)。而 Apache Dubbo-go 作為 Apache Dubbo 生態(tài)中一個(gè)還在不斷迭代發(fā)展的開源項(xiàng)目,會(huì)存在一些待完善的小問題,但更能夠切實(shí)地幫助到我們搭建與發(fā)展整個(gè)云原生微服務(wù)體系。同樣的,我們?cè)谕晟苽鹘y(tǒng)的微服務(wù)體系架構(gòu)的同時(shí),我們也關(guān)注與嘗試目前微服務(wù)技術(shù)的一些發(fā)展方向,像 Serverless、service mesh 這些較為熱門的方向,我們也都將持續(xù)的跟進(jìn)與參與落地。我們將不斷與像?dubbogo 等開源社區(qū)合作,積極反饋我們使用的經(jīng)驗(yàn),參與完善,推動(dòng)更多此類開源項(xiàng)目的發(fā)展。?
關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。
對(duì)「服務(wù)端思維」有期待,請(qǐng)?jiān)谖哪c(diǎn)個(gè)在看
喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈