您的位置:首頁>正文

2018 瘋狂微服務之死

近期微服務的話題非常火爆, 有時可謂非常“瘋狂”:

Netflix 在 devops 上做得很棒, 同時 Netfix 也採用微服務。 因此:如果我也用微服務, 那麼我也可以在 devops 方面做得很好。

很多情況下, 為了解決手頭的問題, 我們付出了巨大的努力採用微服務模式, 但是並不清楚它的成本和收益。

接下來我將詳細介紹什麼是微服務, 這種模式吸引人的原因, 以及它所面臨的主要挑戰。

如果你正在考慮微服務是否適合你的模式, 我會在文章的最後用一系列簡單的問題來幫你做出選擇。

什麼是微服務, 它為什麼如此受歡迎?

首先從最基本的開始瞭解。

下圖是一個假想的視頻共用平臺的實現方式, 左側是傳統的整體式架構(單個巨型單元), 右側則是微服務:

兩種模式的區別在於第一種是整體式架構, 只有一個大單元。 第二種則由多個小單元構成, 每個小單元都是獨立的服務。

上圖已足夠細緻,

從中很容易找到微服務模式的吸引力所在。 以下是微服務架構的具體好處:

獨立開發:小型的獨立組件可由小型的獨立團隊構建。 一個小組可以專門負責開發“Upload”服務, 不用去管其他服務。 每個元件的功能變得簡單, 這樣一來, 開發人員瞭解元件的時間大大減少, 更容易開發新功能。

獨立部署:每個單獨的元件都可以獨立部署。 這樣一來發佈新功能的速度就更快, 風險也更小。 假設“Streaming”組件修復了 bug 或者新增了功能, 那麼部署時並不會影響其他組件。

獨立擴展:每個元件可以獨立地進行擴展。 在新節目剛發佈的繁忙時期, 可以擴展“Download”元件, 以支援增加的負載, 而不必擴展所有組件, 這樣一來擴展更具彈性並且降低了成本。

再使用性:每個元件各自實現一個小的、特定的功能。 這意味著它們可以很容易地適用於其他系統、服務或者產品。 “Transcode”元件可以被其他業務單元使用, 甚至可以改寫成一個新的業務, 從而為其他組提供轉碼服務。

從以上細節層面可見, 微服務模式相比整體式架構的好處顯而易見。 如果確實是這樣的話——那為什麼這種模式最近才開始流行呢?

既然微服務好處多多, 為什麼沒有很早就開始流行呢?

原因有二。 第一個原因是它提升了我們的技術能力, 另一個是最近的技術進步讓我們能夠把它帶到一個新的水準。

當我開始寫這個問題的答案時, 發現一兩句話無法解釋清楚, 所以實際上我把它分成了另外一篇文章,

稍後再發表。 因此在本文中, 我將跳過從單個程式到多個程式的過程, 忽略 ESBs 和面向服務的體系結構、元件設計以及有限的上下文等內容。

在很多方面我們已經開始使用微服務, 隨著近期容器技術(特別是 Docker)和集群技術(如 Kubernetes、Mesos、Consul 等等)的普及, 從技術的角度來看, 微服務模式變得更加可行。

如果我們打算實施微服務, 那麼在開始之前需要想清楚。 從理論的角度我們看到了它的優點, 那麼它有沒有弊端呢?

微服務有什麼問題?

微服務模式優點多多, 那麼它的缺點是什麼呢?據我所知它主要有下列問題。

開發的複雜性增加

對於開發者來說事情會變得更加困難。 當開發人員開發一個新功能時, 如果該功能依賴其他服務的話, 那麼開發人員不得不在他們的機器上運行所有服務,

或者連接到這些服務。 這通常比簡單地運行單個程式更加複雜。

這個問題可以通過一些工具得到部分緩解, 但隨著構成系統的服務數量的增加, 開發人員在整個系統運行時面臨的挑戰也越來越多。

運營的複雜性增加

