“微服務并不能解決你的爛代碼問題
很久以來,軟件的交付質量一直是一個大家比較關心的問題,而程序員和架構師也一直在極力尋找一種更好的方式來構建應用系統(tǒng)。隨著互聯網爆炸式的增長,對于系統(tǒng)的交付速度和質量的要求也日漸提高,這不僅對程序員寫的程序,而且對架構師對整個系統(tǒng)的架構能力提出了更高的要求。如果你學過領域驅動設計,你會知道系統(tǒng)的構建應該建立在業(yè)務模型之上,而不是圍繞著數據庫的表,視圖,存儲過程。如果你學過系統(tǒng)設計的
六邊形理論,你同樣也會知道提煉
業(yè)務核心模型才是構建一個具有可擴展性系統(tǒng)的重心所在。如果你了解過CI/CD,從客戶的滿意度來說,持續(xù)交付要比瀑布模型交付好太多。
image
image
image再加上非功能性的一些需求,最典型的:系統(tǒng)的高可用,高擴展性,高性能。這一系列要求對于傳統(tǒng)的開發(fā)模式根本不可能滿足。伴隨著容器技術,基礎設施自動化,大型集群的流行,微服務也慢慢的浮出水面。它并不是被發(fā)明出來的,而是隨著軟件系統(tǒng)的不斷發(fā)展衍生出來的。最重要的是很多公司在采用了微服務的架構之后確實明顯改善了軟件系統(tǒng)的交付速度和質量,并且可以有更多的機會去嘗試新的技術,比如現在流行的
容器技術,云原生,Serverless等。在團隊與團隊之間,職責更加清晰明顯,而且不同技術棧的團隊也可以很融洽的進行合作。
“當然,我比較排斥那種為了效仿而進行的技術改革。每個公司都有自己的技術沉淀以及債務,不要妄圖利用一種完美的技術來填平所有的焦油坑。
微服務
到目前為止,網絡上關于微服務的定義有很多版本,無論什么樣的文字定義都始終圍繞著以下核心:
“微服務是一組小而自治并且能協同工作的系統(tǒng)服務。它不僅僅是代碼級別的重用,更重要的是業(yè)務級別的重用和自治。
這讓我不禁想到了“中臺”的定義,中臺其中一個很明顯的目標是要達到
公司業(yè)務級別的重用,進而反饋給業(yè)務一些結果來達到閉環(huán)效果。
image微服務一定要足夠小嗎?
每一個系統(tǒng),在誕生的時候其實都很小,隨著產品的不斷發(fā)展,才會賦予這個系統(tǒng)更多的職能,但是,這個系統(tǒng)最主要的特點仍然是:一個
單體應用。什么叫單體應用?說白了,所有的代碼都在一個工程中,對外輸出的也只有一個工程。每次修改任何一個功能,哪怕是修改一個字符,都需要重新發(fā)布。隨著時間的推移,當這個單體越來越大的時候,你會發(fā)現大量的重復性代碼,大量的重復性功能,甚至會存在大量的重復性SQL語句。這些還只是表面現象,如果想要修改一個功能,居然會意想不到的影響很多地方,隨著人員的離職等情況,這些代碼沒有人會熟悉,慢慢的傳說中的“屎山”出現了。
image如果有一個技術且職責比較上心的技術經理或者總監(jiān),一些單體應用至少還會根據不同的模塊進行抽象,用接口的方式來達到代碼內的職責分離和高內聚。這里多說一句:
高內聚,松耦合在設計任何系統(tǒng)的時候都非常重要,尤其在大的單體系統(tǒng)應用中。
“把因為相同原因而變化的模塊(代碼)劃分到一起,而把不同原因而變化的模塊(代碼)分離出來
高內聚松耦合可以說在微服務中體現的淋漓盡致,因為微服務就是按照業(yè)務的不同模塊來進行劃分的,微服務之間擁有
明確的業(yè)務邊界,某個功能屬于哪個微服務,應該寫在哪個微服務里,一目了然。至于微服務的劃分粒度,說實話,業(yè)界并沒有一個明確的標準。但是服務之間的
邊界是明確的,假如說:一個微服務內還存在多個小模塊,這些小模塊是否也應該劃分為更小的微服務呢?這本質上還是微服務粒度劃分的問題,也是一個沒有明確答案的問題,不過卻可以依據一下幾個準則去進行微服務的規(guī)劃:
- 模塊的大小。如果一個模塊可以在兩周之內進行重寫,那這個模塊完全可以獨立成微服務。
- 模塊是否存在獨立的變化。如果一個模塊會頻繁變化,可以考慮獨立成一個單獨的微服務。
- 模塊是否具有比較高的性能需求。如果一個模塊在性能這個指標上有比較高的要求,為了應對這種要求可以劃分為獨立的微服務。
- 雖然每個人對小都沒有明確的概念,但是對“大”卻有著明確的敏感性。當你感覺一個系統(tǒng)“大”的時候,就可以考慮進行拆分了
“警告:系統(tǒng)進行微服務的拆分,并非是越小越好,更多的時候在拆分的時候要根據團隊,運維能力等進行綜合考慮,在總量不變的情況下,小意味著數量多,數量多意味著必須要投入更多的人力物力去管理運維,并且也會引入分布式下的很多問題。這個之后咱們具體詳聊.....
微服務優(yōu)勢明顯嗎?
到目前為止,全網都在吹噓進行微服務的劃分,但是在脫離具體業(yè)務場景的條件下,大力倡導拆分微服務,這很明顯就是在教人耍流氓而不負責任。我某天看到一篇文章返璞歸真的要回歸單體應用,我看完之后默默的點了個贊,從文章中具體的業(yè)務來說,確實采用單體應用比微服務更合適,因為他們的業(yè)務邊界很模糊,可以說沒有業(yè)務邊界,一味的進行微服務劃分,帶來的是一系列的
分布式問題,對于公司而言反而沒有益處。說到微服務的優(yōu)勢,一般都是對比單體服務來說的,單體應用有哪些缺點呢?
- 開發(fā)效率低:所有的開發(fā)在一個項目改代碼,遞交代碼相互等待,代碼沖突不斷
- 代碼維護難:代碼功能耦合在一起,新人不知道何從下手
- 部署不靈活:構建時間長,任何小修改必須重新構建整個項目,這個過程往往很長
- 穩(wěn)定性不高:一個微不足道的小問題,可以導致整個應用掛掉
- 擴展性不夠:無法滿足高并發(fā)情況下的業(yè)務需求
這些你都可以用百度搜到,這里不再詳細展開了。微服務的優(yōu)勢明顯嗎?我想說,對于很多
大型系統(tǒng)確實很奏效,但是對于一些中小型系統(tǒng),那就不一定了。
“就像很多架構師吹噓的充血模型一樣,一味的貶低貧血模型一無是處,無形中總是在拉低自己的格局。
高擴展性
當系統(tǒng)處于單體系統(tǒng)的時候,如果某一個模塊遇到性能問題或者想要保證高可用特性,只能將整個系統(tǒng)進行多份部署來達到目的,哪怕是只有一個小小的部分存在性能問題。如果把這一部分進行了微服務的拆分,那么就可以只針對這個微服務進行擴展了,無論是性能還是高可用的要求,都可以單獨進行,而不必影響其他模塊,而且公司對于成本問題上要低很多。舉一個簡單例子:假如有一個電商系統(tǒng),包含了商品,訂單,支付等模塊,對于性能而言,用戶瀏覽商品量要比下訂單量大很多,很顯然,商品模塊對于性能有著更高的要求,這個時候就可以考慮把商品這個模塊獨立出來,以便提供橫向擴展的高性能能力。
彈性
在傳統(tǒng)的單體系統(tǒng)中,當服務不可用的時候,就意味著所有的模塊都不可用,雖然也可以通過部署多份大單體的方式來降低這個概率,但是這種方式始終是種詬病。在微服務架構中,如果一個服務不可用,并不會影響全部的服務,當然如果做好了微服務的降級,限流等工作,將會把影響降低到最低。
部署簡單
在大單體時代,哪怕是修改了一行代碼也需要重新編譯整個項目來進行重新部署,這種部署方式其實隱含的風險非常大,所以很多大單體的運維人員都不會頻繁進行項目的部署,而且部署的時候很多時候要準備好通宵(因為風險大),尤其是那種多個迭代的大部署行為。在微服務的架構下,每個微服務都是獨立部署的,這樣就可以針對迭代進行更快的上線操作,而不影響其他服務,而且就算是線上出問題,回滾操作也非??臁D軌蚩焖俚牡鹿δ芤馕吨脩艨梢钥焖俚膰L試新功能,這在我們交付高質量的軟件是非常有利的。
技術自由
由于每個微服務之間交互都采用RPC或者REST進行交互,而這些交互方式又有著嚴格的規(guī)范,所以每個微服務采用什么技術棧是相對自由的,不同團隊之間技術的差異性在微服務架構下不復存在,而且每個團隊都可以嘗試一些新技術,最重要的是每個微服務都可以根據自身的業(yè)務特點來進行合適的技術選型,比如:當一個典型的文檔存儲微服務,我們可以選擇采用mongoDB來做存儲;當一個搜索型微服務,我們可以采用ES來做存儲。
image程序員的福音
在大單體的時代,時常會發(fā)生“我的代碼被哪個孫子改了”的情況,由于大家都在一個大的代碼庫進行工作,還會偶爾發(fā)生代碼互相覆蓋的情況(我想很多人都發(fā)生過這種情況)。而在微服務的架構下,每個劃分出來的微服務都有自己的獨立
代碼倉庫,最重要的一點這個代碼倉庫只有一個團隊在使用,至于團隊內的溝通要比團隊之間溝通暢快的多,所以代碼管理這部分幾乎不會出現什么問題。同一個業(yè)務的功能,只需要開發(fā)一遍,至于使用端是網頁,還是桌面,還是小程序或者app,都可以重用一套接口,真正的實現了業(yè)務上的重用。這才是程序員想要的結果?。。。?!而且對于某個微服務的重構工作會非常順利,因為每個微服務的
代碼量不會很大,而且業(yè)務也很清晰,這在大單體時代是不存在的。
總結
就像“人月神話”中描述的一樣,微服務也并非銀彈。如果一個架構師盲目的進行微服務的拆分會面臨著分布式系統(tǒng)的一系列的問題,比如:網絡的不可靠性帶來的問題,分布式事務帶來的一致性問題,分布式監(jiān)控的問題,還有最重要的CAP抉擇問題等。所以:
“微服務有時候可能并不適合你,誰用誰知道!?。?/p>