微服務在過去幾年一直是一個很是熱門的話題(附錄1)。何爲「微服務的瘋狂」,舉個例子:git
衆所周知,Netflix在DevOps上的表現很是棒。Netfix能夠作微服務。所以:若是我作微服務,我也將很是擅長DevOps。github
不少狀況下,咱們盲目的投入巨大的努力來接入微服務模式,然而每每卻不多去考慮接入的成本和收益可否有效的幫咱們解決當前咱們正面臨的痛點。數據庫
下面,我將詳細描述微服務是什麼,以及爲何這種模式這麼吸引人,最後再聊一聊一些微服務正面臨的一些關鍵挑戰。服務器
若是你正在考慮微服務是否適合你,是否能幫你解決當前面臨的問題?那繼續往下看,我會用一系列簡單的問題來幫你走出你的困惑。這一系列「問題」在文章的最後。網絡
來來來,老司機帶你從基礎走一波。一個例子:下面這張圖是一個假想的視頻共享平臺的實現方式,左側是用一個「總體服務」來實現,右側是多個微服務的形式來實現:
兩種系統設計的區別在於左側是一個總體的大而全的服務。右側是一組小而多,但每一個都是一個具體的服務,每一個服務都有特定的角色。數據結構
當從系統細節層面來繪製圖表時,很容易看出微服務的不少潛在的好處,簡單從幾個方面來講一下:架構
獨立開發:小型獨立組件可由小型獨立團隊構建。一個小組能夠改變「Upload」服務,而不會干擾「Transcode」服務,甚至都不須要知道這個服務。瞭解組件的時間大大減小,開發新功能也更容易。併發
獨立部署:每一個單獨的組件均可以獨立部署。這樣能夠以更快的速度和更少的風險發佈新功能。好比:「Streaming」組件的修復或功能能夠部署,而不須要部署其餘組件。運維
獨立的可伸縮性:每一個組件能夠彼此獨立地進行縮放。在需求多併發同時須要發佈新的版本時,能夠放大「Download」組件,以處理增長的負載,而沒必要擴大每一個組件,這使得彈性縮放更加可行並下降了成本。異步
可重用性:組件實現一個小的,特定的功能。這意味着它們能夠更容易地適用於其餘系統、服務或產品。「Transcode」組件能夠被其餘業務部門使用,甚至能夠變成一個新的業務,或者爲其餘組提供Transcode服務。
從細節層面上來看,微服務模型較之於總體模型的好處顯而易見。可是問題來了,若是真的是這樣的話 – 爲何微服務模式最近幾年才流行?我一輩子都快走完了(尷尬,貌似暴露年齡了),它纔出現?
這個問題有兩種答案。其一是,它強依賴咱們最好的技術能力,另外一個是最近的技術進步,促使咱們可以把它帶到一個新的高度。
當我開始寫軟文來回答這個問題的時候,發現這將會是一個很長的描述,因此從實際的角度出發,我將把它拆成兩篇文章,稍後再發表2。第1篇文章,我將跳過一些內容,好比:從單個程序到多個程序的過程,忽略ESB和麪向服務的體系結構,組件設計和有限的上下文等等。
感興趣的朋友能夠稍後閱讀更多關於journey的信息。儘管,在不少方面咱們已經這樣作了一段時間,可是隨着最近容器技術(特別是Docker)和編排技術(如Kubernetes、Mesos、Consul等等)的普及,從技術的角度來看,微服務模式變得更加可行。
所以,若是咱們想要實施微服務的話,咱們最好仔細慎重考慮是否真的須要。咱們已經看到了高大上的「理論效益」,但值得一提的是,未知的挑戰又是什麼?
微服務如此強大、完美,哪裏還會有什麼挑戰?這是目前我見過的最大的問題。
對於開發者來講事情會變得更加困難。在開發人員想要在遠程工做的狀況下,或者可能跨越許多服務的功能的狀況下,開發人員必須在他們的機器上運行它們,或者鏈接到它們。這一般比簡單地運行單個程序更復雜。
這個挑戰能夠經過工具(附錄3)獲得部分緩解,但隨着構成系統的服務數量的增長,開發人員在整個系統運行時面臨的挑戰也會愈來愈多。
對於不開發服務但維護服務的團隊來講,潛在的複雜性是一個巨大的挑戰。他們不是管理幾個正在運行的服務,而是管理數十,數百或數千個正在運行的服務。服務越多,溝通越多,潛在的失敗風險就越多。
閱讀以上兩點,可能會發現運維和開發是分開處理的,尤爲是考慮到DevOps做爲一種實踐的普及(我是DevOps的真愛粉)。DevOps難道不能緩解這一痛點?
目前面臨的挑戰是,許多組織仍然依靠獨立的開發和運營團隊來運行 – 而一些組織則更傾向於採用微服務。
對於已經採用了DevOps的組織來講,這仍然很難。既是開發者又是運維者,已經很是艱難(可是要創建好的軟件卻很關鍵),可是也必須瞭解容器編排系統的細微差異,特別是快速發展的系統是很是困難的。這使我想到了下一點。
當不少事情都由專家完成時,最終的結果也將是極好的。但想象一下,一個機構或組織使用單一的總體系統並不老是能夠很順利的運行。那作些什麼可以來改善並讓這些事情變得更好呢?經過增長系統服務的數量?但同時也會增長運行的複雜性。
不能否認,經過有效的自動化、監控和編排等,這一切均可以改善。但挑戰不多是技術自己——真正的挑戰實際上是找到可以有效使用技術的人。偏偏目前這些技能需求很是高,可能很難找到符合你需求的人。
在咱們用來描述微服務的好處的全部例子中,咱們都談到了獨立的組件。可是在不少狀況下,組件並非徹底獨立的。正所謂「紙上得來終覺淺,絕知此事要躬行」,某些領域可能看起來有限,可是當你陷入冗繁的細節時,你會發現他們比你預期的更具挑戰性。
這是事情變得很是複雜的地方。事實上,若是你的邊界沒有明肯定義,那麼會發生什麼狀況呢?即便理論上的服務能夠單獨部署,你會發現,因爲服務之間的相互依賴關係,你必須部署一系列微服務做爲一個組服務。
這意味着你須要管理協同工做的版本,這些版本的服務在聯調時會通過驗證和測試,你實際上沒有可獨立部署的系統,由於要部署新功能,你須要仔細編排許多服務的同時去部署。
在前面的例子中,我提到一個功能部署可能須要同時部署多個版本的許多服務。假設合理的部署技術將緩解這種狀況,例如藍/綠部署(大多數服務編排平臺不多原生支持這種功能),或者並行運行多個版本的服務,以及決定使用哪一個版本的消費通道。
若是服務是無狀態的,這些技術能夠緩解大量的挑戰。可是無國界的服務很是坦率,容易處理。事實上,若是你有無狀態的服務,那麼我會傾向於考慮跳過微服務,並考慮使用無服務器模型。
實際上,許多服務須要管理。咱們的視頻共享平臺的一個例子多是訂閱服務。訂閱服務的新版本能夠以不一樣形狀將數據存儲在訂閱數據庫中。若是你同時運行這兩個服務,則一次運行兩個模式的系統。若是您進行了藍/綠部署,而其餘服務依賴於新形狀中的數據,則必須同時更新這些數據,而且若是訂閱服務部署失敗並回滾,則可能還須要使用級聯回滾。
一樣,可能你會說,在NoSQL數據庫中,這些架構問題會消失,但事實並不是如此。不強制執行模式的數據庫沒法鏈接無模式系統——這意味着模式每每是在應用程序級而不是數據庫級進行管理的。理解數據結構以及如何流轉的根本性問題並不能被消除。
當你創建一個相互依賴的大型服務網絡時,可能會有不少的服務間通訊。這致使了一些挑戰。首先,有不少事情可能會失敗。咱們必須假設網絡call可能會失敗,這意味着當一個服務call另外一個服務時,它應該至少須要重試幾回。如今當一個服務可能調用不少服務時,咱們最終會遇到一個更加複雜的狀況。
用戶上傳視頻共享服務中的視頻。咱們可能須要運行upload服務,將數據傳遞到transcode服務,更新訂閱,更新建議等等。全部這些調用都須要必定程度的協調,若是過程當中任何部分失敗,咱們都須要重試。
這個重試邏輯可能難以管理。試圖同步作事每每會致使站不住腳,失敗點太多。在這種狀況下,更可靠的解決方案是使用異步模式來處理通訊。這裏面臨的挑戰是異步模式自己每每會使系統具備狀態性。如前所述,分佈式狀態系統和有狀態系統很難處理。
當一個微服務系統使用消息隊列進行服務內通訊時,你基本上須要有一個大的數據庫(消息隊列或代理)將這些服務組合在一塊兒。一樣,雖然起初看起來彷佛不是一個挑戰,但你懂的——出來混早晚都是要還的。X版本的服務可能會寫入某種格式的消息,當發送服務更改發送的消息的詳細信息時,依賴於該消息的服務也將須要更新。
固然,能夠有許多不一樣格式的消息處理服務,但這很難管理。如今,在部署新版本的服務時,你可能會有兩個不一樣版本的服務嘗試處理來自同一隊列的消息,甚至多是由不一樣版本的發送服務發送的消息。這可能會致使複雜的邊緣狀況。爲了不這些邊緣狀況,僅容許特定版本的消息存在可能更容易,這意味着你須要將一組服務的版本做爲一個總體來部署,以確保先前版本的消息被正確地屏蔽。
這再次突出代表,獨立部署的想法可能不會像預期的那樣順利。
爲了緩解前面提到的挑戰,版本控制須要很是謹慎的管理。再說一下,看起來貌似有一種趨勢——假設遵循像Semver[4]這樣的標準或許將能夠解決這個問題。然而事實並不是徹底如此。雖然Semver是一個合理的使用慣例,可是你仍然須要持續的跟蹤那些能夠一塊兒工做的服務和API的版本。
這可能會使事情變得很是具備挑戰性,而且不少時候可能會讓你感到困惑——哪些版本的服務能夠一塊兒正常工做。
在軟件系統中管理依賴關係是很是困難的,不管是節點模塊,Java模塊,C庫仍是其餘。當一個實體消費獨立組件之間的衝突的挑戰是很難處理的。
當依賴關係是靜態的時候,這些挑戰是很難處理的。雖然能夠進行修補、更新、編輯等,可是若是依賴關係自己是實時服務,那麼你可能根本沒法更新它們——你可能須要運行許多版本(上面已經描述過這些挑戰),或者直到整個系統獲得修復。
在須要跨操做交易完整性的狀況下,微服務可能會很是痛苦。分佈式狀態很難處理,不少小的單位可能會很難進行編排交易。
試圖經過使操做冪等性,提供重試機制等來避免這個問題可能聽起來很誘人,並且在不少狀況下確實可能起做用。但可能有一些場景,你只須要一個事務失敗或成功,而不想它處於中間狀態。解決這個問題或者在微服務模型中實現它的代價多是很是高的。
顯然,單獨的服務和組件多是孤立部署的,可是在大多數狀況下,你將不得不運行某種編排平臺,好比Kubernetes。若是你使用的是託管服務,例如Google的GKE 5或Amazon的EKS 6,則會爲你處理管理羣集的大量複雜性。
可是,若是你要本身管理集羣,那麼你正在管理一個龐大而複雜的關鍵任務系統。儘管單個服務可能具備前面所述的全部優勢,但你須要很是當心地管理羣集。這個系統的部署可能很難,更新可能很難,故障轉移可能也很困難等等。
在許多狀況下,整體收益仍然存在,但重要的是不要輕視或低估管理另外一個龐大而複雜系統的額外複雜性。託管服務可能會有所幫助,但在不少狀況下,這些服務都是新興的不穩定的(例如,Amazon EKS直到在2017年末才宣佈)——誰用誰知道。
只有經過仔細考慮才能避免爲微服務而微服務的瘋狂。爲了幫助解決這個問題,我想了一些你可能想問本身的問題,以及可能的答案:
你能夠在這裏下載PDF副本:https://github.com/dwmkerr/blog/raw/master/2018/microservice-madness/images/microservice-questions.pdf
我故意避免這篇文章中的「a」字。可是,個人朋友Zoltan在校對這篇文章的時候提到了一個很好的觀點。
沒有微服務體系結構。微服務只是組件的另外一種模式或實現,無他。不管是否存在於系統中,都不意味着系統的體系結構獲得瞭解決。
微服務在許多方面與打包和運維的技術過程有關,而不是系統的固有設計。組件的適當邊界仍然是工程系統中最重要的挑戰之一。
不管你的服務是否在Docker容器中,你老是須要仔細考慮如何將系統放在一塊兒。沒有惟一的答案,只有更多的選擇。
我但願你看完這篇文章以爲有趣!一如既往,若是你有任何疑問或想法,請在下面評論便可。
如下連接可能有用:
若是你願意,請分享你認爲值得閱讀或觀看的話題的任何東東!