聲動(dòng)派干貨:微服務(wù)架構(gòu)實(shí)踐經(jīng)驗(yàn)分享

作者介紹

伍欣? 廈門聲連網(wǎng)信息科技有限公司 技術(shù)副總監(jiān)

你將看到

1、微服務(wù)的特性,微服務(wù)實(shí)施的要求、復(fù)雜程度以及相應(yīng)的挑戰(zhàn);

2、企業(yè)如何衡量是否應(yīng)該使用微服務(wù)架構(gòu);

3、微服務(wù)對(duì)運(yùn)維的要求;

4、開發(fā)微服務(wù)選擇框架要考慮的因素;

5、我司最佳實(shí)踐案例分享

本文大概:5200字 ??閱讀需要:8分鐘

一、什么是微服務(wù)?

微服務(wù) (Microservices) 是一種軟件架構(gòu)風(fēng)格,它是以專注于單一責(zé)任與功能的小型功能區(qū)塊 (Small Building Blocks) 為基礎(chǔ),利用模組化的方式組合出復(fù)雜的大型應(yīng)用程序,各功能區(qū)塊使用與語(yǔ)言無(wú)關(guān) (Language-Independent/Language agnostic) 的 API 集相互通訊。微服務(wù)架構(gòu)運(yùn)用于軟件架構(gòu)風(fēng)格的其中一項(xiàng)概念是甘露運(yùn)算 (Dew Computing),意指由許多的小露水 (代表微服務(wù)的功能元件) 匯集而成的運(yùn)算能力。

——摘自《維基百科》,微服務(wù)

2014年,Martin Fowler 與 James Lewis 共同提出了微服務(wù)的概念,定義了微服務(wù)是由以單一應(yīng)用程序構(gòu)成的小服務(wù),自己擁有自己的進(jìn)程與輕量化處理,服務(wù)依業(yè)務(wù)功能設(shè)計(jì),以全自動(dòng)的方式部署,與其他服務(wù)使用 HTTP API 通訊。同時(shí)服務(wù)會(huì)使用最小的規(guī)模的集中管理能力,服務(wù)可以用不同的編程語(yǔ)言與數(shù)據(jù)庫(kù)等元件實(shí)作。

微服務(wù)架構(gòu)的幾個(gè)特征

1. 通過服務(wù)組件化

使用服務(wù)作為組件而不是使用庫(kù)的原因主要有兩方面:首先,服務(wù)是可獨(dú)立部署的,其次,能有更加明確的組件接口。服務(wù)通過明確的遠(yuǎn)程調(diào)用機(jī)制可以避免組件間的緊耦合。

但服務(wù)組件化也有一些缺點(diǎn)是我們需要提前注意到的:遠(yuǎn)程調(diào)用比進(jìn)程內(nèi)調(diào)用更昂貴;遠(yuǎn)程API被設(shè)計(jì)成粗粒度,不便于使用。

2.圍繞業(yè)務(wù)能力組織

對(duì)照單體架構(gòu)和微服務(wù)架構(gòu)我們可以看到——單體架構(gòu)中最常用的形式是三層架構(gòu),這樣的架構(gòu)下,人員按照層次進(jìn)行組織。但在微服務(wù)架構(gòu)當(dāng)中,我們以業(yè)務(wù)(或者是微服務(wù))為單位進(jìn)行人員的組織,這樣一來(lái)團(tuán)隊(duì)就是跨職能的,模塊是通過業(yè)務(wù)能力進(jìn)行組織和管理的。

這樣的效果是在某個(gè)業(yè)務(wù)領(lǐng)域里面會(huì)有UI專家、業(yè)務(wù)專家、技術(shù)專家。當(dāng)然在小公司里,這些人員是可以復(fù)用的,但不是很推薦這么做,因?yàn)榇蠹叶贾廊绻粋€(gè)人做多任務(wù),其實(shí)工作效率是相對(duì)較低的,就像一個(gè)cpu需要做多個(gè)線程當(dāng)中切換,成本是很大的,所以在人員充足的情況下,盡量把每個(gè)子模塊的人員固定下來(lái)。

