您的微服務是否過於瑣碎?ironSource分享如何避免微服務帶來的細粒度複雜性 -新堆疊

banq發表於2019-11-14

如何將應用程式分解為細粒度的微服務會帶來可能最終導致巨大災難的複雜性,以及如何避免這種情況。

在ironSource,我們與面向服務的體系結構(SOA)一起工作,該體系已經存在了數十年,並且已經接受了其最新的迭代-微服務。使用微服務方法進行應用程式開發使我們能夠提高彈性並縮短上市時間。當我們將整個應用程式堆疊分解成小塊時,它更易於開發,測試,部署,最重要的是更改和維護。

也就是說,將應用拆分為多個較小的單元並不意味著一切都可以立即正常執行。去年,我們觀察到了幾個服務可用性問題,經過大量調查,我們意識到要避免這些問題,以特定方式實現微服務很重要。在我們的研究過程中,我們發現並減輕了一些不良做法,以防止可能的世界末日場景。在本文中,我將深入探討一種技術,這些技術已幫助我們的研發團隊享受微服務的全部好處,從而使他們在晚上睡個好覺。

我的服務是否彼此耦合?

傳統的“請求驅動”架構(例如REST)是最簡單,最常見的服務通訊模式(例如,服務A向服務B詢問一些資訊並等待。服務B隨後作出響應並將資訊傳送給服務A)。

使用HTTP API是開發人員學習和常用的基本知識之一。很顯然,當收到並確認的請求由相應的服務,並有大量的工具來除錯HTTP的API。因此,這是我們跨系統服務之間進行通訊的預設方法。“請求驅動”通訊的簡單性為我們快速移動,提供新功能以及擴充套件我們的系統以滿足所有需求提供了很好的幫助。

不幸的是,這種模式導致服務緊密耦合。在小型系統中,它執行得很好,但是對於由數十種服務構建的應用程式而言,這種耦合會阻礙開發敏捷性並阻止快速擴充套件。

使用此模式時要注意的主要風險是每個“核心”服務,都將可能成為單個故障點。這意味著,它可能會造成效能瓶頸,或者更糟的是,依賴服務的停機時間。因此,整個依賴鏈都被打亂了(即大災難)。聽起來似乎很容易解決,但是新增到鏈中的每個服務都需要一個服務發現機制(甚至大型系統中的服務網格),故障轉移/重試,斷路器,超時和快取機制到位,端到端完美地工作是一個巨大的挑戰。

實際上,在整個系統上使用諸如REST之類的同步通訊使其表現得像一個整體,或者更確切地說是一個分散式整體,從而無法享受微服務的全部好處

為了消除混亂,在IronSource,我們正在移動許多核心服務以使用非同步事件驅動的體系結構進行通訊。我們的方法是讓我們的核心服務在資訊更新時釋出其提供的資訊,而不是等待其他服務請求該資訊。通過使用“推”而不是“拉”,我們的系統可以實時處理資料。現在,我們可以處理許多複雜的快取管理和清除機制,服務發現和重試技術,這些技術用於在使用同步服務通訊時維護系統的可靠性和效能。

而且,服務現在可以非同步地將事件釋出到彈性訊息代理(在我們的例子中為Kafka)。他們信任經紀人將訊息路由到正確的服務,並且接收方訂閱了他們感興趣的關鍵事件。新增訂閱者很容易,這樣就不會給釋出者服務帶來更多負擔。

為什麼選擇Kafka呢?

