1. 程式人生 > >不解決依賴管理的問題,你也就無法提升持續交付效率

不解決依賴管理的問題,你也就無法提升持續交付效率

微服務架構

作者:Mike McGarr

編輯:薛命燈

微服務架構為軟體開發帶來了極大的靈活性,並加快了交付速度,但同時也帶來了依賴管理問題。傳統的解決方案雖然能夠解決依賴管理問題,但都太極端,顧此失彼。於是,Netflix 嘗試著尋找自己的解決方案,期待著在整個組織層面做到真正的持續整合。本文內容來自 Netflix 技術部落格,且已獲得翻譯授權。

在過去的 8 年間,Netflix 基於 AWS 構建了一套健壯的微服務架構,我們因此學會了如何在 AWS 上構建可靠的高效能服務。我們的微服務架構解耦了工程團隊,讓他們可以自由地構建、測試和部署他們的服務。這種靈活性最大化了團隊的交付速度。在 Netflix,交付速度和可靠性是設計解決方案時首要的考慮點。

基於我們的架構,微服務為它們的消費者提供了一個客戶端軟體包,用於處理所有的 IPC(程序間通訊)邏輯。這同時為服務的提供者和消費者帶來了很多好處。除了客戶端,微服務的很大部分是基於我們的執行時平臺而構建的,這個平臺由內部的軟體包和第三方開源的軟體包組成。

儘管服務開發團隊有很大的釋出靈活性,但他們的交付速度卻受到了依賴軟體包的影響。一項新增的產品特性可能要求很多微服務都用上最新版本的共享軟體包或客戶端,而更新依賴版本可能會帶來風險。

簡而言之,依賴管理是一項艱鉅的任務。

更新專案的依賴可能帶來潛在的問題,包括:

  • 具有阻斷性的 API 變更。這是最典型的場景,一個編譯錯誤導致整個構建失敗。由依賴鎖定(Dependency Locking)和動態版本選擇器組成的語義版本控制(Semantic Versioning)可以幫助大部分團隊避免發生這種錯誤。不過,鎖定在一個主版本上會讓整個公司的程式碼升級變得很困難,導致配置漂移(Configuration Drift),並且需要長期地維護舊軟體包。
  • 具有傳遞性的依賴更新。因為 JVM 的類路徑是扁平結構,所以在一個應用程式裡,一個類只能存在一個版本。像 Gradle 和 Maven 這類工具可以處理版本衝突,避免同一個軟體包的多個版本被引入到專案當中。這也意味著,你的應用程式裡有一些程式碼依賴了具有傳遞性特徵的軟體包,但你的程式碼並沒有針對它們進行過測試。
  • 具有阻斷性的功能變更。理想情況下,這個問題可以通過執行適當的測試來緩解。軟體包的所有者可以通過執行使用者的測試案例來了解他們對軟體包功能的預期。

我們發現,為了解決大規模的依賴管理問題,很多公司使用了兩種方案:共享最小化(Share Little)和單體倉庫(MonoRepo)。

共享最小化(或者乾脆不使用共享軟體包)最近在微服務領域很流行,它的核心論調是說,微服務之間不應該共享程式碼,服務之間只能通過 HTTP API 進行耦合。更有甚者,有人說直接使用拷貝加黏貼的方式來代替共享軟體包。這是一種非常極端的解耦手段。

單體倉庫的核心論調是說,組織的所有程式碼應該全部儲存在一個單獨的倉庫裡。任何一個程式碼變更在提交到 HEAD 之前,都需要針對整個程式碼倉庫進行編譯和測試。內部軟體包沒有所謂的版本,只有 HEAD 程式碼。所有的提交在到達 HEAD 之前需要跨過一些門檻。第三方軟體包需要通過“審批”才能被使用,而且僅限於一兩個版本。

這兩種方式都能解決大規模的依賴管理問題,不過它們也帶來了一些挑戰。共享最小化促進了解耦,也加快了工程速度,但犧牲了程式碼的重用性和一致性。單體倉庫保證了程式碼一致性,並降低了風險,但犧牲了靈活性。不管採用哪一種方式,我們都需要對 Netflix 的開發基礎設施和執行時架構做出重大的調整。況且,這兩種方案會破壞我們所推崇的自由和責任文化。

我們給自己提出了一個很大的挑戰目標:

我們能否為 Netflix 的工程師們提供一種解決方案,它不但具有單體倉庫的優勢,還能保持分散式倉庫的靈活性?

我們以單體倉庫為藍本,另闢蹊徑,希望找出能夠達到相同目的的可替代方案。單體倉庫所要解決的核心問題是什麼?我們能否在傳統的二元整合世界裡開發出一種新的方案?

我們的解決方案,雖然還在試驗階段,不過可以從中歸納出三個關鍵的特性。

  • 向釋出者反饋。直接或間接地向共享程式碼所有者快速地反饋使用者所遇到的問題。同時,允許團隊因下游依賴的中斷而暫停釋出。目前,我們不會把這類問題的責任歸咎到使用者身上。通過向軟體包所有者反饋他們的問題給 Netflix 帶來的影響,希望他們能夠負起應有的責任。
  • 來源管理。當有新版本釋出時,為使用者提供一種安全的方式,用於自動增加軟體包的版本。既然我們已經針對所有的下游依賴測試過每一個軟體包,那為什麼不直接讓使用者知道新版本,從而加快新版本的採用速度呢!
  • 分散式重構。為共享程式碼的所有者提供一種方式,讓他們可以全域性地對 API 的使用者進行快速的重構。我們已經開始向使用了某些特定 Java API 的 Git 程式碼倉庫發起了全面的拉取請求。我們已經做了一些試驗,並希望在這方面有更多的投入。

我們的旅程才剛剛開始。我們的釋出者反饋服務目前正處於 alpha 測試階段,我們計劃後續會大規模採用這個服務,緊接著會進行來源管理。我們的分散式重構試驗讓我們瞭解到進行快速的全域性重構是多麼的重要。我們也看到了通過我們所構建的工具來降低依賴圖複雜度的可能性。我們相信,通過擴充套件和培養這種能力,我們的 Netflix 團隊將會在組織層面做到真正的持續整合,並減少(甚至免去)依賴管理的痛苦。