複雜系統如何在不停機升級同時保持穩定?你必須考慮如下幾個點...

簡介: 千門萬戶閒魚日,總把新桃換舊符算法

做者:閒魚技術-蘭林數據庫

背景

在互聯網行業,線上服務的升級更新可謂屢見不鮮。據統計,在過去的一個季度中閒魚工程師們執行了千餘次發佈,總計更新的代碼數量超過百萬行。緩存

這些發佈中,有一些可能只更新了幾行代碼,而有一些可能執行了整個集羣的遷移升級。而不管這些變動的影響面有多大,咱們都必須保證線上服務的可用性,用戶無感知。本文將以閒魚搜索服務的遷移升級爲例,向你們介紹其背後的技術方案。安全

閒魚搜索服務基本架構

閒魚的底層搜索服務由查詢規劃服務 Search Planner、查詢理解服務 Query Planner、打分排序服務 Rank Service 以及搜索引擎 Heaven Ask 3 所組成。它們之間的相互調用關係以下圖所示:服務器

閒魚搜索架構

能夠看到,整個搜索服務是由多個相互獨立的微服務所構成的。不一樣的微服務之間相互隔離,經過預先向外暴露的接口提供服務。全部的微服務最終經過 Search Planner 收口,對外提供統1、完整的搜索能力。架構

在底層搜索服務之上,還有業務邏輯層和接入網關層,具體架構在此再也不贅述。用戶的搜索請求先經過網關層轉發給邏輯層處理,再向底層搜索服務發起搜索請求。這條請求鏈上包含數十個集羣,調用深度達到兩位數,整個過程當中提供服務的服務器數量可能有成百上千。負載均衡

對於這樣一個複雜的系統,升級過程顯然沒法一蹴而就。好消息是各個微服務之間合理的解耦合給升級工做帶來了很大的便利,有效避免牽一髮動全身而致使無從下手,使咱們能夠分門別類地處理升級問題。框架

  • 注1:Search Planner 是一個基於函數式、服務化、可視化、並行化開發框架所構建的搜索服務網關層。
  • 注2:Query Planner 的主要做用是理解用戶輸入,而後對搜索詞進行算法優化。最終得到更好的搜索召回結果。
  • 注3:Rank Service 是實時打分排序服務,它的做用是根據多維度的特徵對搜素引擎召回的海選結果進行算法打分。分數越高的商品就越有機會出如今搜索結果的前列。
  • 注4:Heaven Ask 3 (問天3)是阿里巴巴研發的一款穩定高效、功能強大的搜索引擎。爲阿里集團包括淘寶、天貓在內的核心業務提供搜索服務支持。

保持兼容

開始升級以前,咱們首先須要確認被升級的服務是否保持了向前與向後兼容性。保持兼容不只減小了工做量,也減小了升級所致使的故障風險。分佈式

爲了儘可能避免升級致使的不兼容,咱們能夠總結一些開發原則:函數

  • 遠程過程調用(RPC)須要可以忽略未知參數,而且容許缺失參數。
  • 若是須要刪除已有參數,須要與全部依賴方確認。能夠先將參數標記爲 Deprecated 而不是直接移除。
  • 使用參數時,區分缺省值和缺失值。
  • 若是接口沒法保持兼容,則建立新接口代替舊接口。不要破壞舊接口的兼容性。

在升級時,先升級那些沒有外部依賴的服務。等到被依賴方升級完畢以後,再去升級依賴方。肯定了每個服務的升級順序以後,咱們再根據服務的實際狀況肯定升級方案。

無狀態服務升級

正式進入升級流程,咱們首先關注搜索鏈路中的被設計成無狀態服務的部分,例如用於處理業務邏輯的 Java 微服務、用於處理查詢邏輯的 Search Planner 等。它們的共同特色是,每一個請求處理完畢以後,關於該次請求的資源即被釋放。不一樣的請求之間沒有相互依賴和時序要求。同一個無狀態服務內不一樣的機器節點是徹底等價的。

無狀態服務的特色使得它們很容易經過水平擴展來動態擴縮容。所以在保證兼容的前提下,它們的升級流程相對通用而且簡單:

  1. 根據服務最小可用度決定分批數。
  2. 選取一批待更新的容器,中止服務。
  3. 批量升級容器、更新鏡像。
  4. 等待這一批容器所有恢復服務後,繼續更新下一批容器。

無狀態服務升級

