實踐者的 DevOps 之路(5. 部署策略)

部署往往是系統上線的前的最後一步,它在 DevOps 中也扮演了相當重要的角色,而它也是在技術上變化最多的步驟。本篇文章會分享在項目中的 DevOps 部署階段的實踐與經驗。

部署

DevOps 讓整個開發迭代的速度加快,隨之而來的是更加頻繁的發佈與上線。這也意味着系統上線穩定性變得愈發重要。任何在線上發現的問題都能得到及時的解決。同樣部署策略應該支持快速驗證產品的想法,能夠幫助產品經理更加準確的確定產品方向與迭代價值。

在這種情況下,DevOps 往往採用藍綠部署,金絲雀發佈(灰度發佈), A/B 測試等策略來適應項目的不同需要。我們先來看看這些不同的部署策略的優點與侷限性。

藍綠部署

藍綠部署的優點很明顯,在系統升級發佈的同時不會導致服務中斷。而它的問題也很明顯,首先是會有額外的資源消耗,即所有的環境都需要部署兩套,用於兩個不同版本的切換。其次如果是個以數據庫爲核心的應用程序,藍綠部署的複雜度也會提升。

數據庫作爲核心資源,考慮到數據一致性,成本等問題,一般不會有兩套生產環境。因此如果更新中有 schema 相關的升級,很可能造成前端藍綠環境無法 100% 兼容,需要其他的特性的支持,例如 feature toggle 等。

這幾年隨着容器技術的普及,藍綠部署的資源消耗問題已經得到了解決。通過使用 Kubernetes 這樣的容器編排系統能夠很容的實現 Rolling Update,從而達到與藍綠部署類似的效果。

金絲雀發佈(灰度發佈)

金絲雀發佈一般也被稱爲灰度發佈,目的在於最小化系統升級時 bug 造成的影響。具體做法上與藍綠部署類似,只是不需要多套環境。在生產環境的集羣中劃分部分機器升級系統的新版本,然後在前端流量的 LB 上將部分用戶分流到新版本的系統上。這種解決方案的關鍵在於有較爲全面的監控與預警體系。能夠自動,快速的發現系統的異常,並通知開發,運維人員。

實際使用過程中的問題是那些服務不可用,或是意料之外的性能降級都比較好捕獲(使用 Prometheus + Grafana 非常容易做到),但是真正造成問題的是那些業務處理上的 bug,例如費用計算錯誤,查詢結果錯誤等。Testing in Production 的解決方案比較麻煩,也不是成熟,因此一般還是在幾天之後由人工確認沒有大問題的情況下結束金絲雀分佈,完整的切換到新版本上。

A/B 測試

與前兩種部署策略不同,A / B 測試的目的不是在於降低部署的風險,而是探索用戶的使用習慣,從數據的角度提升產品的可用性與價值。在形式 A / B 測試與金絲雀發佈非常類似,都是在一套環境中同時存在兩個版本的系統,但其實它們存在着不小的差異。

首先金絲雀發佈中存在的兩個版本是一前一後,一新一舊的,而 A / B 測試中的兩個版本在時間上應該是一致的,只是功能上有不同,類似分支的概念。其次金絲雀發佈的時間較短,即兩個版本共存的時間不會很長,一般持續一至三天,之後如果沒有大問題就會統一升級爲新版本。A / B 測試的持續時間則可能較長,會按照產品經理所需的時間而定。最長可能會持續一個月,甚至更長。

A / B 測試的難點在於測試數據的分組以及多個 A / B 測試的特徵區分,在這方面 DevOps 也沒有很好的解決方案,之前的項目中依然靠一些代碼的數據埋點實現。

實踐

爲了在不同類型的系統,技術架構下能夠實現上述這些部署策略,同時保證整個部署流程的自動化與穩定性,DevOps 將會面臨各種不同的問題,下面是一些我在項目上的相關實踐經驗。

微服務的挑戰

微服務作爲最近幾年開始流行的架構風格的確解決了不少問題,但是對於 DevOps 提出了更高的要求。微服務在降低系統耦合度的時候也會導致系統數量與複雜度的增加。因此在發佈階段需要合理的處理各個系統間的依賴關係,Rolling Update 是必需的,不能因爲一個系統的發佈導致某些業務流程的完全中斷。

對於這種問題,基於容器的部署與 Kubernetes 這樣的容器編排系統可以給予很大的幫助。由於容器本身的特性,我們可以快速,廉價的創造和銷燬某個系統的示例,從而搭建大規模的,基於容器的集羣。而 Kubernetes 則讓 Rolling Update 變得極爲方便,只需簡單的命令就可以完成整個集羣的升級。

流處理系統的發佈

流處理系統在現有的數據處理架構下有着不可或缺的位置,如何做好一個流處理系統的發佈與升級也對 DevOps 提出了挑戰。與一般的系統不同,如果一個流處理系統用於實時報表,或是數據倉庫的寫入源,是非常忌諱有錯誤數據寫入的。對於一般的 OLTP 系統,如果有錯誤數據寫入(一般是數據庫),直接修改數據即可。但是對於流處理系統,如果有錯誤的數據,就需要重新計算整個時間窗口的數據才能得到正確的結果。

如果需要不中斷流處理系統的服務,又要做到在線升級,一般採取的都是基於藍綠部署的冗餘方案。在升級前就會在前端的 LB 切到一套單獨的系統,然後進行升級,升級成功後再把流量回復正常。在實際項目中,我們曾經在 Kafka 上實施了整套的方案,也獲得了不錯的效果。

有狀態的服務

包括傳統的關係型數據庫,或是那些 NoSQL 數據庫在部署過程中往往稱爲最後的堵塞點,特別是關係型數據庫。在多個項目中我們都遇到了線上升級中需要修改數據庫 schema 的變更,對於這樣的場景我們也一直沒有很好的解決方案,只能將整個服務響應關閉,快速返回服務不可用,避免在部署過程中由於基礎服務的不可用引起上層系統的雪崩。

隨着 Kubernetes 對於有狀態服務支持的更加完善,我想這個問題也會在不久的將來得到解決。而在目前的項目中,我們都會從架構層面減少對於數據庫的依賴,嘗試各種更加輕量級的解決方案,繞開這個限制。

小結

這次我們討論了一些部署中不同策略,也聊了在 DevOps 的部署階段會遇到的問題。作爲個人經驗,我覺得在容器化日益流行的今天,DevOps 的能力得到了極大的增強,但是仍然需要考慮老舊架構,技術債等問題爲 DevOps 帶來的困難。DevOps 永遠是一個系統性的問題,一個良性的架構,保持學習能力的團隊纔是解決問題的關鍵,而不是一套自動化的系統。

相關閱讀:

很不幸,自動化測試永遠只能是必要非充分條件

面對疫情這樣的複雜問題,有什麼招呢?

DevOps關鍵能力之文化的力量——重磅新書預覽《加速》

小說體敏捷/DevOps轉型教科書

和實戰經驗分享

又到拼人品的時候,喜歡《獵豹行動》的朋友請賞個臉投票。

每人每天可以投3票,截止4月19日。謝謝。

關注公衆號看其他原創作品

敏於思 捷於行 

堅持每週輸出一篇高質量文章

覺得好看,點個“在看”或轉發給朋友們,歡迎你留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章