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