3.去中心化治理

集中治理的一個(gè)后果是技術(shù)平臺(tái)的單一標(biāo)準(zhǔn)化發(fā)展趨勢(shì)。

把單體的組件分裂成服務(wù),在構(gòu)建這些服務(wù)時(shí)可以有自己的選擇,例如使用其他的語(yǔ)言進(jìn)行開發(fā)(這也是使用HTTP API作為微服務(wù)之間通信方式的一個(gè)原因),還可以利用其它的web容器或者容器化技術(shù)進(jìn)行部署。

在集中治理中,一個(gè)單體應(yīng)用只能使用一種開發(fā)語(yǔ)言,最后的后果是技術(shù)平臺(tái)的單一標(biāo)準(zhǔn)化發(fā)展。比如你選擇了java作為開發(fā)語(yǔ)言開發(fā)單體項(xiàng)目,那么這個(gè)項(xiàng)目就只能用能運(yùn)行在jvm的語(yǔ)言進(jìn)行開發(fā)了。

相反,如果去中心化進(jìn)行單體組件的開發(fā),之間通過http webservice進(jìn)行通信,那么只要是支持http webservice開發(fā)的語(yǔ)言都可以用,比如我們就目前有一些微服務(wù)就在使用golang進(jìn)行開發(fā),這使得我們的工程師不會(huì)因?yàn)檎Z(yǔ)言的局限性限制解決方案的實(shí)現(xiàn)方法。

微服務(wù)更傾向于讓每個(gè)服務(wù)管理自己的數(shù)據(jù)庫(kù),或者同一數(shù)據(jù)庫(kù)技術(shù)的不同實(shí)例,或完全不同的數(shù)據(jù)庫(kù)系統(tǒng)。

在微服務(wù)體系中,想要在其他的子模塊寫入數(shù)據(jù),需要通過調(diào)用服務(wù)API的方式,而不應(yīng)該直接訪問服務(wù)的數(shù)據(jù)庫(kù)。

4. 基礎(chǔ)設(shè)施自動(dòng)化

基于持續(xù)集成(CI)和持續(xù)部署(CD)進(jìn)行自動(dòng)部署上線。在一個(gè)大型系統(tǒng)中微服務(wù)的數(shù)量會(huì)非常多,如果靠運(yùn)維人員手工進(jìn)行部署工作量十分大,也不方便管理。在這樣的場(chǎng)景下如果不使用CI和CD進(jìn)行自動(dòng)化的作業(yè),那么效率會(huì)變得很低。

5. 為失敗設(shè)計(jì)

其實(shí)這是所有分布式系統(tǒng)的特征。

使用服務(wù)作為組件的一個(gè)后果:應(yīng)用程序需要被設(shè)計(jì)成能夠容忍服務(wù)失效。任何服務(wù)調(diào)用都可能因?yàn)榉?wù)提供者不可用而失敗,客戶端必須盡可能優(yōu)雅的應(yīng)對(duì)這種失敗。

與單體應(yīng)用設(shè)計(jì)相比這是一個(gè)劣勢(shì),因?yàn)樗腩~外的復(fù)雜度。單體架構(gòu)下,如果應(yīng)用down掉了,那么整個(gè)應(yīng)用或單個(gè)實(shí)例就停止了工作。如果使用微服務(wù)架構(gòu),組件之間的調(diào)用通過網(wǎng)絡(luò)進(jìn)行,這樣引入了更多的不確定性,網(wǎng)絡(luò)的延遲、網(wǎng)絡(luò)的抖動(dòng)(瞬斷)等等都可能導(dǎo)致API調(diào)用的失敗。因此,微服務(wù)必須快速檢測(cè)故障并自動(dòng)恢復(fù)服務(wù)(自愈)。

微服務(wù)希望看到為每個(gè)單獨(dú)的服務(wù)設(shè)置的完善的監(jiān)控和日志記:

1、控制面板上顯示運(yùn)行(up)/關(guān)閉(down)狀態(tài)

