大白話聊聊微服務(wù)——人人都能看懂的演進(jìn)過(guò)程
本文轉(zhuǎn)載自微信公眾號(hào)「SH的全棧筆記」,作者leonhlh 。轉(zhuǎn)載本文請(qǐng)聯(lián)系SH的全棧筆記公眾號(hào)。
這篇博客的本意是希望看到這篇文章的讀者能夠很輕松的理解我想表達(dá)的意思。但程序向的分享經(jīng)常會(huì)不經(jīng)意間就貼上了代碼,很可能就會(huì)讓人看的很懵。而且我認(rèn)為分享一個(gè)東西,只有對(duì)方真正明白了其中的邏輯,才是有意義的分享。所以接下來(lái)我會(huì)嘗試用大家都能理解的語(yǔ)言來(lái)聊一聊”微服務(wù)“。
【寫在前面】
那么,什么是微服務(wù)呢?你不一定知道微服務(wù),但是你一定知道麥某勞,而且知道麥某勞有個(gè)甜品站。你可能會(huì)問(wèn),甜品站和微服務(wù)有什么關(guān)聯(lián)呢?
讓我們先假設(shè)不把甜品站獨(dú)立出來(lái),而是普通的麥某勞店。經(jīng)營(yíng)一段時(shí)間你會(huì)發(fā)現(xiàn),這個(gè)地方雖然人流量很大,也有顧客,但是顧客的需求80-90%都集中在甜品,導(dǎo)致甜品供不應(yīng)求,而其余的菜品則沒(méi)多少人購(gòu)買。但是把這個(gè)店關(guān)了嗎?那也不行,始終是有流量的。
所以綜合考慮下來(lái),方案就是把甜品這個(gè)“模塊”從整個(gè)店中獨(dú)立出來(lái),單獨(dú)對(duì)外提供服務(wù)。這樣既能保住流量,也能避免浪費(fèi)。
微服務(wù)也是一樣的,比如電商的服務(wù),假設(shè)里面耦合了商品、庫(kù)存、訂單、用戶的服務(wù),但是訂單這個(gè)模塊可能會(huì)訪問(wèn)的特別頻繁,而用戶和商品被訪問(wèn)的頻率沒(méi)有那么高,如果為了同時(shí)給更多用戶提供服務(wù),而再部署一個(gè)包含了商品、庫(kù)存、訂單和用戶的服務(wù),有兩個(gè)模塊的資源其實(shí)沒(méi)有被充分利用到。
跟甜品站的思路是一樣的,如果把商品、庫(kù)存、訂單和用戶分成四個(gè)服務(wù)模塊,每個(gè)服務(wù)只負(fù)責(zé)處理的自己的事情,就像甜品站只賣甜點(diǎn)一樣,如果訂單的訪問(wèn)量大, 那也只需要再部署一個(gè)訂單的模塊,而不會(huì)造成資源利用不充分、耦合性強(qiáng)的情況。
最開(kāi)始的“整家麥某勞”店對(duì)應(yīng)的概念就是單體應(yīng)用,后面獨(dú)立出的“甜品站”就是從單體應(yīng)用中抽離出的“微服務(wù)”。不知道什么是單體應(yīng)用和微服務(wù)是什么沒(méi)關(guān)系,不知道單體應(yīng)用為什么、以及如何轉(zhuǎn)變成微服務(wù)的也沒(méi)關(guān)系,讓我們通過(guò)一個(gè)故事來(lái)完整的理解這個(gè)概念。
假設(shè)正在閱讀這篇文章的你,擁有一家飯店。
0.【夢(mèng)開(kāi)始的地方】
你盤下了一個(gè)店面想賣炸雞和甜品,于是你簡(jiǎn)單的把店裝修了一下,購(gòu)置了相關(guān)的設(shè)備,然后雇了廚師、服務(wù)員等相關(guān)的工作人員,就開(kāi)始掛上招牌對(duì)外營(yíng)業(yè)了,
0.1 店面
就是我們平常去使用的各種C端產(chǎn)品,如果你沒(méi)有一個(gè)概念,那么可以直接把它理解成釘釘、微信這樣一個(gè)我們?nèi)粘6荚谟玫腁PP就好,它們就是C端產(chǎn)品。
店的招牌(比如肯打雞和麥某勞)就可以理解為我們平常APP里所能看到的,所能使用的東西,我們叫它客戶端。
整個(gè)實(shí)體店就可以理解為開(kāi)篇提到的“單體應(yīng)用”,為客戶提供實(shí)際的服務(wù)。
0.2 裝修和購(gòu)置設(shè)備
對(duì)應(yīng)的是我們的開(kāi)發(fā)團(tuán)隊(duì),從產(chǎn)品經(jīng)理接到客戶的需求開(kāi)始,根據(jù)需求整理好原型圖,不停的跟客戶溝通交流細(xì)節(jié),反復(fù)的修改原型圖,最終定下來(lái)的需求。
然后我們的UI同學(xué)介入,根據(jù)原型圖出UI圖,并最終確定下來(lái)。然后就是前端和后端的開(kāi)發(fā)同學(xué)根據(jù)原型圖中的邏輯,和UI圖的樣式細(xì)節(jié)開(kāi)始迭代開(kāi)發(fā),并最終將產(chǎn)品上線。
0.3 炸雞和甜品
有了前面麥某勞的例子,這個(gè)應(yīng)該很好理解。炸雞和甜品其實(shí)就是作為一個(gè)C端產(chǎn)品,提供給用戶的不同種類的服務(wù)。
例如我們?nèi)粘T谟玫尼斸敚梢杂脕?lái)聊天、開(kāi)視頻會(huì)議和預(yù)定會(huì)議室。
1.【漸入佳境】
隨著你不斷的推出新的菜品,以及分量足,性價(jià)比高,朋友之間口口相傳—“那家蒼蠅館子還可以”,也留住了大量回頭客。慢慢的,來(lái)店里吃飯的客人越來(lái)越多,后廚漸漸忙不過(guò)來(lái)了。很多慕名而來(lái)的客人由于等了太長(zhǎng)時(shí)間仍然沒(méi)有上菜,更有甚者連座位沒(méi)有。客人對(duì)美食的渴望轉(zhuǎn)化成了失望和憤怒,于是反手就是一個(gè)超級(jí)差評(píng)。
1.1 不斷的推出新的菜品
代表我們的產(chǎn)品迭代,不斷的推出新功能,以此來(lái)為用戶提供更多元化的服務(wù),吸引更多的用戶來(lái)使用我們的產(chǎn)品。例如疫情期間,釘釘在在線學(xué)習(xí)這塊推出了很多新的功能。
1.2 朋友間的口口相傳
則代表的是部分用戶開(kāi)始代替廣告這種傳播途徑,開(kāi)始了社群內(nèi)的用戶自傳播。這是很多產(chǎn)品都想達(dá)到的目的,把產(chǎn)品的潛力挖掘到極致,讓產(chǎn)品說(shuō)話,為自己代言。
比起漫天飛的廣告,這種來(lái)自朋友們的推薦,更加受到用戶的信任。
1.3 關(guān)于差評(píng)
“后廚忙不過(guò)來(lái)”是指用戶數(shù)量上漲,日常的請(qǐng)求數(shù)就會(huì)隨之增多,而單個(gè)服務(wù)實(shí)例在某個(gè)時(shí)間單位內(nèi)能夠處理請(qǐng)求的數(shù)量是有限的(也就是后廚人數(shù)有限,就那么幾個(gè)廚師,能做的菜數(shù)量也有限),這也直接導(dǎo)致了部分用戶請(qǐng)求十分緩慢,甚至直接無(wú)法訪問(wèn)(后廚實(shí)在忙不過(guò)來(lái)了,有些客人就要等很久)。而用戶對(duì)于產(chǎn)品的耐心是十分有限的,出現(xiàn)這種情況會(huì)導(dǎo)致部分甚至大量用戶流失。
2.【蜂擁而至】
隨著差評(píng)越來(lái)越多,你漸漸坐不住了。你覺(jué)得再這么下去你可能就要涼了,于是你想,廚師不夠用那就多招幾個(gè)嘛,于是雷厲風(fēng)行的你貼出了招聘啟事,然后順利的招到了人。
人的問(wèn)題解決了,那還有座位的問(wèn)題。之前你沒(méi)有想到會(huì)有這么人多來(lái)光顧,所以店里面的桌子和椅子擺的很寬松,但是實(shí)際上重新規(guī)劃一下,還是能夠多放好幾張桌子的,這樣一來(lái)就能夠同時(shí)容納更多人在店里用餐。
2.1 多招人
我們每個(gè)服務(wù)所能使用的資源是有限制的,例如你可以給你的JVM設(shè)置最大堆內(nèi)存為1G,也可以加到2G。啊?什么是JVM?不重要,讓我們重新理解前面一句話。2個(gè)廚師一分鐘可以做5個(gè)菜,你轉(zhuǎn)手再招2個(gè)廚師,那一分鐘就可以做10個(gè)菜,這對(duì)應(yīng)的概念是擴(kuò)容,也就是增加服務(wù)器能夠支配的運(yùn)行資源,服務(wù)器就能夠處理更多的請(qǐng)求,服務(wù)更多的用戶。
這里的擴(kuò)容是針對(duì)CPU和內(nèi)存
2.2 重新規(guī)劃桌椅擺放
剛開(kāi)始開(kāi)發(fā)時(shí)沒(méi)有到用戶會(huì)有這么大體量,所以大部分的API沒(méi)有做什么優(yōu)化,整個(gè)服務(wù)端應(yīng)用的框架也搭建的很隨意,因?yàn)樯暇€的時(shí)間很緊,這可能會(huì)造成應(yīng)用在維護(hù)性、擴(kuò)展性和性能上的弊端。
通俗點(diǎn)來(lái)說(shuō)就是,當(dāng)時(shí)為了店里擺放好看,追求ins風(fēng),桌椅之間擺的太寬了,但是后來(lái)人多了,外面一堆人排隊(duì),店里面卻熙熙攘攘,但是實(shí)際上你卻是已經(jīng)“坐滿了”。
這種情況十分不利于后續(xù)的迭代的。所以對(duì)應(yīng)到開(kāi)發(fā)中的概念就是,對(duì)代碼和框架進(jìn)行重構(gòu),優(yōu)化算法,讓API盡量少占用系統(tǒng)資源,降低響應(yīng)延遲,從而提高整個(gè)服務(wù)的服務(wù)能力。這樣一來(lái),服務(wù)實(shí)例就能扛住更多的請(qǐng)求。
不過(guò)有的時(shí)候,降低延遲和少占用系統(tǒng)資源不可兼得。如果對(duì)響應(yīng)速度要求很高,就可能會(huì)多占一些系統(tǒng)資源,用空間來(lái)?yè)Q時(shí)間。
就像你把店里重新擺放了,店里容納的人多了(占用資源多了),這個(gè)時(shí)候服務(wù)的響應(yīng)時(shí)間可能就會(huì)變慢(上菜就會(huì)變慢),那么用空間換時(shí)間是什么呢?就是你會(huì)提前準(zhǔn)備很多食材、甚至是半成品的食材堆在那里,這樣以來(lái),只需要花平時(shí)一半的時(shí)間就可以把菜做好(比如提前準(zhǔn)備好熟油,各種輔料等等)。
3.【山窮水盡】
雖然多招了幾個(gè)廚師,也重新規(guī)劃了店里桌椅擺放,但是隨著時(shí)間的推移,每天來(lái)店里吃飯的人還是越來(lái)越多,廚師已經(jīng)不能再招了,已經(jīng)沒(méi)有那么多灶臺(tái)了。之前的“差評(píng)熱潮”又開(kāi)始在店里上演。你想著,雖然店里火爆是好事,但是每天有那么多的人來(lái)店里看到?jīng)]有位置就走了,這不是有錢賺不了嗎?
而且很多目標(biāo)用戶在第三方網(wǎng)站上看到了這些差評(píng),將會(huì)直接影響到客戶是否愿意來(lái)店里,這會(huì)使你喪失大量的隱藏客戶。于是你開(kāi)始了轟轟烈烈的開(kāi)分店業(yè)務(wù),在附近又開(kāi)了一家店。還是一樣的配方,就是這個(gè)味~
3.1 開(kāi)分店
開(kāi)分店對(duì)應(yīng)的概念是多實(shí)體部署,就是把一個(gè)同樣的服務(wù)再部署一個(gè),這樣一來(lái)來(lái)自用戶的流量就從一個(gè)服務(wù)扛變成了兩個(gè)服務(wù)扛。
分店就可以把原本要把總店塞爆的流量給接過(guò)去,緩解了壓力。
4.【柳暗花明】
隨著時(shí)間的推移,分店越開(kāi)越多,生意自然也是蒸蒸日上。但是你作為一個(gè)能夠不只看表面的布局者,你發(fā)現(xiàn)了實(shí)際上的情況并沒(méi)有表現(xiàn)出來(lái)的那么好。
有些區(qū)域人流量大,而有些區(qū)域雖然人流量大,但是對(duì)店感興趣的人不多,甚至分店周圍根本沒(méi)有什么人。而有些地方的分店則異常火爆。雖然熱門的店賺的錢能夠抵上冷門的店的虧損,但是追求完美的你認(rèn)為這種情況必須要得到改善,因?yàn)檫@始終是存在對(duì)資源的浪費(fèi)。
所以經(jīng)過(guò)一番調(diào)研,你決定在中心區(qū)域開(kāi)一個(gè)顧客中心,所有想來(lái)餐廳的人都統(tǒng)一的來(lái)顧客中心,由顧客中心的人根據(jù)各個(gè)分店的火爆情況來(lái)分批次的把顧客送過(guò)去。這樣一來(lái),也就解決了有些店火爆,而有些店冷清的情況了。
4.1 人流量分布不均勻
這種情況主要發(fā)生在服務(wù)端運(yùn)行了多個(gè)實(shí)例,那也就對(duì)于多個(gè)IP地址,而要調(diào)用哪個(gè)是由客戶端來(lái)決定的,如果設(shè)計(jì)的不夠好,就會(huì)出現(xiàn)某些時(shí)候某些實(shí)例成為熱點(diǎn)實(shí)例,甚至出現(xiàn)“差評(píng)”實(shí)例這種情況,而其余實(shí)例則沒(méi)有承擔(dān)多少來(lái)自用戶的流量。
說(shuō)人話就是,我要是顧客,我去哪家店不是看我心情嗎?我想去哪家店就去哪家店。當(dāng)然實(shí)際情況沒(méi)有這么夸張,客戶端會(huì)有自己的策略。
而且同時(shí)維護(hù)如此多的服務(wù)端地址也是很麻煩的一件事,如果服務(wù)端此時(shí)又增加了實(shí)例,客戶端則需要同步的更新。但是如果用戶體量大的話,因?yàn)檫@種問(wèn)題頻繁的發(fā)包讓用戶更新,會(huì)對(duì)用戶造成不好的體驗(yàn)。
4.2 顧客中心
這個(gè)比喻有些夸張,現(xiàn)實(shí)中有人這么干可能早破產(chǎn)了。“顧客中心”就是我們說(shuō)的“網(wǎng)關(guān)”。有了網(wǎng)關(guān),客戶端就不用關(guān)心服務(wù)有多少個(gè)實(shí)例,也不用去維護(hù)所有的HOST,所有的請(qǐng)求直接從網(wǎng)關(guān)走,由網(wǎng)關(guān)來(lái)決定將當(dāng)前請(qǐng)求分發(fā)到哪個(gè)實(shí)例。
“客戶中心分批次根據(jù)情況送顧客”其實(shí)對(duì)應(yīng)到的概念是負(fù)載均衡,什么意思呢?就是要讓客戶端產(chǎn)生的流量對(duì)所有實(shí)例雨露均沾。其實(shí)現(xiàn)的方式也有很多,大致分為隨機(jī)、輪詢、一致性哈希、加權(quán)等等。
而網(wǎng)關(guān)除了負(fù)載均衡,還有很多其他的特性。例如,動(dòng)態(tài)的路由、限流、認(rèn)證、日志、熔斷、可編程插件配置等等。
5. 【微服務(wù)的關(guān)注點(diǎn)】
看完了這個(gè)故事,你可能會(huì)覺(jué)得沒(méi)有什么,但是實(shí)際上你已經(jīng)了解了一個(gè)應(yīng)用從單體應(yīng)用架構(gòu)轉(zhuǎn)為微服務(wù)的架構(gòu)生命周期以及過(guò)程。這其中也包括為什么需要轉(zhuǎn)為微服務(wù)架構(gòu),和轉(zhuǎn)到微服務(wù)架構(gòu)的好處在哪里。如果你都沒(méi)有意識(shí)到自己理解了這個(gè)概念,可以再閱讀一遍上面的小故事。
其實(shí)實(shí)際上的微服務(wù)要比上面故事所呈現(xiàn)出來(lái)的復(fù)雜很多,微服務(wù)中需要關(guān)注的點(diǎn)要比傳統(tǒng)的單體應(yīng)用多的多。在微服務(wù)中我們需要關(guān)注服務(wù)的發(fā)現(xiàn)、負(fù)載均衡,統(tǒng)一的配置管理,微服務(wù)集群的自愈和彈性伸縮,服務(wù)的調(diào)度和發(fā)布,微服務(wù)中的調(diào)用鏈監(jiān)控,包括Metrics監(jiān)控,日志監(jiān)控,服務(wù)的安全考慮,API的統(tǒng)一管理等等。
首先把強(qiáng)耦合在一起的代碼有條理的拆分出來(lái)就是一件很復(fù)雜的事情,微服務(wù)的劃分粒度也是一個(gè)很大的挑戰(zhàn)。例如很復(fù)雜的系統(tǒng),一個(gè)用戶服務(wù)的代碼可能有好幾千上萬(wàn)行,但是它仍然是一個(gè)微服務(wù),沒(méi)有再拆分用戶服務(wù)A和用戶服務(wù)B。而有的服務(wù)可能代碼量只有幾百行,這需要根據(jù)實(shí)際的業(yè)務(wù)情況來(lái)選擇劃分的粒度。
除了拆分服務(wù)的粒度,微服務(wù)本身還有很多組件。大家在故事中只了解了網(wǎng)關(guān)。其實(shí)還有很多組件。
服務(wù)發(fā)布就涉及到Jenkins,把我們的應(yīng)用打包成Docker Image,然后通過(guò)自動(dòng)化工具發(fā)布到對(duì)應(yīng)的環(huán)境中。我們的應(yīng)用跑在Docker中,那么我們就需要有一個(gè)容器編排工具來(lái)管理這么多容器。例如我們現(xiàn)在使用的就是Docker Swarm,跟業(yè)界現(xiàn)在流行的Kubernetes一樣,有很多人在使用。
有了容器編排工具,就有工具的可視化界面,Docker Swarm對(duì)應(yīng)的Portainer,和Kubernetes對(duì)應(yīng)的Rancher。除此之外我們還要使用Gitlab來(lái)做我們的代碼版本管理工具,MySQL和MongoDB作為數(shù)據(jù)存儲(chǔ)的解決方案。Redis作為緩存的解決方案。同時(shí)需要有一個(gè)地方來(lái)統(tǒng)一管理所有服務(wù)的配置,我們叫微服務(wù)的配置中心。
除此之外,服務(wù)之間要相互調(diào)用就必須要知道對(duì)方的地址,就需要一個(gè)注冊(cè)中心,來(lái)保管所有服務(wù)的地址,并及時(shí)的更新服務(wù)的狀態(tài)。
還有很多細(xì)節(jié),例如如何去構(gòu)建一個(gè)Jenkins的構(gòu)建流水線,如果實(shí)現(xiàn)一套CI/CD的流程,如果使用ELK去做統(tǒng)一的日志收集,如果在集群內(nèi)實(shí)現(xiàn)SSO啊等等,由于篇幅原因就不在此一一贅述了。