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