在快節奏交付的今天,LinkedIn是如何使用暗金絲雀進行生產現場測試?

banq發表於2020-09-11

網際網路軟體行業已經從漫長的開發週期和專門的質量保證(QA)階段轉移到了快節奏的連續整合/連續交付(CI / CD)管道,在該管道中可以快速編寫,提交和推送新程式碼。
這樣做極大地提高了迭代速度,在LinkedIn上,提交新程式碼並將其推入生產環境並不少見。一個小時之內,一天多次。
儘管這取得了令人難以置信的成功:透過允許我們更快地進行更改提高了開發人員的生產力。但當不良程式碼、配置或AI模型投入生產時,它還引起了諸如站點或服務中斷的問題。即使使用完整的單元和整合測試,有時也無法替代使用生產資料和生產量的生產級測試,尤其是在系統效能指標方面,例如記憶體消耗,CPU / GPU使用率,併發性和延遲。
但是,為了安全地進行生產級測試而不對客戶造成負面影響,團隊經常需要生產請求和生產資料。諸如記錄和重放之類的框架提供了一種解決方案,但通常不適合快速變化的場景,例如測試 新的AI模型,該模型需要不同的輸入功能才能產生輸出。收集生產量的新輸入需要重新記錄生產請求和響應的潛在昂貴且耗時的步驟,而這對於每天進行A / B測試的多個新模型是不可行的。這篇部落格文章介紹了暗金絲雀群集,作為在生產之前就發現問題的一種方法。
 

什麼是暗金絲雀?
金絲雀的術語來自採礦業,礦工將不幸的金絲雀放到籠子裡,以檢測是否存在有毒氣體危害礦工呼吸。這些金絲雀將向礦工發出預警訊號,表示進入礦山並不安全。在軟體工程中,金絲雀是在生產級別執行新程式碼,配置或AI模型的服務的例項,因此我們可以在將新程式碼部署到更多例項之前驗證其安全性。如果新程式碼不正確(例如,效能降低或錯誤率增加),則對該“金絲雀”的請求可能會“犧牲”,直到該錯誤程式碼被回滾為止。這可能意味著一小部分使用者請求將失敗(banq注:因為網際網路是免費的,故可以承受參與測試的失敗)。
“暗”金絲雀是服務的一個例項,該服務從實際服務例項中獲取重複流量,但是預設情況下會丟棄來自暗金絲雀的響應。這意味著即使在暗金絲雀中出了點問題,例如錯誤,更高的延遲,更高的CPU /記憶體消耗等,終端使用者也不會受到影響。(banq注:使用免費使用者做測試,但是不影響使用者結果)。
例如,如果有讀取配置檔案的請求,則普通情況下的副作用是將對配置檔案讀取次數進行計數的資料寫入資料庫;可以透過檢測到這是一個暗金絲雀請求並使用單獨的資料庫計數器,或者在這種情況下不寫入資料庫,來減輕這種副作用。
對下游服務的呼叫也必須消除副作用,或者需要減輕其影響。在使用暗金絲雀之前,還需要仔細考慮其他下游影響。
 

LinkedIn的暗金絲雀歷史
早在2013年,我們的大型後端服務之一就希望在Rest.li中為暗金絲雀提供支援。當時的服務涉及複製來自一臺主機的請求並將其傳送到另一臺主機。它是透過Python工具新增的,以填充Apache ZooKeeper中的主機到主機對映以及用於讀取此對映並增加流量的過濾器。隨著操作複雜性的增加(由於額外的資料中心,中端甚至前端服務中使用了暗金絲雀,以及動態伸縮例項),維護起來變得更加複雜。越來越多的團隊在使用暗金絲雀,但我們的開發人員和SRE仍然受困於維護暗金絲雀的難度。例如,當暗金絲雀突然停止接收流量,工程師不得不在每個資料中心中重新建立乏味的主機到主機對映。很明顯,我們需要一個新的解決方案。
 