2、各種各樣的運(yùn)營(yíng)和業(yè)務(wù)相關(guān)指標(biāo)

3、斷路器狀態(tài)

4、當(dāng)前吞吐量和時(shí)延

所以有一種說(shuō)法,使用微服務(wù)的前提是你具備了良好的運(yùn)維能力,因?yàn)樾枰ㄙM(fèi)大量的時(shí)間做基礎(chǔ)設(shè)施的建設(shè)。這其中包括、日志的分布式收集、調(diào)用鏈的跟蹤、指標(biāo)的監(jiān)控、告警等等。


二、企業(yè)該怎么權(quán)衡是否應(yīng)該使用微服務(wù)?

在以下幾種情況下,企業(yè)使用微服務(wù)是一個(gè)合理的選擇——

1、系統(tǒng)已經(jīng)足夠的龐大,單體架構(gòu)難以維護(hù)、機(jī)器資源浪費(fèi)

2、人力充足、可按業(yè)務(wù)進(jìn)行組織

3、了解并掌握開發(fā)微服務(wù)的框架

4、能夠容許若干迭代的失敗

5、有比較成熟的分布式系統(tǒng)運(yùn)維經(jīng)驗(yàn)

第2點(diǎn)中的人力充足其實(shí)也并不是絕對(duì)的,我相信在一些已經(jīng)應(yīng)用微服務(wù)的公司(包括我們)中,人員也不是絕對(duì)地按照業(yè)務(wù)進(jìn)行劃分,但是的確是一個(gè)人或少數(shù)人負(fù)責(zé)一個(gè)微服務(wù)的開發(fā)和維護(hù)。

這就要求工程師的水平比較高,推薦的一種方式是先成功在一個(gè)或兩個(gè)模塊徹底執(zhí)行微服務(wù)的改造,然后把這一兩個(gè)模塊當(dāng)成樣板工程。

當(dāng)然要把這個(gè)樣板工程弄好的話,還有很多的前置工作,例如規(guī)范的制定,自動(dòng)化測(cè)試、集成測(cè)試要怎么做?容錯(cuò)、熔斷要怎么做?錯(cuò)誤處理要怎么做等等。這些都是需要提前考慮的。

第4點(diǎn),能夠容許若干迭代的失敗,為什么這么說(shuō)呢?

其實(shí)就算理論掌握得再好,最后在執(zhí)行起來(lái)總會(huì)有些東西考慮不全面,尤其是之前說(shuō)到的容錯(cuò)(Design for failure)部分尤其要花很多時(shí)間去考慮和設(shè)計(jì)。

第5點(diǎn)是比較重要的一點(diǎn),前面我們說(shuō)到在微服務(wù)當(dāng)中,很多環(huán)節(jié)可能會(huì)失敗,所以我們得對(duì)這些情況了如指掌才能避免問題的發(fā)生。

因此,我們?cè)跇?gòu)建微服務(wù)模塊的時(shí)候,除了要監(jiān)控CPU、內(nèi)存、磁盤IO、網(wǎng)絡(luò)等指標(biāo)之外,模塊的指標(biāo)也是我們要抓取和統(tǒng)計(jì)的。

這些指標(biāo)包括:接口調(diào)用的延遲率、失敗率、某個(gè)API的調(diào)用次數(shù)甚至是請(qǐng)求體數(shù)據(jù)的大小等等。


三、微服務(wù)實(shí)踐分享

關(guān)于技術(shù)選型

就如前面“去中心化治理”部分提到的,我們選型的時(shí)候希望不被具體的通信協(xié)議或者語(yǔ)言框架綁架,所以我們選型的考慮點(diǎn)先是跟語(yǔ)言無(wú)關(guān)的通信機(jī)制,再來(lái)才是性能,所以我們優(yōu)先選擇通過HTTP進(jìn)行遠(yuǎn)程調(diào)用的框架。