對於維護服務的團隊來說, 潛在的複雜性是一個巨大的挑戰。 他們管理的服務不是簡單的幾個, 而是數十、數百甚至數千個正在運行的服務。 服務數量越多, 通信鏈路就越多, 那麼出錯的可能性就會變大。

devops 的複雜性增加

以上兩點表示開發和運營是分開進行的, 隨著 devops 的普及(我是 devops 的忠實粉絲), devops 能夠緩解這個問題嗎?

如今有許多組織仍然依靠獨立的開發和運營團隊來工作, 而也有一些組織更傾向於採用微服務。

對於已經採用了devops 的組織來說,這仍然很難。既是開發者又是運營者已經非常艱難(但是要建立好的軟體卻很關鍵)了,還得瞭解集群容器系統的細微差別,特別是快速發展的系統,那就更困難了。

它需要資深專家

如果開發團隊成員都是專家級別,那麼結果可能會很好。但想像一下,一個使用單一的整體式系統運行的不是很順暢。如果增加系統的數量,就會增加運行的複雜性。

通過有效的自動化、監控和集群等技術可以做到。但瓶頸很少在於技術本身,而在於找到能夠有效使用這些技術的人。目前這些技能需求非常高,可能很難找到。

真實世界的系統往往界限不清

當我們描述微服務的好處時,經常談到獨立的元件。但是在很多情況下,元件並不是獨立的。在論文中,某些領域可能看起來有限,但是當你深入細節時,你會發現他們比你預期的更具挑戰性。

事情變得非常複雜。如果你的界限沒有明確的定義,那麼即使理論上的服務可以單獨部署,你也會發現,由於服務之間的相互依存關係,你必須部署一組服務。

這意味著你需要一系列管理協同工作的服務版本,這些服務版本之間的協作需要通過驗證和測試,你實際上沒有可獨立部署的系統,為了部署新功能,你需要仔細編排並同時部署許多服務。

狀態的複雜性往往被忽略

在前面的例子中,我提到一個功能的部署可能需要同時部署多個版本的多個服務。假設合理的部署技術可以緩解這種情況,例如 blue/green 部署(大多數服務編排平臺可輕鬆應對),或者並行運行的多個服務版本,以及決定使用哪個版本的通道。

如果服務是無狀態的,這些技術可以緩解大量的挑戰。但是無狀態服務非常容易處理。事實上,如果你有無狀態的服務,那麼我會傾向於考慮跳過微服務,而考慮使用無伺服器模型。

實際上,大多數服務都需要狀態。比如我們的視頻共用平臺例子中的訂閱服務。新版的訂閱服務可以用新的形式將資料存儲在訂閱資料庫中。如果你並行運行兩個服務,則一次運行了兩個模式的系統。如果你進行了 blue green 部署,而其他服務依賴於新的資料,那麼必須同時更新這些服務,如果訂閱服務部署失敗並回滾,則需要層級回滾。

你可能會認為在 NoSQL 資料庫中這些問題不存在,但事實並非如此。不強制執行模式的資料庫並不意味著它是無模式系統 - 它僅僅意味著模式在應用級而不是資料庫級進行管理。理解資料的形狀及其演變過程的挑戰依然存在。

通信的複雜性往往被忽略

當你建立一個相互依賴的大型網路服務時,可能會涉及到很多服務間的通信,挑戰隨之而來。首先,潛在的失敗無處不在。假設網路調用失敗了,那麼當一個服務調用另一個服務失敗時,它至少應當重試幾次。服務之間的調用關係越多,那麼情況將變得愈加複雜。

假設使用者上傳視頻到共用服務中。那麼我們需要運行上傳服務,然後將資料傳遞到轉碼服務,此外,還得更新訂閱和推薦服務。所有這些調用都需要一定程度的協調,如果失敗,就得重試。

而重試邏輯可能很難管理。同步運行往往不是很穩定,很容易失敗。在這種情況下,更可靠的解決方案是使用非同步模式來處理通信。此處面臨的挑戰是非同步模式會使系統具有狀態性。如前所述,分散式系統和狀態系統很難處理。

