乾貨!如何平穩用戶無感知的完成系統重構升級

前言

咱們在實際開發系統的過程中,頗有可能會遇到須要進行系統重構升級的狀況,須要重構的緣由多是以前的設計不合理,致使如今維護起來很是的困難,也有多是如今的業務發展很是迅速,須要進行分庫分表了又或者以前用的是單機的本地的文件存儲,如今須要用到統一的網絡存儲。總而言之,就是當初的系統設計已經不符合如今發展須要了,須要進行重構和升級。php

而這其中會可能會涉及到代碼邏輯的變動,數據存儲的變動(如DB或者文件存儲等)或者第三方接口的變動。在這樣一個新舊的切換過程中,怎麼樣才能讓用戶無感知,平穩地進行過渡?segmentfault

有人說可能說能夠停服,而後遷數據,遷完後切新邏輯,然而先不說會有一段不可接受的不可用時間,就說在遷移過程當中,咱們如何保證能一次遷移成功呢?再退一步,就算數據遷移成功了,可是若是代碼邏輯有漏洞,咱們又該如何快速回退到舊版本呢?這可不僅僅是切回舊代碼就行了,要知道這段時間可能產生了新版本的數據,這些新數據可也要遷回舊版本。網絡

重構升級系統的過程可能會遇到這麼多問題,那咱們有什麼辦法能夠平穩且用戶無感知地完成系統升級嗎?今天就給你們提供一個通用的系統重構升級的框架。裏面不少具體的邏輯得按不一樣系統的實際狀況來,可是總體思路倒是通用且可靠的。框架

場景模擬

咱們先來模擬一個簡單的場景,並看看實際狀況中應該如何操做。測試

假設咱們一開始有個users表存儲學生數據,表結構以及一些數據以下:設計

id name age
1 張三 18
2 李四 19
3 王五 17

後面隨着業務發展,咱們須要記錄學生的語文成績,而後咱們在users表加了score字段,以下code

id name age score
1 張三 18 98
2 李四 19 76
3 王五 17 80

過一段時間咱們發現又須要記錄數學分數了,後面還可能須要記錄英語分數等等。這時候不可能一次次加字段,現有的表設計又極不知足咱們的需求,因此只好對如今的系統進行重構升級了。咱們想用兩個表來存數據:接口

students開發

id name age

mark表get

id type user_id score

這時候咱們會面臨幾個問題:

  • 代碼邏輯的切換:包括增刪改查
  • 表結構的變動
  • 數據的遷移
  • 遷移過程當中用戶無感知

如何來升級呢?

步驟

  1. 在舊代碼的增刪改查的地方寫好新邏輯和建好新的表,可是一開始線上並不調用新邏輯和寫入新表,僅僅在測試環境調用和寫入,線上仍調用舊邏輯。如:

    if($is_dev){
      //新邏輯:如增刪改查students表和mark表
    }else{
      //舊邏輯:如增刪改查users表
    }
  2. 測試新邏輯沒問題了,線上同時雙寫新舊錶(包括增刪改),如:

    //新寫入邏輯:如增刪改students表和mark表
    //舊寫入邏輯:如增刪改users表
    
    
    if($is_dev){
      //新讀取邏輯:如查students表和mark表
    }else{
      //舊讀取邏輯:如查users表
    }
  3. 進行數據遷移,把原來users表的數據遷到students表和mark
  4. 而後讓系統運行一段時間,而後再對users表和students表、mark表的數據進行對帳,若是有數據不一致的狀況,說明咱們以前雙寫的時候有遺漏的地方,須要補全,若是沒有不一致,說明咱們寫入的地方都已經對齊了,如今新舊數據是已經能一直保持一致了,那下面就是切讀的地方了。
  5. 把讀的地方改爲只讀新的,以下

    //新寫入邏輯:如增刪改students表和mark表
    //舊寫入邏輯:如增刪改users表
    
    //新讀取邏輯:如查students表和mark表
  6. 系統運行一段時間,沒發現問題以後把寫的改爲只寫新的,以下

    //新寫入邏輯:如增刪改students表和mark表
    
    //新讀取邏輯:如查students表和mark表

完成以後咱們的系統就平穩的完成遷移了。

分析

整個過程可能看起來很繁瑣,不要緊,咱們一步一步來分析其必要性。

  • 第一步是先寫好新邏輯,並進行充分的測試,這固然是必要的啦,算是升級前的準備
  • 第二步是咱們升級的起始步驟了,咱們須要雙寫數據。在代碼發佈過程當中,即便有的訪問到了新代碼雙寫了,有的仍是訪問舊代碼單寫也不要緊,由於會有第三步數據遷移的過程。這一步和第三步是爲了保證數據無感知遷移(不用停服遷移數據),保證遷移後數據的一致性。
  • 第四步是對帳過程,是爲了找出咱們寫入遺漏的地方,這是由於咱們不能保證對於一個龐大的系統,你一次改造就能改到了全部的地方,因此留一段時間對寫入進行對帳是很是有必要的,有則改之。
  • 上面的第四步保證了咱們新舊的數據已是一致的了,這時候第五步咱們就能夠很放心的把咱們讀從舊的地方改到讀新的地方了。
  • 第六步也是很重要的,咱們要先讓系統平穩運行一段時間再切成單讀新表,由於這個過程當中,若是咱們發現系統新邏輯有問題,咱們能夠不少地切回讀舊邏輯,由於咱們寫入仍是雙寫的,舊數據仍是有寫入,直接切回去是沒有問題的。這就避免了沒法回滾,或者回滾後數據丟失的問題。
  • 注意第五步和第六步最好分開進行,也就是說不要一次就改單讀和單寫,否則在發佈代碼的過程當中,某些機器仍是舊代碼,這是用戶訪問系統的時候可能先訪問到新機器寫入了數據,而後又訪問到舊機器讀的是舊錶,這時候就會讀不到剛寫入的數據。這種臨界狀況雖然極端,可是在大訪問量的基數仍是可能出現的

總結

能夠看到,上面的系統升級重構的思路是比較細緻的,可是確實是很是平穩,且不須要停服就能完成升級,即便系統很是的複雜,升級重構的邏輯和存儲結構大變樣也能適用。固然在實際過程當中你們也能夠根據實際狀況(小系統小改動)進行一些步驟的合併或者縮短期。

版權聲明

轉載請註明做者和文章出處
做者: X先生
http://www.javashuo.com/article/p-hufrzoqx-nk.html

以爲不錯的話請幫忙收藏點贊~

相關文章
相關標籤/搜索