DUBBO來(lái)自阿里巴巴,而DUBBOX來(lái)自當(dāng)當(dāng)(最近也加入了RESTful webservice)。當(dāng)當(dāng)在dubbo的基礎(chǔ)上開發(fā)了dubbox(Dubbo eXtensions),支持REST風(fēng)格遠(yuǎn)程調(diào)用。

Spring cloud是Spring社區(qū)基于Netflix(中文名網(wǎng)飛,是一間在世界多國(guó)提供網(wǎng)絡(luò)視頻點(diǎn)播的公司)在微服務(wù)方面的成功應(yīng)用,將其開源成spring cloud項(xiàng)目。

2013年3月,在VMware投資者大會(huì)上,VMware和EMC聯(lián)合宣布將成立Pivotal公司,由VMware前CEO保羅·馬瑞茲出任新公司首席執(zhí)行官,并宣布將專注開源PaaS和大數(shù)據(jù)應(yīng)用的Cloud Foundry、Greenplum等業(yè)務(wù)。

為什么我們要用Spring Cloud?

1、背景:出自Spring家族,具有Pivotal和Netfix強(qiáng)大的后盾

2、活躍度:版本更新頻繁,每月都基本更新一個(gè)版本

3、架構(gòu):具有一套完整的微服務(wù)解決方案

4、文檔:官方文檔完整(目前英文文檔居多)

5、未來(lái):微服務(wù)是一種趨勢(shì),它是實(shí)現(xiàn)微服務(wù)架構(gòu)的首選

因此,綜合考慮了各方面因素后,我們最后確定Spring Cloud作為開發(fā)框架。

關(guān)于API設(shè)計(jì)

首先,在API的設(shè)計(jì)方面,我們可以參考借鑒stormpath的文檔,聲連網(wǎng)本身也是借鑒stormpath的API文檔進(jìn)行設(shè)計(jì)和開發(fā)的;

那么首先給大家分享幾個(gè)我們?cè)趯?shí)踐中摸索出的經(jīng)驗(yàn):

1、要有一套消息格式標(biāo)準(zhǔn),使用統(tǒng)一的方式處理錯(cuò)誤

尤其是在錯(cuò)誤消息格式的制定,把錯(cuò)誤進(jìn)行分類,服務(wù)之間能按照統(tǒng)一的規(guī)則進(jìn)行處理,避免重復(fù)勞動(dòng)。

給大家展示一下我們的錯(cuò)誤碼分類(當(dāng)然這只是一部分),我們可以把錯(cuò)誤碼處理的邏輯封裝起來(lái)。

在spring cloud里面,通過feign調(diào)用微服務(wù) API,我們就可以把錯(cuò)誤碼的處理邏輯封裝到feign的intercepter(攔截器)當(dāng)中;

2. 接口必須是冪等的

可以使用唯一request id的方式,避免重復(fù)處理業(yè)務(wù)請(qǐng)求,造成狀態(tài)不一致。

3. 接口粒度合理權(quán)衡

需要根據(jù)業(yè)務(wù)場(chǎng)景決定API的粒度。例如,是分別調(diào)用A、B、C三個(gè)服務(wù)完成三個(gè)業(yè)務(wù)還是提供一個(gè)接口一起做ABC三個(gè)業(yè)務(wù)。我們?cè)谶@里提供一個(gè)參考,如果A/B/C相互之間比較獨(dú)立,且能并行執(zhí)行,建議分三個(gè)接口。而如果業(yè)務(wù)關(guān)聯(lián)性很強(qiáng),需要有先后的調(diào)用順序,可以考慮做一個(gè)微服務(wù)調(diào)用的編排服務(wù),然后對(duì)外提供服務(wù)。

4. 給API加上指標(biāo)監(jiān)控(如調(diào)用次數(shù)、duration等)& 告警

在指標(biāo)的抓取方面,我們使用的是prometheus。

我們?cè)贏PI接口中加入我們關(guān)心的指標(biāo)數(shù)據(jù),然后通過prometheus進(jìn)行收集存儲(chǔ),用grafana進(jìn)行可視化展示,使用Prometheus的alert manager進(jìn)行告警通知。