當一個微服務系統使用訊息佇列進行服務內通信時,基本上會有一個大的資料庫(訊息佇列或代理)將這些服務粘合在一起。雖然起初看起來似乎沒什麼問題,但模式始終是一個隱患。新版本的服務可能會寫入新的格式的消息,當發送服務更改發送消息的詳細資訊時,依賴於該消息的服務也需要更新。

當然可以擁有多個不同格式的消息處理服務,但數量一多就很難管理。當部署一個新版本的服務時,兩個不同版本的服務可能會處理來自同一佇列的消息,儘管消息來自不同版本的發送服務。這可能會導致複雜的邊緣情況。為了避免這些邊緣情況的產生,最好是只允許特定版本的消息存在,這意味著你需要將一組服務的版本作為一個整體來部署,以確保先前版本的消息被適當地排除。

這再次表明,當你深入細節時會發現獨立部署的想法可能與預期的有所差異。

版本控制變難

為了緩解前面提到的問題,我們需要謹慎管理版本。遵循像 semver 這樣的標準能夠解決這個問題嗎?答案是否定的。Semver 是一個利器,但是你仍然需要跟蹤協同工作的服務和 API 的版本。

這件事頗具挑戰,你可能自己都搞混,不知道哪個版本的服務可以一起正常工作。

在軟體系統中管理依賴關係是非常困難的,無論是節點模組、Java 模組、C 庫還是其他東西。獨立元件和單一整體之間的衝突很難處理。

當依賴關係是靜態,並且能夠進行修補、更新、編輯的時候,挑戰在所難免。但是如果依賴關係本身是即時服務,那麼你可能無法僅僅更新它們 - 你可能需要運行許多版本,或者直到整個系統得到修復。

分散式事務

在需要跨操作交易完整性的情況下,微服務可能會非常痛苦。分散式狀態很難處理,很多小的失敗單元可能會很難進行集群操作。

可以通過操作冪等性、重試機制等方法來避免這個問題,這些手段在許多情況下能夠起作用。但有些情況你需要保證操作的事務性,要麼成功,要麼失敗,而不能處於失敗和成功的中間狀態。在微服務模型中想要解決這個問題或者實現事務難度是很大的。

微服務可能是一種變相的整體式模型

單獨的服務和元件可以獨立部署,但是在大多數情況下,你將不得不運行某種集群平臺,比如 Kubernetes。如果你使用穀歌的 GKE 或者亞馬遜的 EKS 這樣的託管服務,它們會幫你完成複雜的集群管理。

但是,如果你自己管理集群的話,那麼面對的是一個龐大而複雜的系統。雖然單個服務擁有前文提到的大量優點,但是你依然需要非常小心。這個系統的部署、更新、容錯移轉等等操作起來都不是那麼簡單。

在大多數情況下,優點能夠得到體現,但是任然不要輕視或低估管理一個龐大而複雜的系統的難度。託管服務可能會有所説明,但這些服務大都剛剛新起(例如,亞馬遜的 EKS 在2017年底才發佈)。

微服務的狂熱將開始降溫

仔細考慮避免加入對微服務的狂熱追捧。為了幫助解決這個問題,我已經注意到了一些你可能想問自己的問題,並列舉了問題的答案:

