改善十年應用的部署體驗

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 2018 年,Etsy 將它的服務基礎設施從自我管理的數據中心遷移到雲端配置(我們當時在博客上寫了這件事)。這種改變提供了改善整個公司技術流程的機會。對於 Search 團隊而言,雲環境所帶來的靈活擴展讓我們可以完全重新評估一個有些繁瑣的部署流程。在已有的金絲雀發佈架構模式的啓發下,我們編寫了一個新的自定義工具來補充現有的部署基礎設施。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在三個月的努力之後,我們最終得到了一個更具可擴展性、對開發人員更友好、最終也是更健壯的方式來滾動發佈對 Search 的改變。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"藍綠部署"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"過去,我們把堆棧部署到兩套獨立的主機上,也就是所謂的“藍綠策略”。在任何時候,只有一組主機是活動的;而另一組,或 \"側端\"則處於“黑暗”狀態。這兩邊都是完全擴展的,並準備好爲流量提供服務,但只有活動的那一組可以進入公共互聯網。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"藍綠部署策略雖然簡單,但具有一些非常有用的特性:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於搜索應用,我們可以在一邊做重要的改變,因爲它是有狀態的,同時持續地使用另一邊來提供流量。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在將生產流量發送到它之前,我們有地方可以手動測試更改。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們總是有一個以前的 Search 版本,在緊急情況下,我們可以輕鬆恢復。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有一個內置的機制,可以測試和產生其他突破性的變化,比如軟件版本升級。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們將這兩組主機稱爲“flip”和“flop”,這是以現代計算機的基本構件——電路命名的。在配置文件中,我們通過幾行代碼,將單個 PHP Web 應用指向哪一組,哪一組就應該處於活動狀態。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/69\/95\/693902ef68d7a288437c9bbd8d1c2f95.jpg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"圖爲我們之前的基礎設施。一組(本例中的 flop)始終處於活動狀態,在部署過程中,我們會將所有的流量一次性轉移到另一組(本例中的 flip)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"三年前,Etsy 向雲端遷移時,這種藍綠部署的方法被“提升和轉移”。Search 團隊將搜索應用移至谷歌 Kubernetes 引擎(Google Kubernetes Engine,GKE),flip 和 flop 成爲兩個獨立的生產 Kubernetes 命名空間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"撇開這一變化不談,事情的運作與以往一樣:部署 Search 會立即觸發所有的流量從一個命名空間——活動端——重定向到另一個命名空間中運行的同一服務。爲了確保黑暗端始終準備就緒,我們將繼續在任何時候都保持 200% 的容量(每個生產命名空間 100%),正如我們在企業內部時所做的那樣。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種最初的部署策略對團隊來說非常有用,尤其是爲我們提供了一個安全的空間,可以測試和準備主要的軟件更新和基礎設施變更。然而,它也並非沒有痛苦。突然間,所有流量都被轉移到兩邊,這使得我們沒有餘地在全部投入之前測試少量生產流量的變化。甚至在一切順利的時候,部署也是充滿壓力的。如果情況出了問題,工程師們就得進行分流,來決定是否要完全恢復原狀。最重要的是,長時間維持雙倍容量既昂貴又低效。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲雲計算提供了靈活性,一旦我們安全地進入 GKE,我們就有機會重新考慮我們的藍綠策略,並解決這些長期存在的問題。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"金絲雀(精簡版)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們的第一個想法是採用金絲雀部署策略。在“金絲雀發佈”期間,在將所有流量切換到新服務之前,將一小部分流量發送到服務的新版本,以確定它是否 “安全”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲什麼叫這個名字?煤礦工人曾經使用金絲雀來檢測一氧化碳的濃度,這種濃度可能會傷害一隻小鳥,但仍不會對人造成傷害。軟件工程師們也採取了類似的模式(儘管更加人性化),以樹立新軟件能夠安全地服務於流量的信心。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然 Kubernetes 的架構和靈活的擴展意味着金絲雀發佈是一個非常流行的部署解決方案,但是 Etsy 的搜索系統的設計意味着我們不能使用任何現成的金絲雀發佈解決方案。我們必須爲自己建造一些新的東西,一種金絲雀精簡版。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在考慮重新構建整合金絲雀組件的部署流程時,存在兩個關鍵的限制。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一個限制是,我們不能使用單一的負載均衡器活 API 斷電來控制流入流量的數量。這樣,我們就不能使用 Kubernetes 標籤在單個 Kubernetes 部署上爲任何搜索服務做基本的金絲雀發佈,因爲 Search 是由許多不同的 Kubernetes 部署組成的。我們沒有地方來設置路由邏輯來檢查標籤,以及相應的路由到金絲雀 Pod。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,Etsy 的 PHP Web 應用是搜索應用的唯一客戶端。對於 Etsy,這是一種常見模式,因此,配置負載平衡通常是直接在 Web 應用本身中進行管理。任何新的部署解決方案或者必須對 Web 應用管理流量到 web 應用內部的 Search,或者實現某種全新的網狀網絡(比如 Istio),捕獲並引導 Web 應用到 Search 的所有流量。這兩個方案在分配給該項目的時間範圍內都不可行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二個限制是,搜索應用假定請求路徑中所有搜索服務的相同版本都會爲任何單一 Web 請求服務。所以,任何新解決方案的部署都需要確保所有搜索服務的舊版本都能滿足正在進行的搜索請求。甚至像 Istio 這樣複雜的金絲雀發佈解決方案,也要求你的應用處理不同服務之間的版本不匹配,這是我們無法保證的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼,我們如何爲所有新版本的搜索服務創建一個逐步推出的過程,同時管理從 Web 應用到滾動發佈的所有部分的負載平衡,並保證搜索服務只能和其他搜索服務的相同版本對話?對於這種 Etsy 特定問題,沒有現成的解決方案。因此我們開發了一種全新的工具,叫做 Switchboard。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"走入 Switchboard"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Switchboard 的主要功能是管理流量:它通過逐步增加提供給新的活動端的百分比,並按比例減少進入舊的活動端的數量,將一個部署滾動發佈到生產。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有預先定義的流量比例的部署階段被硬編碼到系統中,當在當前滾動發佈階段中添加的所有 Pod 都完全創建並正常運行時,Switchboard 就會過渡到下一個階段。這是通過編輯和提交新的流量比例到 Web 應用中的配置文件來實現這一目標的。Web 應用對每一個心情求都重新檢查這個文件,並使用這些信息在兩個不同的生產 Kubernetes 命名空間之間進行負載均衡搜索流量,這兩個命名空間仍然被稱爲 flip 和 flop。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/46\/81\/463a22bf6455643540yycc0e156cb481.jpg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"使用 Switchboard 的一端開關的例子。Smoke 測試在 16:57 和 17:07 進行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Switchboard 在部署過程中很大程度上實現了流量從一個搜索端到另一個搜索端的自動遷移。Smoke 測試在部署的不同階段運行,向新的一端發送人工創建的和真實的歷史搜索查詢請求。開發人員只需監控圖表,以確保滾動發佈的工作順利進行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/4b\/0c\/4be7c0bdc479a2ae75fb2b361c5bc50c.jpg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"推動部署的工程師通過顯示當前滾動發佈狀態的用戶界面來管理 Switchboard,它還可以選擇暫停或者回滾部署。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Switchboard 中,我們主要依靠 Kubernetes 內置的自動伸縮功能來擴展部署期間的新集羣。在開始向集羣發送生產流量之前,我們已經發現,我們只需要先將集羣的規模擴大到我們當前容量的 25%。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Kubernetes 內置的自動伸縮是被動的,因此與我們強制 Search 在需要額外容量之前進行伸縮相比,速度肯定要慢。這樣,它可以幫助提前擴展新的活動端,從而在該端上線並開始接收流量時更快地響應初始轉換。通過 Switchboard,Kubernetes 可以管理自己的自動伸縮功能,只需監控 Kubernetes 的滾動發佈,可以確保所有服務在當前階段是健康的,然後再決定升級。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"結果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們設計 Switchboard 是爲了改善我們 Search 系統的資源消耗,它已經做到了這一點。然而,分步部署的方法也給開發者帶來了許多不錯的工作流程改進。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Switchboard 使我們能夠將搜索虛擬機的總容量控制在或接近 100%,而非我們以前所支持的 200% 的容量,隨着 Search 流量的增加,我們再也不必提供雙倍的容量了。如今,適應流量的不安華變得更加容易,因爲任何額外的的被動(自動)或主動(手動)擴展只需要爲我們的真實容量保留計算服務,而不是兩倍。所以,我們在發佈 Switchboard 期間,雲虛擬機的利用率有了明顯的提高。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/40\/ba\/40861a3a1b61eca63c08d74baac280ba.jpg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"幾個月來,每個搜索請求的雲成本(雲計費總額 \/ 請求數)顯示,我們在 Switchboard 之後,利用效率有所提高。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Switchboard 的第二大成功在於,它使得我們在 Staging 環境中的部署速度不斷提高。我們第一次嘗試放棄傳統的雙重配置方法,就是在兩次部署之間完全縮減未使用的搜索集羣,然後預先對其進行重新配置,作爲下一個部署的第一步。這種方法的一個問題就是,開發人員必須等待我們的 Search 系統內的所有服務被擴展到足以接受流量,然後他們才能在我們的 Staging 環境中進行測試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/c7\/ee\/c7e89fb5e9dce64a235af51f7fb2d0ee.jpg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"每個 Staging 環境部署所用的時間。每個單獨的行是一個單獨的部署。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總的來說,在實施 Switchboard 後,我們看到利用率的提高與中間解決方案相似,但卻不必在較慢的部署時間上做出妥協。Switchboard 甚至還提高了中間解決方案的利用效率。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,在部署過程中發現和響應問題也變得更加容易。從技術上講,Search 部署的時間比我們維護兩個完全擴展的集羣時要長,但是這個額外的時間是由於自動流量滾動發佈過程的漸進性造成的。人類搜索部署人員通常是被動地監控滾動發佈階段,根本沒有交互。但是,如果他們需要的話,可以暫停滾動發佈,檢查當前的結果。Search 部署人員至少每月使用一次 Switchboard 來暫停滾動發佈。我們以前根本就沒有這個選項。由於 Switchboard 個別部署變得更加安全和可靠。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,重新架構我們的藍綠部署流程,包括通過 Switchboard 進行金絲雀式的逐步流量提升,使我們的系統更具可擴展性和效率,同時也爲開發者提供了更好的體驗設計。爲了充分利用 Kubernetes 和雲環境的靈活性,我們成功地調整了搜索應用的架構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/codeascraft.com\/2021\/06\/15\/improving-the-deployment-experience-of-a-ten-year-old-application\/"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章