你好! 我叫 Vadim Madison,負責 Avito 系統平台的開發。 人們不只一次說過我們公司如何從單一架構轉向微服務架構。 現在是時候分享我們如何改造我們的基礎設施以充分利用微服務並防止我們迷失其中。 PaaS 如何在這方面為我們提供幫助,我們如何簡化部署並將微服務的創建減少為一鍵式 - 請繼續閱讀。 並非我下面寫的所有內容都在 Avito 中完全實現,其中一些是我們開發平台的方式。
(在本文的最後,我將談論參加微服務架構專家 Chris Richardson 舉辦的為期三天的研討會的機會)。
我們如何走向微服務
Avito 是世界上最大的分類網站之一;每天發布超過 15 萬條新廣告。 我們的後端每秒接受超過 20 個請求。 我們目前有數百個微服務。
多年來我們一直在建構微服務架構。 究竟如何——我們的同事詳細介紹
最初,我們並沒有創造一個能夠全面幫助我們開發和推出微服務的生態系統。 他們只是收集了明智的開源解決方案,在家中推出它們並邀請開發人員來處理它們。 結果,他去了十幾個地方(儀表板、內部服務),之後他更加強烈地渴望以舊的方式,在一個整體中削減代碼。 下圖中的綠色表示開發人員用自己的雙手以某種方式完成的工作,黃色表示自動化。
現在,在 PaaS CLI 實用程式中,使用一個命令建立一個新服務,並新增一個新資料庫和另外兩個命令並將其部署到 Stage。
如何克服「微服務碎片化」時代
在單體架構中,為了產品變化的一致性,開發人員被迫弄清楚他們的鄰居發生了什麼事。 在使用新架構時,服務上下文不再相互依賴。
此外,微服務架構要發揮作用,還需要建立許多流程,也就是:
• 記錄;
• 請求追蹤(Jaeger);
• 錯誤聚合(哨兵);
• 來自 Kubernetes(事件流處理)的狀態、訊息、事件;
• 競賽限制/斷路器(可使用Hystrix);
• 服務連線控制(我們使用Netramesh);
• 監控(Grafana);
• 裝配(TeamCity);
• 溝通與通知(Slack、電子郵件);
• 任務追蹤; (吉拉)
• 準備文件。
為了確保系統不會失去完整性並在擴展時保持有效,我們重新考慮了 Avito 中的微服務組織。
我們如何管理微服務
以下有助於在許多 Avito 微服務之間實施統一的「聚會策略」:
- 將基礎設施分層;
- 平台即服務(PaaS)概念;
- 監控微服務發生的一切。
基礎設施抽象層包括三層。 讓我們從上到下。
A. 頂部 - 服務格。 起初我們嘗試了 Istio,但結果發現它使用了太多資源,這對我們的捲來說太昂貴了。 因此,架構團隊的高級工程師Alexander Lukyanchenko開發了自己的解決方案—
B. 中型 - Kubernetes。 我們在其上部署和運行微服務。
C. 底部 - 裸露金屬。 我們不使用雲端或 OpenStack 之類的東西,而是完全依賴裸機。
所有層均由 PaaS 組合。 而這個平台又由三個部分組成。
一、發電機,透過 CLI 實用程式控制。 正是她幫助開發人員以正確的方式、以最少的努力創造微服務。
二. 聯合收集器 透過通用儀表板控制所有工具。
三. 貯存。 與自動設定重要操作觸發器的調度程序連線。 有了這樣的系統,不會因為有人忘記在 Jira 設定任務而錯過任何任務。 為此,我們使用名為 Atlas 的內部工具。
Avito 中微服務的實現也是按照單一方案進行的,這簡化了在開發和發布的每個階段對它們的控制。
標準微服務開發管道如何運作?
一般來說,微服務創建鍊是這樣的:
CLI 推送 → 持續整合 → 烘焙 → 部署 → 人工測試 → 金絲雀測試 → 擠壓測試 → 生產 → 維護。
讓我們完全按照這個順序來過一遍。
CLI 推播
• 創建微服務.
我們花了很長時間努力教導每個開發人員如何做微服務。 這包括在 Confluence 中編寫詳細說明。 但計劃發生了變化並得到了補充。 結果是,在旅程的開始就出現了瓶頸:啟動微服務需要花費更多的時間,並且在創建過程中仍然經常出現問題。
最後,我們建立了一個簡單的 CLI 實用程序,可以自動執行建立微服務時的基本步驟。 事實上,它取代了第一個 git Push。 這就是她所做的。
— 依照範本以「精靈」模式逐步建立服務。 我們在 Avito 後端提供了主要程式語言的範本:PHP、Golang 和 Python。
- 一次一個命令,在特定機器上部署本機開發環境 - Minikube 啟動,Helm 圖表自動產生並在本機 kubernetes 中啟動。
— 連接所需的資料庫。 開發人員不需要知道 IP、登入名稱和密碼即可存取他所需的資料庫 - 無論是本地、階段還是生產中。 此外,資料庫立即以容錯配置和平衡方式部署。
— 它自行執行現場組裝。 假設開發人員透過他的 IDE 更正了微服務中的某些內容。 該實用程式會看到檔案系統中的更改,並根據這些更改重建應用程式(對於 Golang)並重新啟動。 對於 PHP,我們只需轉發多維資料集內的目錄,然後「自動」獲得即時重新載入。
— 產生自動測試。 雖然是白色形式,但非常適合使用。
• 微服務部署.
部署微服務對我們來說曾經是一件苦差事。 需要以下內容:
一、Dockerfile。
二. 配置。
三. Helm 圖表,它本身就很麻煩,包括:
——圖表本身;
— 模板;
——考慮到不同環境的具體值。
我們已經消除了重新設計 Kubernetes 清單的痛苦,因此它們現在可以自動產生。 但最重要的是,他們將部署簡化到了極限。 從現在開始,我們有了一個 Dockerfile,開發人員將整個配置寫入一個簡短的 app.toml 檔案中。
是的,在 app.toml 本身中暫時沒有什麼可做的。 我們指定在哪裡以及要啟動多少個服務副本(在開發伺服器上、在登台上、在生產中),並指示其依賴項。 請注意 [engine] 區塊中的行號 = "small"。 這是將透過 Kubernetes 分配給服務的限制。
然後,根據配置,自動產生所有必要的 Helm 圖表並建立與資料庫的連線。
• 基本驗證。 此類檢查也是自動化的。
需要追蹤:
— 有 Dockerfile 嗎?
— 有app.toml嗎;
— 有可用的文件嗎?
——依賴關係是否有序?
— 是否設定了警報規則。
最後一點:服務的所有者自己決定要監控哪些產品指標。
• 準備文件。
仍然是一個問題領域。 它似乎是最明顯的,但同時它也是一個「經常被遺忘」的記錄,因此也是鏈條中的一個脆弱環節。
每個微服務都有必要有文件。 它包括以下區塊。
一、服務簡要說明。 從字面上講幾句話來說明它的作用以及為什麼需要它。
二. 架構圖連結。 重要的是,快速瀏覽一下就很容易理解,例如,您是否使用 Redis 進行快取或作為持久模式的主要資料儲存。 目前在 Avito 中,這是 Confluence 的連結。
三. 運行手冊。 關於啟動服務以及處理該服務的複雜性的簡短指南。
四. 常問問題,最好能夠預測您的同事在使用該服務時可能遇到的問題。
五、API端點說明。 如果您突然沒有指定目的地,那麼與您的微服務相關的同事幾乎肯定會為此付出代價。 現在我們使用 Swagger 和我們的解決方案來解決這個問題,稱為brief。
六. 標籤。 或顯示服務所屬公司的產品、功能或結構部門的標記。 例如,它們可以幫助您快速了解您是否正在削減同事一周前為同一業務部門推出的功能。
七. 服務的所有者或所有者。 在大多數情況下,它(或它們)可以使用 PaaS 自動確定,但為了安全起見,我們要求開發人員手動指定它們。
最後,類似於程式碼審查,審查文件是一個很好的做法。
持續集成
- 準備儲存庫。
- 在 TeamCity 中建立管道。
- 設定權限。
- 搜尋服務所有者。 這裡有一個混合方案 - 手動標記和 PaaS 的最小自動化。 當服務被轉移到另一個開發團隊以獲得支援時,或者例如,如果服務開發人員退出時,全自動方案就會失敗。
- 在 Atlas 中註冊服務 (往上看)。 及其所有所有者和依賴項。
- 檢查遷移。 我們檢查其中是否有潛在危險。 例如,其中之一會彈出更改表或其他內容,這可能會破壞不同版本服務之間資料模式的兼容性。 然後,不會執行遷移,而是將其放入訂閱中 - PaaS 必須在可以安全使用它時向服務所有者發出信號。
烤
下一階段是在部署之前打包服務。
- 建立應用程式。 根據經典 - 在 Docker 映像中。
- 為服務本身和相關資源產生 Helm 圖表。 包括資料庫和快取。 它們是根據 CLI 推送階段產生的 app.toml 配置自動建立的。
- 為管理員建立開放連接埠的票證 (在需要的時候)。
- 運行單元測試並計算程式碼覆蓋率。 如果程式碼覆蓋率低於指定的閾值,那麼該服務很可能不會進一步進行部署。 如果處於可接受的邊緣,那麼該服務將被分配一個「悲觀」係數:然後,如果該指標隨著時間的推移沒有改善,開發人員將收到測試方面沒有進展的通知(並且需要對此採取一些措施)。
- 考慮記憶體和 CPU 限制。 我們主要用Golang編寫微服務並在Kubernetes中運行它們。 因此,與Golang 語言的特性相關的一個微妙之處是:預設情況下,啟動時,會使用機器上的所有內核,如果您沒有明確設定GOMAXPROCS 變量,並且當在同一台機器上啟動多個此當類別服務時,它們會開始運作。爭奪資源,互相干擾。 下圖顯示了在無爭用且處於資源競爭模式下執行應用程式時執行時間的變化。 (圖表來源為
這裡 ).
執行時間越少越好。 最大值:643ms,最小值:42ms。 照片是可點擊的。
手術時間越少越好。 最大值:14091 ns,最小值:151 ns。 照片是可點擊的。
在組裝準備階段,您可以明確設定此變量,也可以使用庫
部署
• 檢查約定。 在開始將服務程序集交付到預期環境之前,您需要檢查以下內容:
- API 端點。
— API 端點回應與架構的合規性。
— 日誌格式。
— 設定服務請求的標頭(目前由 netramesh 完成)
— 在向事件總線發送訊息時設定所有者令牌。 這是追蹤總線上服務的連接性所必需的。 您既可以將冪等資料傳送到總線,這不會增加服務的連接性(這很好),也可以發送加強服務的連接性的業務資料(這非常糟糕!)。 當這種連接成為問題時,了解誰寫入和讀取總線有助於正確分離服務。
阿維託的會議還不是很多,但數量正在擴大。 此類協議以團隊能夠理解和理解的形式提供的越多,就越容易維護微服務之間的一致性。
綜合測試
• 閉環測試。 為此,我們現在使用開源
• 壓力測試。 我們努力使所有服務達到最佳效能。 並且每個服務的所有版本都必須經過負載測試——這樣我們就可以了解服務當前的效能以及與相同服務的先前版本的差異。 如果在服務更新後,其效能下降了一倍半,這對其所有者來說是一個明確的訊號:您需要深入研究程式碼並糾正這種情況。
例如,我們使用收集到的資料來正確實現自動擴展,並最終大致了解服務的可擴展性。
在負載測試期間,我們檢查資源消耗是否符合設定的限制。 我們主要關注極端情況。
a) 我們查看總負載。
- 太小 - 如果負載突然下降幾次,很可能有些東西根本不起作用。
- 太大 - 需要優化。
b) 我們根據 RPS 查看截止值。
這裡我們來看看目前版本與上一版本的差異以及總量。 例如,如果某個服務產生 100 個 rps,那麼它要么寫得不好,要么這就是它的特殊性,但無論如何,這都是仔細查看該服務的原因。
相反,如果 RPS 太多,則可能存在某種錯誤,並且某些端點已停止執行有效負載,但其他端點只是被觸發 return true;
金絲雀測試
通過綜合測試後,我們在少量用戶上測試微服務。 我們從該服務的目標受眾中的一小部分開始謹慎行事——不到 0,1%。 在這個階段,將正確的技術和產品指標納入監控中非常重要,以便它們盡快顯示服務中的問題。 金絲雀測試的最短時間為 5 分鐘,主要時間為 2 小時。 對於複雜的服務,我們手動設定時間。
我們來分析一下:
— 特定於語言的指標,特別是 php-fpm 工作人員;
— Sentry 中的錯誤;
——回應狀態;
——反應時間,準確的和平均的;
- 潛伏;
——已處理和未處理的異常;
——產品指標。
擠壓測試
擠壓測試也稱為“擠壓”測試。 該技術的名稱被引入 Netflix。 其本質是,首先我們用真實流量填充一個實例直到故障點,從而設定其限制。 然後我們添加另一個實例並加載這一對 - 再次達到最大值; 我們在第一次「擠壓」時看到了它們的上限和三角洲。 因此,我們一次連接一個實例併計算變化模式。
透過「擠壓」的測試資料也會流入一個通用的指標資料庫,我們可以用它們豐富人工負載結果,甚至用它們來取代「合成」。
生產
• 縮放。 當我們將服務推出到生產環境時,我們會監控它的擴展。 根據我們的經驗,僅監控CPU指標是無效的。 使用 RPS 基準測試的自動擴展以其純粹的形式有效,但僅適用於某些服務,例如線上串流媒體。 因此,我們首先關注特定於應用程式的產品指標。
因此,在縮放時我們分析:
- CPU和RAM指示器,
— 佇列中的請求數量,
- 回應時間,
——基於累積歷史資料的預測。
擴展服務時,監控其依賴關係也很重要,這樣我們就不會擴展鏈中的第一個服務,並且它所存取的服務會在負載下失敗。 為了為整個服務池建立可接受的負載,我們查看「最近」依賴服務的歷史資料(基於 CPU 和 RAM 指標的組合,加上特定於應用程式的指標)並將其與歷史資料進行比較初始化服務的訊息,等等,從上到下貫穿整個「依賴鏈」。
維修
微服務投入運作後,我們可以為其附加觸發器。
以下是觸發發生的典型情況。
— 偵測到潛在危險的遷移。
— 安全性更新已發布。
— 服務本身已經很久沒有更新了。
— 服務負載明顯下降或部分產品指標超出正常範圍。
— 該服務不再滿足新平台要求。
有些觸發器負責運作的穩定性,有些則作為系統維護的功能,例如某些服務已經很長時間沒有部署並且其基礎鏡像已不再通過安全檢查。
儀表板
簡而言之,儀表板就是我們整個PaaS的控制面板。
- 有關服務的單點信息,包括有關其測試覆蓋範圍、圖像數量、生產副本數量、版本等的數據。
- 一種按服務和標籤(屬於業務部門、產品功能等的標記)過濾資料的工具
- 與用於追蹤、記錄和監控的基礎設施工具整合的工具。
- 單點服務文件。
- 跨服務的所有事件的單一觀點。
在總
在引入 PaaS 之前,新開發人員可能會花幾週時間了解在生產中啟動微服務所需的所有工具:Kubernetes、Helm、我們的內部 TeamCity 功能、以容錯方式設定與資料庫和快取的連接等。需要幾個小時來閱讀快速入門並創建服務本身。
我在 HighLoad++ 2018 上做了一個關於這個主題的報告,你可以觀看
讀到最後的人的獎勵曲目
我們 Avito 正在為來自以下國家的開發人員組織為期三天的內部培訓:
訓練將於5月7日至XNUMX日在莫斯科舉行。 這些工作日將被佔用。 午餐和培訓將在我們的辦公室進行,選定的參與者將自行支付交通費和住宿費。
您可以申請參與
我們將在這篇文章的更新中以及開發人員的社交網路 Avito 上公佈培訓參與者的姓名(AvitoTech
來源: www.habr.com