通过Dapr实现一个简单的基于.net的微服务电商系统
本來想在Dpar 1.0GA時(shí)發(fā)布這篇文章,由于其他事情耽擱了放到現(xiàn)在。時(shí)下微服務(wù)和云原生技術(shù)如何如荼,微軟也不甘示弱的和阿里一起適時(shí)推出了Dapr(https://dapr.io/),園子里關(guān)于dapr的文章不太多,所以今天就借這篇文章分享一下如何通過dapr跑起來一個(gè)簡易的電商系統(tǒng),讓大家通過這個(gè)系統(tǒng)來觀察dapr如何運(yùn)作的,權(quán)當(dāng)拋磚引玉。
?
首先第一個(gè)話題,什么是dapr?
要說dapr,首先我們得了解什么是服務(wù)網(wǎng)格,而要說服務(wù)網(wǎng)格還是得先講講微服務(wù)。微服務(wù)的概念相信現(xiàn)在大家已經(jīng)耳熟能詳了。在微服務(wù)體系中,開發(fā)者通過拆分設(shè)計(jì)不同的服務(wù),通過服務(wù)間協(xié)同作業(yè)的方式聚合業(yè)務(wù)實(shí)現(xiàn)相關(guān)的功能。
服務(wù)與服務(wù)之間涉及服務(wù)調(diào)用、事件傳播、狀態(tài)流轉(zhuǎn)等等概念,再細(xì)分相關(guān)功能會涉及到服務(wù)調(diào)用時(shí)限流、重試、降級,事件傳播時(shí)確保一致性,對整個(gè)服務(wù)系統(tǒng)的拓?fù)渥粉櫋⒈O(jiān)控等等功能。以java為例,一般是采用dubbo或者springcloud這樣的侵入性框架,通過開發(fā)人員手動(dòng)集成到項(xiàng)目里。并在外部搭建諸如zookeeper、eureka這樣的分布式協(xié)調(diào)器來實(shí)現(xiàn)服務(wù)的注冊、發(fā)現(xiàn)。通過網(wǎng)關(guān)如zuul、kong實(shí)現(xiàn)對外部對內(nèi)部服務(wù)的調(diào)用,通過feign ribbon hystrix這樣或那樣的組件實(shí)現(xiàn)服務(wù)間通訊時(shí)負(fù)載均衡、熔斷、限流、降級。通過設(shè)計(jì)eventbus來實(shí)現(xiàn)事件在服務(wù)間流轉(zhuǎn)。
說了這么一大堆,和服務(wù)網(wǎng)格有什么關(guān)系呢?服務(wù)網(wǎng)格本質(zhì)上就是微服務(wù)架構(gòu)在云原生基礎(chǔ)上對網(wǎng)絡(luò)通訊相關(guān)的功能做了解耦和下沉。讓運(yùn)行于云原生之上的應(yīng)用(一般呈現(xiàn)方式主要是容器)可以不再關(guān)心服務(wù)間通訊相關(guān)的一大堆技術(shù)實(shí)現(xiàn)。通過對每一個(gè)應(yīng)用附加一個(gè)獨(dú)立進(jìn)程的代理(也叫sidecar)實(shí)現(xiàn)。
?
這樣開發(fā)人員只關(guān)心應(yīng)用如何實(shí)現(xiàn)具體的業(yè)務(wù),而不用去關(guān)心具體的服務(wù)間治理,服務(wù)網(wǎng)格幫應(yīng)用完成服務(wù)注冊、發(fā)現(xiàn)、負(fù)載均衡、重試、限流等等相關(guān)功能。
所以dapr是什么就一目了然了,dapr就是服務(wù)網(wǎng)格的一種實(shí)現(xiàn)方式。只不過相比傳統(tǒng)的服務(wù)網(wǎng)格關(guān)注的可能是流量治理來講dapr更關(guān)注服務(wù)間狀態(tài)變化,用官方的原話來講“Dapr 是一個(gè)可移植的、事件驅(qū)動(dòng)的運(yùn)行時(shí),它使任何開發(fā)人員能夠輕松構(gòu)建出彈性的、無狀態(tài)和有狀態(tài)的應(yīng)用程序,并可運(yùn)行在云平臺或邊緣計(jì)算中,它同時(shí)也支持多種編程語言和開發(fā)框架。”
?
什么是事件驅(qū)動(dòng)?
什么是事件驅(qū)動(dòng)?我們知道在一個(gè)分布式系統(tǒng)里,當(dāng)某個(gè)服務(wù)需要其他服務(wù)協(xié)同作業(yè)時(shí),有兩種辦法,一種就是通過強(qiáng)一致性的方式調(diào)用,比如RPC call或者restapi。這種方式有一個(gè)弊端,就是必須確保下游服務(wù)必須可用,否則可能會導(dǎo)致同步調(diào)用時(shí)調(diào)用過程超時(shí)、或者下游服務(wù)不響應(yīng)導(dǎo)致的失敗。
在分布式系統(tǒng)里由于網(wǎng)絡(luò)IO不可靠等等因素,我們往往很難100%確保同步調(diào)用能夠?qū)⒁粋€(gè)業(yè)務(wù)在多個(gè)服務(wù)間協(xié)同完成,所以一般會采用訂閱-發(fā)布的方式。也就是大家比較熟悉的事件總線這樣的異步模型,通過將我們的請求以發(fā)布事件的方式灌入消息隊(duì)列后不等待立即返回,通過訂閱方訂閱消息完成后續(xù)操作,若需要回滾同樣發(fā)布事件,由發(fā)送方訂閱失敗消息進(jìn)行補(bǔ)償操作即可。
通過這樣的方式我們可以構(gòu)建一個(gè)以事件來驅(qū)動(dòng)的異步的,最終一致性的響應(yīng)式系統(tǒng)。而dapr則是將事件驅(qū)動(dòng)在云原生層面發(fā)揚(yáng)光大,通過對不同中間件的集成屏蔽了構(gòu)建事件驅(qū)動(dòng)架構(gòu)的各種復(fù)雜性,讓開發(fā)人員幾乎不寫或者少寫代碼的情況下完成一個(gè)事件驅(qū)動(dòng)架構(gòu)的分布式系統(tǒng)。
?
Dapr如何助力微服務(wù)設(shè)計(jì)落地的?
Dapr提供了哪些功能來助力我們微服務(wù)落地呢?可以從上圖看到有7,8種功能,我們從左至右一個(gè)一個(gè)來講。
?
第一個(gè)就是服務(wù)間調(diào)用,也就是常見的同步調(diào)用。dapr在服務(wù)間調(diào)用封裝了服務(wù)注冊發(fā)現(xiàn)、ssl、自動(dòng)重試、熔斷、限流(需單獨(dú)配置支撐)。一般當(dāng)應(yīng)用請求下游服務(wù)時(shí)daprd會發(fā)起一個(gè)https請求、若超時(shí)會重試數(shù)次,若下游服務(wù)下線不可用則會返回一個(gè)友好的json格式的50x供上游服務(wù)做異常冗余處理。
第二個(gè)是狀態(tài)管理,提供了對于存儲鍵/值對的狀態(tài)管理,同時(shí)對大部分主流的狀態(tài)存儲中間件進(jìn)行了支持,而無需開發(fā)者去對特定中間件做相應(yīng)的sdk集成。
第三個(gè)是訂閱發(fā)布,通過該api可以輕松實(shí)現(xiàn)一個(gè)異構(gòu)的語言無關(guān)的事件總線,同時(shí)和狀態(tài)管理一樣,它的訂閱發(fā)布中間件是可插拔的。
第四個(gè)是資源綁定,帶觸發(fā)器的資源綁定通過接收和發(fā)送事件到任何外部源(如數(shù)據(jù)庫、隊(duì)列、文件系統(tǒng)等)來進(jìn)一步構(gòu)建事件驅(qū)動(dòng)架構(gòu),以實(shí)現(xiàn)擴(kuò)展性和彈性,此特性有一點(diǎn)Serverless的思想。
第五個(gè)是大名鼎鼎的actor模型,很多沒接觸過actor的同學(xué)可能會一頭霧水的問actor模型是什么呢?簡單來講就是一個(gè)分布式的并發(fā)的無鎖線程同步對象。舉一個(gè)簡單的例子它可以解決在并發(fā)下商品超賣的問題,假設(shè)我們有一個(gè)api可以通過訪問來扣商品庫存,在無鎖無事務(wù)的情況下,由于讀寫數(shù)據(jù)庫時(shí)間差的問題,一定會導(dǎo)致商品超賣,即便是我們將商品庫存放在對象上通過內(nèi)存保存,如果不引入原子操作,也一樣會有線程同步導(dǎo)致的數(shù)據(jù)不一致問題,而actor則可以在不引入任何內(nèi)部或外部api/sdk的情況下實(shí)現(xiàn)多線程訪問下數(shù)據(jù)的完全一致性。簡單來講就是每一個(gè)actor是通過對mailbox隊(duì)列來阻塞消費(fèi)實(shí)現(xiàn)多線程訪問下數(shù)據(jù)一致性的,具體大家可以多了解一下這個(gè)模型。而Dapr 在其 actor 運(yùn)行時(shí)提供了很多能力,包括并發(fā),狀態(tài)管理,用于 actor 激活/停用的生命周期管理,以及喚醒 actor 的計(jì)時(shí)器和提醒器。
第六個(gè)是可觀測性,dapr通過一些三方組件提供了諸如鏈路追蹤和應(yīng)用監(jiān)控等等相關(guān)觀測手段來方便開發(fā)人員更加直觀的定位網(wǎng)絡(luò)問題等等。
第七個(gè)是安全性,默認(rèn)dapr之間調(diào)用不管是同步調(diào)用還是actor調(diào)用或者訂閱發(fā)布,均會通過雙向https的方式加密通訊,避免明文傳遞消息。
最后一個(gè)是豐富的擴(kuò)展組件,熟悉dapr的開發(fā)者可以自定義各種組件通過中間件的方式插入到sidecar的pipline中去實(shí)現(xiàn)自定義功能的擴(kuò)展。
另外需要關(guān)注的是dapr對上層應(yīng)用提供了兩種請求模式,一種是http api一種是grpc api,通過這種語言無關(guān)的方式我們可以輕易的在不同語言之間通過dapr搭建起一個(gè)異構(gòu)的分布式系統(tǒng)而不用關(guān)心不同語言之間的差異。
?
Dapr與其他服務(wù)網(wǎng)格的區(qū)別
目前市場上的服務(wù)網(wǎng)格框架基本都被諸如linkerd、istio這樣的老牌服務(wù)網(wǎng)格占據(jù)。這些服務(wù)網(wǎng)格的關(guān)注點(diǎn)和dapr有一定區(qū)別。如果非要說相同或者相似點(diǎn)的話那就是他們的架構(gòu)都是由數(shù)據(jù)平面和控制平面組成,其中數(shù)據(jù)平面主要是由集群內(nèi)的各種sidecar組成,而控制平面就是調(diào)度中心。另外一個(gè)相同點(diǎn)就是他們都實(shí)現(xiàn)了對應(yīng)用程序的代碼無侵入性(dapr提供了簡單的sdk,只是對dapr api的簡易封裝,不是必選項(xiàng)),但是從功能層面來講,兩者的關(guān)注點(diǎn)則完全不一樣了,例如service mesh霸主istio他提供了對流量切分、流量鏡像、監(jiān)控、智能路由、故障注入,自動(dòng)化的度量指標(biāo)、日志以及追蹤等等功能,可以看到它更關(guān)心流量代理這部分邏輯。而dapr在這部分目前來講還稍弱,但是dapr提供了其他服務(wù)網(wǎng)格幾乎沒有關(guān)心的狀態(tài)服務(wù)、事件、actor模型等等功能,兩者可以說是互補(bǔ)的(dapr是可以和istio這樣的服務(wù)網(wǎng)格集成工作的,未來可期)
?
更多了解dapr
訪問https://dapr.io了解更多
?
talk is cheap, show me the code!
說了那么多概念,最終還是需要落地到具體的系統(tǒng)設(shè)計(jì)上,我們就從這個(gè)電商系統(tǒng)開始吧。
技術(shù)概要、設(shè)計(jì)規(guī)范
整個(gè)電商系統(tǒng)分為兩個(gè)具體的repo
https://github.com/sd797994/Oxygen-Dapr?
該repo是針對Dapr通訊相關(guān)的API統(tǒng)一了編程模型封裝實(shí)現(xiàn)的一個(gè)rpc框架,類似于dapr提供的.net SDK,該repo我已經(jīng)將打包到了nuget,所以電商系統(tǒng)不需要依賴該repo的源代碼,有興趣的朋友可以copy下來,可以的話請star一下。該框架基于.net5
https://github.com/sd797994/Oxygen-Dapr.EshopSample
該repo為本次演示電商系統(tǒng)源代碼,其結(jié)構(gòu)如下:
?
Depoly主要是一些yaml和bat方便讀者朋友通過k8s快速啟動(dòng)之用。
Public包含一些領(lǐng)域業(yè)務(wù)的抽象(DomainBase)和工具層(InfrastructureBase)以及RPC的接口層(Remote-IApplicationService)以及前端(WebPage-www)及后端(WebPage-Admin)頁面
Services文件夾包含后端的微服務(wù),分為賬戶服務(wù)、商品服務(wù)、商城公共服務(wù)以及交易服務(wù),另外包含兩個(gè)通用支撐服務(wù):圖片服務(wù)以及作業(yè)服務(wù)。
業(yè)務(wù)微服務(wù)類主要是以清潔架構(gòu)分層,清潔架構(gòu)是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的一個(gè)概念:
?
整個(gè)代碼結(jié)構(gòu)是以Domain為核心,外部依次是應(yīng)用層、基礎(chǔ)設(shè)施,是一個(gè)從內(nèi)及外的設(shè)計(jì)。
Domain包含了整個(gè)服務(wù)所需的具體的業(yè)務(wù)聚合,Domain的核心數(shù)聚合,包含聚合根、實(shí)體以及值對象,剩余部分則是圍繞聚合形成的規(guī)約、DTO、領(lǐng)域服務(wù)、倉儲抽象等等。
應(yīng)用層通過讀寫分離的方式來實(shí)現(xiàn)對領(lǐng)域?qū)拥牟僮骱蛯Σ樵儤I(yè)務(wù)的操作,另外包含事件訂閱器用于接收其他應(yīng)用發(fā)起的領(lǐng)域事件。其結(jié)構(gòu)如下:
用例(UseCaseService)類型的應(yīng)用服務(wù)主要作用就是聚合操作當(dāng)前服務(wù)的領(lǐng)域,同時(shí)調(diào)用基礎(chǔ)設(shè)施層實(shí)現(xiàn)持久化以及事務(wù),同時(shí)可以發(fā)送領(lǐng)域事件亦或是調(diào)用遠(yuǎn)程RPC。
查詢(QueryService)類型的應(yīng)用服務(wù)主要是對各種客戶端發(fā)起的業(yè)務(wù)指令調(diào)用基礎(chǔ)設(shè)施層的ORM或es或者dapr的statemanager或者遠(yuǎn)程RPC進(jìn)行具體的操作查詢。
事件訂閱器(EventHandler)類型的應(yīng)用服務(wù)主要是接收事件并進(jìn)行業(yè)務(wù)操作,其操作邏輯和用例類似。
基礎(chǔ)設(shè)施層則包含了對上層的一系列支撐,包括各種通用組件、工具、ORM、持久化實(shí)體、倉儲實(shí)現(xiàn)等等,其中用到的外部持久化設(shè)備有postgres、elasticsearch以及redis,所有的業(yè)務(wù)表存儲主要依賴于postgres,elasticsearch主要是包含移動(dòng)端的商品列表查詢,redis則主要是對dapr以及作業(yè)系統(tǒng)的持久化支撐。此處不再贅述。
Host作為服務(wù)啟動(dòng)的入口,主要是啟動(dòng)通用主機(jī)注入依賴注入框架,注入Oxygen框架初始化各種配置、AOP、鑒權(quán)服務(wù)等等來啟動(dòng)RPC服務(wù)。不再贅述
?
部署網(wǎng)絡(luò)拓?fù)鋱D
Tips:如何部署可以參考repo的readme.md
整個(gè)系統(tǒng)前、后端以及各種通用服務(wù)都是以容器化的方式運(yùn)行在k8s之上的。其中在最前端是k8s的ingress-controller,由于這個(gè)場景相對比較簡單,不需要各種復(fù)雜的流量切分邏輯,所以我目前選型的是k8s官方推薦的nginx。當(dāng)請求從客戶端發(fā)起的時(shí)候,流量最先流入ingress-controller,通過已配置好的ingress規(guī)則會再次發(fā)送到各個(gè)k8s service再流入具體的pod進(jìn)行作業(yè)。
其中對www.dapreshop.com的訪問會直接請求到后端頁面pod、對m.dapreshop.com的訪問會請求到移動(dòng)端頁面pod,這兩個(gè)頁面上發(fā)起的api.dapreshop.com則會統(tǒng)一先流入到一個(gè)叫apigateway的pod上,該pod附加了一個(gè)dapr的sidecar,該pod只是一個(gè)包含路由重寫規(guī)則的nginx,它的作用是將源地址請求重新組裝為dapr可識別的api地址并調(diào)用sidecar,這樣通過sidecar和內(nèi)網(wǎng)的其他掛載了sidecar的各種子服務(wù)進(jìn)行相應(yīng)的互操作。
?
如何運(yùn)行它?
Tips:如何運(yùn)行可以參考repo的readme.md
通過kubectl查詢兩個(gè)命名空間看到如下情況則代碼系統(tǒng)已經(jīng)完全啟動(dòng)完畢。
?
這個(gè)時(shí)候訪問admin.dapreshop.com會進(jìn)入該頁面:
?
當(dāng)初始化后會自動(dòng)創(chuàng)建一個(gè)管理員、一個(gè)用于模擬下單的用戶以及相關(guān)的權(quán)限、角色。
?
?
同時(shí)會自動(dòng)創(chuàng)建商城的基礎(chǔ)設(shè)置、商品分類、商品,以及隨機(jī)創(chuàng)建幾個(gè)商品的折扣活動(dòng)。
?
?
?
此時(shí)訪問m.dapreshop.com就能看到一個(gè)包含商品的下單頁面了
?
隨意選擇幾個(gè)商品,選擇結(jié)算后,后端即可創(chuàng)建一個(gè)訂單,后臺就可以模擬訂單的剩余流程、注意該訂單會在5分鐘內(nèi)被作業(yè)系統(tǒng)取消,庫存會回滾。
?
觀察
當(dāng)我們在前后端做了各種操作后,登錄zipkin.dapreshop.com即可觀察到流量的變化
?
可以觀察到相應(yīng)的請求和鏈路細(xì)節(jié)
?
以前端下訂單為例:
?
流量通過網(wǎng)關(guān)路由到交易服務(wù),交易服務(wù)會調(diào)用賬戶服務(wù)獲取一個(gè)mock account、然后會調(diào)用商品RPC查詢商品基礎(chǔ)信息,接下來調(diào)用商品Actor對象做具體的庫存減扣,最后發(fā)布事件,同時(shí)交易服務(wù)的交易記錄訂閱器和作業(yè)訂閱器會訂閱該事件做后續(xù)相關(guān)操作。由于所有的請求都通過daprd這個(gè)sidecar完成,所以所有的請求和流量都能通過zipkin直觀的觀察到。
?
最后我們可以在daprcli中通過dapr dashborad -k 來觀測dapr目前控制平面的基本情況,此部分就不贅述了,大家可以登錄dapr的官網(wǎng)多了解
?
?
?
以上就是本次關(guān)于dapr如何落地一個(gè)電商demo的入門級的相關(guān)分享,Dapr本身包含了太多的內(nèi)容由于時(shí)間關(guān)系無法一一呈現(xiàn)還需要讀者朋友們在實(shí)際使用中去挖掘,如果喜歡的話請給repo一個(gè)star,歡迎轉(zhuǎn)發(fā)fork~
相關(guān)文章:
Dapr能否引領(lǐng)云原生中間件的未來?
云原生 | 阿里巴巴的Dapr實(shí)踐與探索
Dapr 可視化指南
Dapr 知多少 | 分布式應(yīng)用運(yùn)行時(shí)
Dapr 正式發(fā)布 1.0
Dapr 交通流量控制示例
Dapr是如何簡化微服務(wù)的開發(fā)和部署
微軟開源微服務(wù)運(yùn)行時(shí)Dapr,賦能云原生應(yīng)用開發(fā)
Dapr微服務(wù)應(yīng)用開發(fā)系列0:概述
Dapr微服務(wù)應(yīng)用開發(fā)系列1:環(huán)境配置
Dapr微服務(wù)應(yīng)用開發(fā)系列2:Hello World與SDK初接觸
Dapr微服務(wù)應(yīng)用開發(fā)系列3:服務(wù)調(diào)用構(gòu)件塊
Dapr微服務(wù)應(yīng)用開發(fā)系列4:狀態(tài)管理構(gòu)件塊
Dapr微服務(wù)應(yīng)用開發(fā)系列5:發(fā)布訂閱構(gòu)建塊
Windows環(huán)境下Dapr入門
總結(jié)
以上是生活随笔為你收集整理的通过Dapr实现一个简单的基于.net的微服务电商系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网关Ocelot功能演示安排的明明白白~
- 下一篇: 如何在 .NET 程序万种死法中有效的生