.Net微服务实战之技术选型篇
王者榮耀
去年我有幸被老領(lǐng)導(dǎo)邀請以系統(tǒng)架構(gòu)師的崗位帶技術(shù)團(tuán)隊(duì),并對公司項(xiàng)目以微服務(wù)進(jìn)行了實(shí)施。無論是技術(shù)團(tuán)隊(duì)還是技術(shù)架構(gòu)都是由我親自的從0到1的選型與招聘成型的,此過程讓我受益良多,因此也希望在接下來的系列博文盡可能的與大家分享我的經(jīng)驗(yàn)。
古人有云:將軍難打無兵之仗。想要把微服務(wù)很好的實(shí)施也并非能一個人可以完成的事,一來需要有出色的運(yùn)維提供支持,二來需要花時(shí)間做技術(shù)選型與攻關(guān),三來還要開發(fā)兄弟們配合實(shí)施。因此,這次能順利實(shí)施并不是一個人的王者,而是團(tuán)隊(duì)的榮耀。
框架源碼:https://github.com/SkyChenSky/Sikiro (文末有說明)
工欲善其事,必先利其器
以上是我們公司的技術(shù)棧(點(diǎn)擊圖片可在瀏覽器打開),除了統(tǒng)一配置中心沒有服務(wù)器資源和Hangfire還沒場景使用外,其他都已經(jīng)上線使用了。
俗話說得好:工欲善其事,必先利其器。一個優(yōu)秀的工程師應(yīng)該善于使用框架和工具,在微服務(wù)這一塊的技術(shù)棧選型并非一蹴而就,也是我多次對比驗(yàn)證后,并良好的集成到公司項(xiàng)目然后落地實(shí)施。這系列框架單純這么去用其實(shí)是可以無縫集成的,但是在落實(shí)項(xiàng)目的時(shí)候,我為了集成得更加友好和使用上更加便利,在基礎(chǔ)上做了擴(kuò)展,例如SkyWalking添加Request和Response,CAP與Chloe.ORM的集成等,下文我會逐個分享。
有需要的朋友可以參照我這套去實(shí)施,這樣大家就可以花更多的時(shí)間把精力放在業(yè)務(wù)、調(diào)優(yōu)、拆分、設(shè)計(jì)等方面。
此外大家看得出,我所有的技術(shù)棧基本上找的都是開源社區(qū)的比較出名的項(xiàng)目,沒有一個屬于自研的。這樣做的原因:
快速搭建
降低成本
社區(qū)支持維護(hù)
利于人才引進(jìn)
其實(shí)可以看出.Net不缺優(yōu)秀的開源項(xiàng)目,那么實(shí)施這么久讓我唯一覺得深刻的印象是:缺少整合。
之前我也跟不少同行討論過甚至在面試的時(shí)候,他們覺得應(yīng)該自己造一個輪子,原因各種各樣,但唯獨(dú)缺少了希望在開源項(xiàng)目基礎(chǔ)上完善下這個原因。我也理解他們的心理,因?yàn)椤皟?yōu)秀”的工程師應(yīng)該自己寫一套證明下自己。其實(shí)我認(rèn)為這也許是包容心的在作祟,我們應(yīng)當(dāng)求同存異,學(xué)會接受已經(jīng)檢驗(yàn)過的輪子,在基礎(chǔ)上完善您的需要,有必要還可以給社區(qū)做貢獻(xiàn),雙贏。
原則
我做技術(shù)選型的時(shí)候,堅(jiān)持著三大原則,簡單、適合、運(yùn)維優(yōu)先。
在滿足需求的情況下,優(yōu)先選擇輕量級的框架,因?yàn)檩p量級總比重量級的易學(xué)習(xí),易于擴(kuò)展,易于理解源碼。試想一下,有個框架什么都很齊全,但是學(xué)習(xí)曲線高,在寫一個demo的時(shí)候各種踩“坑”找原因,還有可能出了問題不知道怎么解決,除了開始你初認(rèn)識該框架覺得他很厲害之外,后面使用每走一步都是阻礙和吐槽。
在有限的資源、人力、時(shí)間,我們更新技術(shù)的同時(shí)還要保證業(yè)務(wù)的正常開展,我會優(yōu)先選擇我比較熟悉的技術(shù),我會將他們進(jìn)行封裝、優(yōu)化、集成,盡可能的減少開發(fā)人員對技術(shù)細(xì)節(jié)的認(rèn)知負(fù)擔(dān),盡可能以他們最熟悉的使用方式提供。此外,我們團(tuán)隊(duì)是有運(yùn)維崗,如果問題由運(yùn)維解決更快、更方便則優(yōu)先交給運(yùn)維,盡可能讓開發(fā)關(guān)注數(shù)據(jù)流轉(zhuǎn)與業(yè)務(wù)流程。
PS:我選型的時(shí)候不是一蹴而就的,下文可能我會提到某些框架工具我沒有去選擇原因,并不是否認(rèn)它們存在的價(jià)值,而絕大問題是這些不適用于我們團(tuán)隊(duì)。最后我向偉大的開源項(xiàng)目與其作者致敬。
微服務(wù)
?
有一條盛傳于我們行業(yè)的公式:軟件 = 程序 + 軟件工程。
程序就是我們經(jīng)常產(chǎn)出的算法、數(shù)據(jù)結(jié)構(gòu)、腳本、框架、架構(gòu)等。
為什么稱之為軟件工程?因?yàn)檫@是具有科學(xué)方法論引導(dǎo)的、多人協(xié)作、有明確目標(biāo)、有階段性的。從以前瀑布開發(fā)再到10年前盛行的敏捷開發(fā)最后到最近幾年流行的DevOps,可見開發(fā)模式也隨著技術(shù)架構(gòu)更新也不停的演進(jìn)。我們團(tuán)隊(duì)選用了原型模式+DevOps模式來應(yīng)對我們的微服務(wù)架構(gòu)的開發(fā)。
書本的教條主義我就不多說了,我對微服務(wù)的理解分為微和服務(wù)。
微
如何微?微到什么程度?我借助兩樣?xùn)|西,合理的系統(tǒng)架構(gòu)分層與DDD思想,兩者分別管理架構(gòu)的縱向拆分與橫向拆分。
架構(gòu)分層,我采用了前后端分離+多層架構(gòu),自頂向下的依賴,各司其職。
DDD在最近幾年非常流行,然而這并非新的技術(shù),十幾年前就已經(jīng)它的出現(xiàn)了。隨著微服務(wù)盛行,DDD的劃分域的化繁為簡的思想與微服務(wù)的本質(zhì)-拆不謀而合,因此DDD也隨之熱門起來。
下面是我們的架構(gòu)圖,這個話題在下一篇重點(diǎn)再討論。
服務(wù)
我接下來用一段話描述一下服務(wù)化的需要。首先API網(wǎng)關(guān)作為我們請求流量的入口,隔離了外網(wǎng)與內(nèi)網(wǎng)的作用。接著開發(fā)人員得知道如何調(diào)用服務(wù),那么可以從注冊中心發(fā)現(xiàn)已注冊的服務(wù)的IP地址、端口的列表,這就是服務(wù)的注冊與發(fā)現(xiàn);接著我們需要知道服務(wù)下接口路徑、請求與響應(yīng)的格式,因此我們需要服務(wù)描述。滿足前面兩個條件后,我們就可以進(jìn)行調(diào)用服務(wù)了,因此我們需要RPC框架進(jìn)行服務(wù)通信。當(dāng)服務(wù)運(yùn)作后,我們需要服務(wù)監(jiān)控來監(jiān)控服務(wù)的運(yùn)行情況以此方便調(diào)優(yōu)。隨著服務(wù)拆分得越細(xì)、跨度越大,服務(wù)出問題的時(shí)候不容易定位,因此我們需要服務(wù)跟蹤進(jìn)行問題定位。
由上述可見組件主要包括以下6點(diǎn):
API網(wǎng)關(guān)
服務(wù)描述
服務(wù)注冊中心
RPC框架
服務(wù)監(jiān)控
分布式鏈路跟蹤
API網(wǎng)關(guān)
API網(wǎng)關(guān)主要起到了隔離內(nèi)外網(wǎng)、身份驗(yàn)證、路由、限流等作用。我用一個生活的例子搭地鐵比喻來描述下:過閘前我們需要經(jīng)過安檢保證客流的安全性,上下班高峰期還會排隊(duì)進(jìn)行限流,我們還可以通過看指示牌或者詢問工作人員了解到應(yīng)該往什么方向走,這就是路由。
我們團(tuán)隊(duì)選型了Kong和KongA作為我們的API網(wǎng)關(guān),Kong是一個在Nginx運(yùn)行的Lua應(yīng)用程序,由lua-nginx-module實(shí)現(xiàn)。Kong和OpenResty一起打包發(fā)行,其中已經(jīng)包含了lua-nginx-module。基本功能有路由、負(fù)載均衡、基本認(rèn)證、限流、跨域、日志等功能,其他功能例如jwt認(rèn)證可以通過插件進(jìn)行擴(kuò)展。
有人會問為什么不用Ocelot?回答這個問題之前,我首先聲明我尊敬Ocelot項(xiàng)目與其開發(fā)者。
1.易用性。需要二次開發(fā),雖然對.Net開發(fā)者來說能接受,但不利于運(yùn)維。
2.性能。社區(qū)很多測試數(shù)據(jù),據(jù)我了解就是kong 11K,Ocelot 3.5K,四舍五入3倍性能差,作為流量的入口,性能這塊我還是比較注重的。
3.可擴(kuò)展性,Kong很多功能可以通過插件式按需使用與開發(fā)。
?
服務(wù)描述
我們團(tuán)隊(duì)采用了Swagger,以此來銜接前后端開發(fā)的接口對接,省去了編寫接口文檔的成本,此外也支持接口調(diào)試,讓開發(fā)效率提高不少。我們的服務(wù)都是以HTTP協(xié)議提供,對外API用RESTful風(fēng)格,對內(nèi)統(tǒng)一以POST的RPC風(fēng)格提供。
服務(wù)注冊中心
服務(wù)注冊,服務(wù)在發(fā)布后自動把IP地址與端口注冊進(jìn)服務(wù)中心;服務(wù)發(fā)現(xiàn),通過調(diào)用服務(wù)中心的接口獲取到某服務(wù)IP地址與端口的列表。我們團(tuán)隊(duì)選用Consul+Consul Tamplate+nginx,Consul是基于GO語言開發(fā)的開源工具,主要面向分布式,服務(wù)化的系統(tǒng)提供服務(wù)注冊、服務(wù)發(fā)現(xiàn)和配置管理的功能。Consul的核心功能包括:服務(wù)注冊/發(fā)現(xiàn)、健康檢查、Key/Value存儲、多數(shù)據(jù)中心和分布式一致性保證等特性。
Consul作為服務(wù)注冊中心的存在,但是我們服務(wù)發(fā)現(xiàn)只能拿到IP列表,我們使用RPC調(diào)用時(shí)還是得做負(fù)載均衡算法,于是使用了Consul Tamplate把服務(wù)列表同步到nginx的配置,那么RPC框架就無需集成負(fù)載均衡算法經(jīng)過nginx路由。
開始選型我并沒有選擇Consul Tamplate,而是選擇了fabio的這個中間件。fabio是一個應(yīng)用于Consul的輕量級、零配置負(fù)載均衡路由器,開始用的時(shí)候部署起來很方便、很簡單。后來上了Skywalking分布式鏈路跟蹤系統(tǒng),只要經(jīng)過fabio路由的都無法把調(diào)用鏈串起來,雖然將就的用是沒什么問題,但是Skywalking的調(diào)用鏈日志無法很好的展示出來就會影響日后的問題排查。我當(dāng)時(shí)花了兩天時(shí)間研究與issue提問,并沒有很好的結(jié)果,所以最后另外選擇了Consul Tamplate+nginx。
服務(wù)通信
RPC框架主要三大核心,序列化、通信細(xì)節(jié)隱藏、代理。協(xié)議支持分TCP和HTTP,當(dāng)然還有兩者兼容+集成MQ的。我們選擇了WebApiClient做客戶端,服務(wù)端仍是.Net Core WebAPI,主要考慮到WebAPIClient的輕量、易用,而且和Skywalking、Consul集成方便。我當(dāng)時(shí)用的時(shí)候時(shí).Net Core 2.2版本,gRPC并沒有集成進(jìn)來。
此外我也選擇過ServiceStack,ServiceStack的技術(shù)棧很全,缺點(diǎn)是依賴得很深,當(dāng)時(shí)試用的時(shí)候,它所以依賴的一個底層包ServiceStack.Common的某個類與WebAPI沖突了,所以對于不熟悉該框架的我斷定存在依賴污染,無論我需要還是不需要都統(tǒng)統(tǒng)依賴進(jìn)來了,然而我只是希望要一個簡單的RPC框架。此外還需要破解。
Surging也作為我當(dāng)時(shí)選型的目標(biāo),開始也是我抱著最大希望的,因?yàn)槊枋龅煤芘1?#xff0c;什么都是全得。然而深入去用的時(shí)候,沒有一個完整的文檔,入門demo也不友好,說實(shí)話我駕馭不住只能放棄。
服務(wù)跟蹤
市面上的分布式鏈路跟蹤系統(tǒng)基本上都是根據(jù)谷歌的dapper論文實(shí)現(xiàn)的,基本上都分三大塊,UI、收集器、代理(探針),原理大概是把涉及的服務(wù)鏈路的RequestID串起來。
我們團(tuán)隊(duì)選擇了SkyWalking作為了項(xiàng)目的分布式鏈路跟蹤系統(tǒng),原因很簡單:易用,無侵入,集成良好。
實(shí)施到我們項(xiàng)目的時(shí)候我做了點(diǎn)擴(kuò)展,把Reqeust、Response、Header、異常給記錄了下來,并過濾了部分不需要記錄的路徑。
分布式事務(wù)
只要在分布式系統(tǒng),分布式事務(wù)必不可缺。
| 分類 | 理論 | 案例 | 中間件 |
| 強(qiáng)一致性 | ACID | 二階段提交 | msdtc |
| 最終一致性 | BASE | 本地消息表 | CAP |
?
本地消息表是eBay在N年前提出的方案,而CAP以該思想實(shí)現(xiàn)的一門框架,原理大概是,本地業(yè)務(wù)表與消息憑據(jù)表作為一個事務(wù)持久化,通過各種補(bǔ)償手段保證MQ消息的可靠性,包括MQ正常發(fā)布與消費(fèi)。
我花了多天的時(shí)間專門測試了該框架可靠性,的確有保證。然而有個地方我認(rèn)為可以優(yōu)化,Retry的查詢語句條件可以更加嚴(yán)謹(jǐn)點(diǎn),只需要負(fù)責(zé)相應(yīng)的Group進(jìn)行Retry就好,沒必要全部都查詢出來,因?yàn)檫@個問題我在測試環(huán)境與本地環(huán)境共同調(diào)試時(shí),剛好兩個環(huán)境的Group不一致,導(dǎo)致會Retry失敗的問題。
框架源碼
寫到這里,本篇的分享差不多要結(jié)束了,我將開源我們公司的工具庫,有需要的朋友可以去使用。
Sikiro.Tookits?-公共基礎(chǔ)庫
Sikiro.Nosql.Redis-StackExchange.Redis的基本封裝
Sikiro.Nosql.Mongo-mongodb驅(qū)動封裝更新、排序等支持lambda
Sikiro.MicroService.Extension-RPC注冊,微服務(wù)框架-服務(wù)注冊,終端跟蹤忽略
Sikiro.Chloe.Extension-支持多數(shù)據(jù)、事務(wù)封裝、分頁、IOC
Sikiro.Chloe.Cap-把Chloe,ORM與CAP整合
額外說明下DotNetCore.CAP.MySql,這個是我從CAP源碼拷貝過來然后改了MySql.Data的依賴,原本CAP.MySql是用的MySqlConnector,和我的Chloe.ORM沖突了。
總結(jié)
以上是生活随笔為你收集整理的.Net微服务实战之技术选型篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【项目升级】单库、多库、读写分离 · 任
- 下一篇: .NET Core开发实战(第32课:集