您花了幾個月的時間將整體架構重新設計為微服務,最後每個人都齊心協力翻轉開關。 您前往第一個網頁...但什麼事也沒發生。 你重新加載它 - 又沒有什麼好處,該網站太慢了,以至於幾分鐘內都沒有響應。 發生了什麼事?
在演講中,Jimmy Bogard 將對現實生活中的微服務災難進行「事後剖析」。 他將展示他發現的建模、開發和生產問題,以及他的團隊如何慢慢地將新的分散整體轉變為理智的最終畫面。 雖然不可能完全防止設計錯誤,但您至少可以在設計過程的早期發現問題,以確保最終產品成為可靠的分散式系統。
大家好,我是吉米,今天您將聽到如何在建立微服務時避免巨大災難。 這是我在一家公司工作了大約一年半的故事,目的是幫助防止他們的船與冰山相撞。 為了正確地講述這個故事,我們必須回到過去,討論這家公司的起源以及它的 IT 基礎設施如何隨著時間的推移而發展。 為了保護這場災難中無辜者的名譽,我已將這家公司的名稱改為貝爾電腦公司。 下一張幻燈片顯示了 90 年代中期此類公司的 IT 基礎設施的樣子。 這是用於經營電腦硬體商店的大型通用容錯 HP Tandem 大型主機伺服器的典型架構。
他們需要建立一個系統來管理所有訂單、銷售、退貨、產品目錄和客戶群,因此他們選擇了當時最常見的大型主機解決方案。 這個龐大的系統包含了公司的每一點訊息,一切可能,每一筆交易都是透過這個主機進行的。 他們把所有的雞蛋都放在一個籃子裡,並認為這是正常的。 這裡唯一不包括的是郵購目錄和透過電話下訂單。
隨著時間的推移,系統變得越來越大,裡面累積了大量的垃圾。 此外,COBOL 並不是世界上最具表現力的語言,因此該系統最終成為一個巨大的、單一的垃圾。 到 2000 年,他們發現許多公司都擁有網站,透過這些網站可以開展所有業務,因此決定建立他們的第一個商業 .com 網站。
最初的設計看起來相當不錯,由一個頂級網站bell.com 和許多用於各個應用程式的子網域組成:catalog.bell.com、accounts.bell.com、orders.bell.com、產品搜尋search.bell 。 com. 每個子域都使用ASP.Net 1.0框架和自己的資料庫,並且它們都與系統後端通訊。 然而,所有訂單繼續在一個巨大的大型主機中處理和執行,所有垃圾都保留在其中,但前端是具有單獨應用程式和單獨資料庫的單獨網站。
所以系統的設計看起來是有序且合乎邏輯的,但實際的系統如下一張投影片所示。
所有元素都涉及彼此的呼叫、存取的 API、嵌入的第三方 dll 等。 版本控制系統經常會抓取別人的程式碼,將其塞入專案中,然後一切都會崩潰。 MS SQL Server 2005使用了連結伺服器的概念,雖然我沒有在投影片上顯示箭頭,但每個資料庫也可以相互通信,因為根據從多個資料庫獲得的資料來建立表格並沒有什麼問題。
由於現在系統的不同邏輯區域之間有一定的分離,因此這變成了分散式的污垢塊,最大的垃圾仍然保留在大型主機後端。
有趣的是,這台大型主機是由貝爾電腦公司的競爭對手建造的,並且仍然由他們的技術顧問維護。 由於確信其應用程式的性能不能令人滿意,該公司決定擺脫它們並重新設計系統。
現有應用程式已投入生產 15 年,這是基於 ASP.Net 的應用程式的記錄。 該服務接受了來自世界各地的訂單,單一應用程式的年收入達到了 XNUMX 億美元。 很大一部分的利潤是由bell.com 網站產生。 黑色星期五期間,透過該網站下的訂單數量達到數百萬。 然而,現有的架構不允許任何開發,因為系統元素的嚴格互連實際上不允許對服務進行任何更改。
最嚴重的問題是無法從一個國家下訂單,在另一個國家付款並將其發送給第三個國家,儘管這種交易方案在跨國公司中非常普遍。 現有的網站不允許這樣做,因此他們必須透過電話接受並下達這些訂單。 這導致該公司越來越多地考慮改變架構,特別是轉向微服務。
他們透過觀察其他公司來看看他們是如何解決類似問題的來做明智的事情。 其中一個解決方案是 Netflix 服務架構,它由透過 API 和外部資料庫連接的微服務組成。
貝爾電腦公司管理階層決定建構這樣一個架構,並遵循某些基本原則。 首先,他們透過使用共享資料庫方法消除了資料重複。 沒有資料被發送;相反,每個需要資料的人都必須去一個集中的來源。 接下來是隔離和自治——每個服務都獨立於其他服務。 他們決定使用 Web API 來完成所有事情 - 如果您想獲取資料或對另一個系統進行更改,這一切都可以透過 Web API 完成。 最後一件大事是名為「Bell on Bell」的新大型主機,而不是基於競爭對手硬體的「Bell」大型主機。
因此,在 18 個月的時間裡,他們圍繞著這些核心原則建立了系統,並將其投入預生產。 週末後返回工作崗位,開發人員聚集在一起,打開了新系統連接的所有伺服器。 18 個月的工作、數百名開發人員、最現代的貝爾硬體 - 但沒有任何積極結果! 這讓很多人感到失望,因為他們已經在筆記型電腦上運行過這個系統很多次了,一切都很好。
他們很聰明,把所有的錢都用來解決這個問題。 他們安裝了最現代化的帶有交換機的伺服器機架,使用了千兆位元光纖,最強大的伺服器硬體以及大量的 RAM,將所有這些連接起來,進行了配置 - 但同樣,什麼也沒有! 然後他們開始懷疑原因可能是超時,所以他們進入了所有的Web設置,所有的API設置,並將整個超時配置更新為最大值,這樣他們所能做的就是坐等事情發生。到該網站。 他們等啊等啊等了9分半鐘,網站終於載入完畢。
後來他們意識到現在的情況需要徹底分析,就邀請了我們。 我們發現的第一件事是,在整個 18 個月的開發過程中,沒有創建任何真正的「微型」——一切都變得更大。 此後,我們開始寫事後剖析,也稱“回顧”,或“悲傷回顧”,也稱“責備風暴”,類似“頭腦風暴”,以了解災難發生的原因。
我們有幾條線索,其中之一是 API 呼叫時流量完全飽和。 當您使用整體服務架構時,您可以立即了解到底出了什麼問題,因為您有一個堆疊追蹤來報告可能導致故障的所有內容。 在一堆服務同時存取同一個 API 的情況下,除了使用 WireShark 等額外的網路監控工具之外,無法追蹤跟踪,借助該工具,您可以檢查單一請求並找出其執行過程中發生的情況。 因此,我們拿了一個網頁,花了近兩週的時間將拼圖的各個部分拼湊在一起,對其進行各種呼叫並分析每個呼叫會導致什麼結果。
看這張圖。 它表明一個外部請求會提示服務進行許多傳回的內部呼叫。 事實證明,每個內部呼叫都會進行額外的躍點以便能夠獨立地服務該請求,因為它無法轉向其他任何地方來獲取必要的資訊。 該圖看起來像是毫無意義的級聯調用,因為外部請求調用附加服務,附加服務又調用其他附加服務,依此類推,幾乎無窮無盡。
圖中的綠色顯示了一個半圓,其中服務相互呼叫-服務A呼叫服務B,服務B呼叫服務C,然後它再次呼叫服務A。結果,我們得到了「分散式死鎖」。 單一請求創建了一千個網路 API 調用,由於系統沒有內建的容錯和循環保護,因此即使其中一個 API 呼叫失敗,請求也會失敗。
我們做了一些數學計算。 每個 API 呼叫的 SLA 不超過 150 毫秒,正常運作時間為 99,9%。 一個請求會引發 200 次不同的調用,在最好的情況下,頁面可以在 200 x 150 毫秒 = 30 秒內顯示。 這自然是不好的。 將 99,9% 的正常運作時間乘以 200,我們得到 0% 的可用性。 事實證明,這個架構從一開始就注定失敗。
我們詢問開發人員,為什麼經過18個月的工作後,他們還沒有意識到這個問題? 事實證明,他們只計算了他們運行的程式碼的 SLA,但如果他們的服務呼叫了另一個服務,他們就不會在 SLA 中計算該時間。 一個進程內啟動的所有內容都遵守 150 毫秒的值,但存取其他服務進程會使總延遲增加許多倍。 從中學到的第一個教訓是:“你控制著你的 SLA,還是 SLA 控制著你?” 就我們而言,就是後者。
我們發現的下一件事是,他們知道彼得·戴奇和詹姆斯·高斯林提出的分散式計算概念的誤解,但他們忽略了它的第一部分。 它指出,「網路可靠」、「零延遲」和「無限吞吐量」等說法是誤解。 其他誤解包括「網路是安全的」、「拓撲永遠不會改變」、「永遠只有一名管理員」、「資料傳輸成本為零」和「網路是同構的」等說法。
他們犯了一個錯誤,因為他們在本地電腦上測試了他們的服務,並且從未連接到外部服務。 在本地開發並使用本地快取時,他們從未遇到過網路躍點。 在全部 18 個月的開發過程中,他們從未想過如果外部服務受到影響會發生什麼。
如果您查看上圖中的服務邊界,您會發現它們都是不正確的。 有很多來源就如何定義服務邊界提供建議,但大多數都做錯了,就像下一張投影片中的 Microsoft 一樣。
這張圖來自MS博客,主題為「如何建立微服務」。 這顯示了一個簡單的 Web 應用程式、一個業務邏輯區塊和一個資料庫。 請求直接來,可能有一台用於Web的伺服器,一台用於業務的伺服器,一台用於資料庫的伺服器。 如果增加流量,情況會有些變化。
這裡有一個負載平衡器,用於在兩個 Web 伺服器之間分配流量,一個快取位於 Web 服務和業務邏輯之間,另一個快取位於業務邏輯和資料庫之間。 這正是 Bell 在 2000 年代中期用於負載平衡和藍/綠部署應用程式的架構。 直到一段時間以來,一切都運作良好,因為該方案是針對整體結構的。
下圖顯示了 MS 如何建議從整體遷移到微服務 - 只需將每個主要服務拆分為單獨的微服務。 正是在這個計畫的實施過程中,貝爾犯了一個錯誤。
他們將所有服務分為不同的層,每個層都包含許多單獨的服務。 例如,Web服務包括用於內容渲染和身份驗證的微服務,業務邏輯服務包括用於處理訂單和帳戶資訊的微服務,資料庫被劃分為一堆具有專門資料的微服務。 Web、業務邏輯和資料庫都是無狀態服務。
然而,這張圖是完全錯誤的,因為它沒有映射公司 IT 集群之外的任何業務部門。 該計劃沒有考慮到與外界的任何联系,因此不清楚如何獲取第三方業務分析等。 我注意到他們也發明了一些服務,只是為了發展個別員工的職業生涯,這些員工試圖管理盡可能多的人,以獲得更多的錢。
他們認為,遷移到微服務就像採用內部 N 層實體層基礎架構並在其上貼上 Docker 一樣簡單。 我們來看看傳統的N層架構是什麼樣子的。
它由4個層次組成:UI使用者介面層、業務邏輯層、資料存取層和資料庫。 更先進的是 DDD(領域驅動設計),即軟體導向的架構,其中兩個中間層是領域物件和儲存庫。
我嘗試著眼於這個架構中不同的變化領域和不同的責任領域。 在典型的 N 層應用程式中,不同的變更區域被分類,從上到下垂直滲透到結構中。 這些是在單一電腦上執行的目錄、配置設定以及結帳檢查,這些由我的團隊處理。
該方案的奇特之處在於,這些變化區域的邊界不僅影響業務邏輯層面,也延伸到資料庫。
讓我們看看服務意味著什麼。 服務定義有 6 個特徵屬性 - 它是軟體:
- 由特定組織創建和使用;
- 負責系統內某種類型資訊的內容、處理和/或提供;
- 可獨立建置、部署和運行,以滿足特定的營運需求;
- 與消費者和其他服務溝通,根據協議或合約保證提供資訊;
- 保護自身免受未經授權的訪問,並防止其資訊遺失;
- 以不會導致訊息損壞的方式處理故障。
所有這些屬性都可以用一個字「自治」來表達。 服務彼此獨立運行,滿足某些限制,並定義人們可以接收所需資訊的基礎上的合約。 我沒有提及具體技術,其用途是不言而喻的。
現在我們來看看微服務的定義:
- 微服務規模較小,旨在解決一個特定問題;
- 微服務是自治的;
- 在創建微服務架構時,會使用城市規劃的比喻。 這是 Sam Newman 的書《建構微服務》中的定義。
有界脈絡的定義取自 Eric Evans 的《領域驅動設計》一書。 這是 DDD 的核心模式,DDD 是一個架構設計中心,它使用體積架構模型,將它們分成不同的有界上下文,並明確定義它們之間的交互作用。
簡單地說,有界上下文表示可以使用特定模組的範圍。 在此上下文中是一個邏輯上統一的模型,例如在您的業務領域中可以看到該模型。 如果你問負責訂單的人員“誰是客戶”,你會得到一個定義,如果你問負責銷售的人員,你會得到另一個定義,表演者會給你第三個定義。
因此,有界上下文說,如果我們無法給出服務的消費者是什麼的明確定義,那麼讓我們定義我們可以討論這個術語的含義的邊界,然後定義這些不同定義之間的過渡點。 也就是說,如果我們從下訂單的角度來談論客戶,這意味著這個和那個,如果從銷售的角度來說,這意味著這個和那個。
微服務的下一個定義是封裝任何類型的內部操作,防止工作流程的元件「洩漏」到環境中。 接下來是“外部互動或外部通訊的顯式契約的定義”,它以從 SLA 返回的契約的思想為代表。 最後一個定義是一個單元或單元的隱喻,這意味著微服務中一組操作的完整封裝以及其中存在與外界通訊的接收器。
因此,我們對貝爾電腦公司的員工說:「我們無法修復你們造成的任何混亂,因為你們沒有錢去做這件事,但我們只會修復一項服務,讓這一切都變得簡單。」感覺。” 現在,我將首先告訴您我們如何修復我們唯一的服務,使其回應請求的速度超過 9 分半鐘。
22:30 分鐘
很快就會繼續......
有點廣告
感謝您與我們在一起。 你喜歡我們的文章嗎? 想看更多有趣的內容? 通過下訂單或推薦給朋友來支持我們,
Dell R730xd 在阿姆斯特丹的 Equinix Tier IV 數據中心便宜 2 倍? 只有這裡
來源: www.habr.com