我們選擇Kafka是因為它非常有彈性且可靠。它具有強大的社群和文件資源。與其他訊息代理不同,Kafka使我們能夠以高度可用的方式複製資料並控制資料保留策略,因此即使事件被多個使用者使用後也可以保留。事件會根據保留策略在流中自動過期。因此,如果您正在使用事件源,並且想從事件日誌中重現狀態,則它可以用作持久儲存源,從中重建當前和過去的狀態。此外,Kafka為流和實時聚合(使用KSQL)等高階方案提供了本地支援,並與我們基礎架構中的許多元件(例如Spark流,Cassandra,Elasticsearch,S3,

在非同步通訊中,一個服務可能仍然依賴於另一個服務,這意味著各方之間的API和依賴關係仍然存在。但是,如果一項服務失敗或過載並且響應速度很慢,它將不會影響其他服務,因為它們現在彼此鬆散耦合並且包含了它們需要響應的所有內容。

因此,公共事件匯流排的好處在於,它消除了我們的核心服務同步通訊時出現的單點故障和效能瓶頸-例如,佇列仍可以保留髮送到服務B的訊息,直到訊息備份並能夠使用它們為止。 。

這導致我們遵循“單跳”規則:

預設情況下,除非在特殊情況下,否則服務不應呼叫其他服務來響應請求。

服務應該是自包含的,並管理自己的資料。允許服務呼叫其他服務會增加請求的開銷,並可能導致服務非常緩慢或無響應。如果您發現需要在多個服務之間來回撥用,則建議您探索使用非同步事件驅動模式還是將這些服務合併為一個(微型元件)服務可以為您提供更健康的服務。

當然,每個規則都有例外。在某些情況下,您需要做出明智的決定,以便在服務之間進行同步通訊以響應請求。

例如,同步通訊的一種典型情況是擁有一個集中的身份驗證服務,該服務從多個面向使用者的API獲取同步伺服器呼叫,以驗證和驗證使用者令牌。身份驗證服務的分離在開發和部署方面釋放了敏捷性,為需要身份驗證的任何服務建立了高度的凝聚力,並使團隊可以獨立高效地工作。此外,分離為身份驗證服務和其他使用該服務的其他服務啟用了不同的自動縮放模式和資源分配。最重要的是,它使您能夠同步阻止任何未通過身份驗證的使用者請求。

等待,如果事件匯流排變成單點故障該怎麼辦?

在使用事件匯流排來消除系統內的故障點的同時,您可能會擔心事件匯流排本身是否是單點故障。好吧,繼續做您為了增強健壯性和擴充套件性而總是做的事情:分發它,部署事件匯流排的多個例項以實現高可用性,並弄清楚是否需要重試。使用Kafka,您將獲得許多選項和配置,以對其進行調整以實現高可用性。如果您有多個不同的用例和高負載,我的建議是考慮旋轉多個叢集,甚至考慮在多個資料中心上部署叢集(使用主動-主動或主動-被動拓撲)。考慮到這一點,我建議檢查如果完全丟失事件匯流排會發生什麼情況。雖然結果似乎很明顯,實際上,您測試的不僅僅是故障,還測試了恢復。瞭解系統如何應對故障對於確保彈性至關重要。

全部放在一起

我們的服務現在正在發出事件,從而導致事實日誌:

  1. 可重現:可以通過重播事件日誌來重現系統在給定時間點的狀態。
  2. 冗餘:使用Kafka對日誌進行分割槽和複製以實現高可用性。
  3. 與任何特定的資料儲存區分離:事件通常使用JSON,Avro等格式進行序列化。
  4. 不變的:一旦發出事件,就無法更改。

該日誌使我們能夠通過處理事件(即事件溯源)來重構當前和過去的狀態。事實的唯一來源成為儲存事件的資料儲存庫。消耗日誌中資料的每個服務都變得獨立,不再與任何微服務集(無論它們處於啟動,關閉還是緩慢)耦合。從同步依賴項取消連結服務改善了我們的故障隔離,並且我們的系統幾乎不受單個模組故障的影響。整體可靠性和效能提高了,這對我們的業務來說是一個巨大的勝利。

下一步是什麼?

我們已經將我們的應用程式細分為細粒度的微服務,我們在所有內容的中間放置了一個彈性事件匯流排,以協調通訊,並使每個服務都是獨立的。我們甚至將我們的團隊組織成“小隊”或足夠小的團隊,以便可以用兩個比薩餅來餵養他們。在本系列的下一篇文章中,我們將處理可能引起危險訊號的其他問題:

  1. 對一種微服務的更改是否需要對其他微服務的更改?
  2. 微服務部署是否需要同時部署其他微服務?
  3. 是否有一個開發人員團隊來處理大量微服務?
  4. 微服務是否共享很多相同的程式碼或模型?

 

相關文章