現(xiàn)在釘釘也支持webhooks了,所以我們可以把告警信息發(fā)布到釘釘運(yùn)維群里面,或者額一些協(xié)作工具比如 Teambition。當(dāng)然,合適的選擇還有很多,具體的途徑確認(rèn)還要看公司使用的工具是什么。

關(guān)于Token管理

Token管理方面我們通常的做法是:

1、使用JWT(JSON Web Token)

2、 把JWT存放在token管理服務(wù)中,由proxy取出處理后傳遞(或者直接讓客戶端托管JWT )

3、在微服務(wù)之間傳遞解密后的自包含用戶信息

每個(gè)服務(wù)應(yīng)該都是無(wú)狀態(tài)的,當(dāng)服務(wù)需要獲取上下文信息或者會(huì)話信息,比較常見的做法是將這些信息托管在外部服務(wù),需要的時(shí)候進(jìn)行訪問。那么,我們能否使用另外一種方式達(dá)到同樣的目的呢?

JSON Web Token(JWT)就是一個(gè)非常輕巧的規(guī)范。這個(gè)規(guī)范允許我們使用JWT在用戶和服務(wù)器之間傳遞安全可靠的信息。

如果你的payload當(dāng)中不會(huì)有什么敏感信息(例如userId就不是那么敏感),那么甚至可以考慮把JWT讓客戶端來(lái)托管。

當(dāng)然如果讓客戶端托管,會(huì)遇到一個(gè)不方便的地方,如果token還沒有過期,但是想讓token立即過期,那么使用這個(gè)解決方案是沒辦法做到的,而使用proxy的方案卻是可以的。

使用DDD進(jìn)行服務(wù)的識(shí)別與劃分

使用DDD之后,我們能切實(shí)感受到這些便捷:

1、方便快速發(fā)現(xiàn)和劃分業(yè)務(wù)模塊;

2、業(yè)務(wù)知識(shí)更加穩(wěn)固,有利于產(chǎn)品與開發(fā)人員的溝通;

3、縮減代碼量(精煉出模式,使用設(shè)計(jì)模式);

盡可能避免使用分布式事務(wù)

對(duì)于任何分布式系統(tǒng)而言,分布式事務(wù)都是難以處理的一個(gè)問題。

而我們的做法是,在設(shè)計(jì)的時(shí)候就盡量避免使用分布式事務(wù)的解決方案,使用最終一致性;

以下這些解決方案可以用于處理分布式事務(wù):

1、兩段式提交(或者叫TCC,Try-Commit-Cancel)

2、使用持久化隊(duì)列(之所以要說(shuō)那個(gè)持久化隊(duì)列是因?yàn)橄⒉荒軄G失)

2.1 事務(wù)的補(bǔ)償

2.2 事務(wù)的回滾

因此,我認(rèn)為要區(qū)分場(chǎng)景來(lái)使用分布式事務(wù)——

例如在庫(kù)存相對(duì)于無(wú)限,或比較沒有限制條件的情況下,可以使用補(bǔ)償機(jī)制達(dá)到數(shù)據(jù)的一致性;而若是對(duì)于有前提條件的事務(wù),就需要通過回滾的方式避免做了錯(cuò)誤的業(yè)務(wù)處理。

使用容器技術(shù)部署和管理微服務(wù)實(shí)例

使用容器技術(shù)部署微服務(wù)的優(yōu)勢(shì):

1、把運(yùn)行環(huán)境安裝到鏡像當(dāng)中,簡(jiǎn)化運(yùn)維人員的工作,避免出現(xiàn)“在我的環(huán)境下運(yùn)行完全正常,在xx環(huán)境下就不正常”的情況出現(xiàn);為DevOps做好基礎(chǔ)工作

2、最大可能地使用集群中的機(jī)器資源(在自建IDC的時(shí)候尤其適用)

3、可以方便地修改端口的映射

4、使用工具方便地啟動(dòng)整個(gè)微服務(wù)體系(例如docker-compose)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容