點擊下載 PDF 版本:microservice-questions.pdf(https://github.com/dwmkerr/blog/raw/master/2018/microservice-madness/images/microservice-questions.pdf)。

不要把微服務和架構混淆

沒有微服務架構一說。微服務只是元件的另一種模式或實現。不論微服務是否在系統中使用,它都與架構無關。

微服務在許多方面與打包和操作的技術過程有關,而與系統設計無關。元件邊界仍然是工程系統中最重要的挑戰之一。

無論你的服務體量有多大,是否在 Docker 容器中,你都需要仔細考慮如何將系統放在一起。這裡沒有標準答案,只是多一個選擇而已。

原文:The Death of Microservice Madness in 2018

連結:http://www.dwmkerr.com/the-death-of-microservice-madness-in-2018/

作者:dwmkerr

譯者:安翔

而也有一些組織更傾向於採用微服務。

對於已經採用了devops 的組織來說,這仍然很難。既是開發者又是運營者已經非常艱難(但是要建立好的軟體卻很關鍵)了,還得瞭解集群容器系統的細微差別,特別是快速發展的系統,那就更困難了。

它需要資深專家

如果開發團隊成員都是專家級別,那麼結果可能會很好。但想像一下,一個使用單一的整體式系統運行的不是很順暢。如果增加系統的數量,就會增加運行的複雜性。

通過有效的自動化、監控和集群等技術可以做到。但瓶頸很少在於技術本身,而在於找到能夠有效使用這些技術的人。目前這些技能需求非常高,可能很難找到。

真實世界的系統往往界限不清

當我們描述微服務的好處時,經常談到獨立的元件。但是在很多情況下,元件並不是獨立的。在論文中,某些領域可能看起來有限,但是當你深入細節時,你會發現他們比你預期的更具挑戰性。

事情變得非常複雜。如果你的界限沒有明確的定義,那麼即使理論上的服務可以單獨部署,你也會發現,由於服務之間的相互依存關係,你必須部署一組服務。

這意味著你需要一系列管理協同工作的服務版本,這些服務版本之間的協作需要通過驗證和測試,你實際上沒有可獨立部署的系統,為了部署新功能,你需要仔細編排並同時部署許多服務。

狀態的複雜性往往被忽略

在前面的例子中,我提到一個功能的部署可能需要同時部署多個版本的多個服務。假設合理的部署技術可以緩解這種情況,例如 blue/green 部署(大多數服務編排平臺可輕鬆應對),或者並行運行的多個服務版本,以及決定使用哪個版本的通道。

如果服務是無狀態的,這些技術可以緩解大量的挑戰。但是無狀態服務非常容易處理。事實上,如果你有無狀態的服務,那麼我會傾向於考慮跳過微服務,而考慮使用無伺服器模型。

實際上,大多數服務都需要狀態。比如我們的視頻共用平臺例子中的訂閱服務。新版的訂閱服務可以用新的形式將資料存儲在訂閱資料庫中。如果你並行運行兩個服務,則一次運行了兩個模式的系統。如果你進行了 blue green 部署,而其他服務依賴於新的資料,那麼必須同時更新這些服務,如果訂閱服務部署失敗並回滾,則需要層級回滾。

你可能會認為在 NoSQL 資料庫中這些問題不存在,但事實並非如此。不強制執行模式的資料庫並不意味著它是無模式系統 - 它僅僅意味著模式在應用級而不是資料庫級進行管理。理解資料的形狀及其演變過程的挑戰依然存在。

通信的複雜性往往被忽略

當你建立一個相互依賴的大型網路服務時,可能會涉及到很多服務間的通信,挑戰隨之而來。首先,潛在的失敗無處不在。假設網路調用失敗了,那麼當一個服務調用另一個服務失敗時,它至少應當重試幾次。服務之間的調用關係越多,那麼情況將變得愈加複雜。

假設使用者上傳視頻到共用服務中。那麼我們需要運行上傳服務,然後將資料傳遞到轉碼服務,此外,還得更新訂閱和推薦服務。所有這些調用都需要一定程度的協調,如果失敗,就得重試。

而重試邏輯可能很難管理。同步運行往往不是很穩定,很容易失敗。在這種情況下,更可靠的解決方案是使用非同步模式來處理通信。此處面臨的挑戰是非同步模式會使系統具有狀態性。如前所述,分散式系統和狀態系統很難處理。

當一個微服務系統使用訊息佇列進行服務內通信時,基本上會有一個大的資料庫(訊息佇列或代理)將這些服務粘合在一起。雖然起初看起來似乎沒什麼問題,但模式始終是一個隱患。新版本的服務可能會寫入新的格式的消息,當發送服務更改發送消息的詳細資訊時,依賴於該消息的服務也需要更新。

當然可以擁有多個不同格式的消息處理服務,但數量一多就很難管理。當部署一個新版本的服務時,兩個不同版本的服務可能會處理來自同一佇列的消息,儘管消息來自不同版本的發送服務。這可能會導致複雜的邊緣情況。為了避免這些邊緣情況的產生,最好是只允許特定版本的消息存在,這意味著你需要將一組服務的版本作為一個整體來部署,以確保先前版本的消息被適當地排除。

這再次表明,當你深入細節時會發現獨立部署的想法可能與預期的有所差異。

版本控制變難

為了緩解前面提到的問題,我們需要謹慎管理版本。遵循像 semver 這樣的標準能夠解決這個問題嗎?答案是否定的。Semver 是一個利器,但是你仍然需要跟蹤協同工作的服務和 API 的版本。

這件事頗具挑戰,你可能自己都搞混,不知道哪個版本的服務可以一起正常工作。

在軟體系統中管理依賴關係是非常困難的,無論是節點模組、Java 模組、C 庫還是其他東西。獨立元件和單一整體之間的衝突很難處理。

當依賴關係是靜態,並且能夠進行修補、更新、編輯的時候,挑戰在所難免。但是如果依賴關係本身是即時服務,那麼你可能無法僅僅更新它們 - 你可能需要運行許多版本,或者直到整個系統得到修復。

分散式事務

在需要跨操作交易完整性的情況下,微服務可能會非常痛苦。分散式狀態很難處理,很多小的失敗單元可能會很難進行集群操作。

可以通過操作冪等性、重試機制等方法來避免這個問題,這些手段在許多情況下能夠起作用。但有些情況你需要保證操作的事務性,要麼成功,要麼失敗,而不能處於失敗和成功的中間狀態。在微服務模型中想要解決這個問題或者實現事務難度是很大的。

微服務可能是一種變相的整體式模型

單獨的服務和元件可以獨立部署,但是在大多數情況下,你將不得不運行某種集群平臺,比如 Kubernetes。如果你使用穀歌的 GKE 或者亞馬遜的 EKS 這樣的託管服務,它們會幫你完成複雜的集群管理。

但是,如果你自己管理集群的話,那麼面對的是一個龐大而複雜的系統。雖然單個服務擁有前文提到的大量優點,但是你依然需要非常小心。這個系統的部署、更新、容錯移轉等等操作起來都不是那麼簡單。

在大多數情況下,優點能夠得到體現,但是任然不要輕視或低估管理一個龐大而複雜的系統的難度。託管服務可能會有所説明,但這些服務大都剛剛新起(例如,亞馬遜的 EKS 在2017年底才發佈)。

微服務的狂熱將開始降溫

仔細考慮避免加入對微服務的狂熱追捧。為了幫助解決這個問題,我已經注意到了一些你可能想問自己的問題,並列舉了問題的答案:

點擊下載 PDF 版本:microservice-questions.pdf(https://github.com/dwmkerr/blog/raw/master/2018/microservice-madness/images/microservice-questions.pdf)。

不要把微服務和架構混淆

沒有微服務架構一說。微服務只是元件的另一種模式或實現。不論微服務是否在系統中使用,它都與架構無關。

微服務在許多方面與打包和操作的技術過程有關,而與系統設計無關。元件邊界仍然是工程系統中最重要的挑戰之一。

無論你的服務體量有多大,是否在 Docker 容器中,你都需要仔細考慮如何將系統放在一起。這裡沒有標準答案,只是多一個選擇而已。

原文:The Death of Microservice Madness in 2018

連結:http://www.dwmkerr.com/the-death-of-microservice-madness-in-2018/

作者:dwmkerr

譯者:安翔

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示