通常來講咱們能夠經過把狀態存儲在消息隊列、緩存、數據庫或者其它外部中間件中來達成服務的無狀態。把服務設計成無狀態的好處顯而易見:升級時不須要分配額外的機器資源,升級速度快,變動代價小,於是能夠支持頻繁的迭代更新。可是,這種設計也給狀態訪問和更新帶來了額外的開銷,在某些性能敏感的場合多是不適用的。

有狀態服務升級

咱們繼續關注有狀態的部分。有狀態服務升級的麻煩之處在於,狀態的存儲、恢復、轉移每每由服務根據實際狀況單獨設計(或者根本沒有設計),於是升級較爲困難。咱們能夠簡單列舉一些相對通用的有狀態服務升級可選方案。

  • 接入層網關提供熱更新的能力(例如 Nginx),把狀態的保持隔離在接入層內部。適合須要長時間保持狀態的場景。
  • 漸進更新,新請求逐步切換到新服務上處理,舊服務處理完存量請求後銷燬。適合短期保持狀態的場景(例如遊戲服務、實時音視頻通信服務)。
  • 建立全新的服務副本,經過數據雙寫保持新舊服務狀態一致,逐步用新服務取代舊服務。

在閒魚搜索的架構中,搜索引擎自己提供的雖然是無狀態服務,可是引擎內部保存了用於處理索引分區,增量進度的各類狀態。最終使用的升級方案以下:

  1. 使用新版本鏡像建立一個徹底獨立的新引擎。
  2. 新舊引擎全量數據同步。
  3. 增量數據同時向新舊引擎發送。
  4. 新引擎上線,逐步擴大承接流量的比例。
  5. 舊引擎再也不承接流量後下線。

搜索引擎升級

和無狀態服務的升級相比,這種方式不只額外使用了一倍的機器資源,並且每次升級都須要作一次複雜而繁瑣的服務配置。若是服務自己不是無狀態的,還須要自行編碼實現切流邏輯,保證同一個用戶的請求可以落到同一個集羣上。總體升級成本較爲昂貴,只適合更新頻率很是低的服務。若是服務的更新頻率較高,則應該根據服務的實際狀況設計實現升級成本更低的方案。

服務發現

在升級過程當中,服務發現機制承擔着重要做用。它爲咱們提供瞭如下功能:

  • 保證分佈式一致性
  • 服務優雅上下線
  • 負載均衡
  • 流量調控與請求降級
  • 同機房優先調度
  • 跨機房容災調度

服務發現

服務發現是流量調控的總閥門。一個成熟穩定的服務發現機制不只能夠有效避免發佈致使的請求成功率抖動,也爲發生異常時快速回滾止血提供了保證。

風險防控

對搜索鏈路的每個集羣按照依賴順序進行服務升級、掛載、切流無疑是高危操做,稍有不慎就可能引發線上故障。所以,咱們按照阿里巴巴安全生產三板斧原則對升級流程進行了梳理:

  • 可監控
    重要鏈路的重要指標均提早保證監控覆蓋。例如請求總量,請求成功率,請求響應時長等等。確保重大問題能夠經過監控指標及時發現。
  • 可灰度
    任何變動都不容許未經灰度直接全量發佈到線上。對於無狀態服務,咱們通常經過調整服務發現中的權重或者調整機器比例來完成灰度放量。對於部分不能隨機灰度的情形,咱們設計了按用戶分批放量的機制。
  • 可回滾
    變動系統提供了通用的一鍵回滾能力,但並不是是最快的方式。在不少狀況下,咱們在執行變動前就作好了把待更新的機器或集羣在服務發現上從新掛載或移除的準備,從問題發現到恢復的時間基本是秒級的。

總結

綜上所述,複雜系統不停機升級的原則和流程能夠歸納以下:

  1. 服務間解耦與隔離,確保單次升級的範圍和影響可控。
  2. 根據兼容性和依賴關係決定服務的升級順序。
  3. 根據服務是否無狀態決定升級方式。
  4. 提早準備好監控和回滾方案,灰度升級。

閒魚搜索服務升級的整個執行過程經歷了兩個月的時間。這其中咱們既保證了用戶無感知,線上服務穩定運行,也保證了與咱們合做開發的算法團隊以及其餘工程團隊的正常開發不受影響。

在實際執行的過程當中,咱們還遇到了不少細節上的問題。例如建立新服務時未能提早合理預估預算需求,致使升級過程當中不斷挪借預算,拆東牆補西牆。又好比異地多活部署帶來的延遲問題迫使服務保持單元化,給升級過程當中的流量調控工做帶來了不少挑戰。這些暴露的問題也爲咱們繼續完善架構和方案提供了指引。

但願本次的分享可以給你們帶來一些幫助和啓發。

相關文章
相關標籤/搜索