引入暗金絲雀叢集
暗金絲雀群集類似於暗金絲雀本身,只是存在多個暗金絲雀例項。將流量傳送到暗金絲雀群集要求使用者發現流量並將其分散到群整合員之間。LinkedIn使用Rest.li中動態發現(D2)服務發現機制將請求從服務傳送到服務,因此這是新增對黑暗群集的一流支援的邏輯位置,因為D2已經可以將請求傳送到群集。這種整合使整個常規服務例項叢集能夠將重複但被忽略的請求傳送到黑暗的例項叢集。這樣做的好處是:

  • 我們可以輕鬆地向暗金絲雀傳送大量流量,同時將對傳送例項的影響降到最低,因為任何例項上的附加QPS都很低。
  • LinkedIn開發人員熟悉D2服務發現機制,並擁有明確的支援途徑來檢查程式碼更改,並促進跨登臺區域和資料中心的更改。
  • 分叉機制(我們在其中複製請求,將其傳送到暗服務,然後忽略響應)可以知道源和目標群集的大小,以便我們可以在常規服務例項和暗例項之間維持可比較的流量水平,例如與心電圖

我們在LinkedIn上的團隊發現,暗金絲雀群集是驗證更改的簡便方法,尤其是對於測試新的線上AI模型時,該模型在生產級流量下的系統效能尚不清楚。所有用例的共同點在於,這可以使我們的工程師不必擔心新的變化,從而使LinkedIn網站更穩定,開發人員的工作效率更高。
 

架構
在典型的面向服務的體系結構中,服務將呼叫其他服務來滿足使用者請求。在下圖中,服務A具有多個例項,接受入站請求,並呼叫其他服務(包括服務B)以檢索必要的資訊。這是一個典型的分層系統,其中服務A是中間層服務,服務B是後端服務。如果服務A是我們要驗證的服務,則可以設定服務A暗金絲雀的群集。在快節奏交付的今天,LinkedIn是如何使用暗金絲雀進行生產現場測試?
儘管有很多方法可以將流量分配給服務A的暗金絲雀群集,但LinkedIn使用客戶端庫,該庫可以發現服務A應當將流量分叉到的暗群集。 
在這種情況下,我們在Apache ZooKeeper中儲存從源群集(“ ServiceACluster”)到一組對應的深色群集([“ DarkServiceACluster”])的自更新對映。此外,我們可以儲存其他後設資料,例如如何將流量增加到Dark Cluster以及分叉流量所需的其他配置。現在,每當服務A收到請求時,入站請求過濾器就會讀取該ZooKeeper資料,檢測到它需要向DarkServiceACluster傳送暗流量,並適當地分叉該請求。

“ServiceACluster” {
  … // other properties
  “darkClusters” {
    “DarkServiceACluster” {
      “DarkClusterStrategyPrioritizedList”
        “RELATIVE_TRAFFIC”
      “multiplier” : “1.0”
    } // map of properties for DarkServiceACluster
  } // map of darkClusters
} // map of properties for ServiceACluster


在這種情況下,並非絕對需要使用Apache ZooKeeper,但確實有幫助,因為它使我們能夠知道常規群集和暗群集的確切計數。這使我們能夠自動調整排程例項,從而獨立地擴充套件和縮減常規叢集和暗叢集。傳送暗流量的一種策略是使暗群集例項和常規群集例項之間的每秒查詢(QPS)相同(或根據某個乘數成比例),因此可以透過驗證工具進行比較。如果將例項新增到DarkServiceACluster,則可以預期來自ServiceACluster的總出站暗請求總數會增加,但是每個暗群集例項上的QPS保持不變。相反,如果我們將例項新增到ServiceACluster,那麼我們希望每個例項到ServiceACluster的QPS會下降(因為總QPS保持不變,並且分佈在更多例項上)。結果,我們希望每個例項的DarkServiceACluster QPS減少相應的數量。 
 

相關文章