作者介紹
伍欣? 廈門聲連網(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)