歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 自動增量升級方案的設計及實現

自動增量升級方案的設計及實現

日期:2017/2/27 15:58:54   编辑:Linux教程
問題背景:
1. 能否以某種簡便甚至自動化的方式,將修改過的文件以增量的方式同步到線上而不影響應用的正常運行。
2. 除了文件同步外,能否自定義某些腳本,在升級時自動執行。
3. 如果發現升級後的版本有問題,能否快速回滾到原來的版本。

寫作目的:
1. 以SVN為例子,學會基於版本庫的自動增量升級。
2. 無需依賴任何文件同步工具,只需簡單的幾個shell腳本便可完成從自動增量打包到自動增量升級的整個過程。

適合閱讀對象:
1. 想從繁瑣乏味的升級工作中解放出來的運維人員。
2. 擔心因修改文件數目多而可能導致升級遺漏的開發人員(尤其是web項目開發者)。
3. 想了解自動增量升級設計思想的人員。

不涉及的內容:
1. 暫未包含基於hg或git版本庫的增量升級的實現,但思路與SVN是類似的。
2. 本文側重業務應用的增量升級,不涉及個人軟件或者系統軟件的增量升級,盡管這兩者存在一些相似的地方。

腳本下載地址:
https://github.com/joerong666/auto_patch.git

正文:
增量升級這個名詞相信已經不是什麼新鮮事物了,甚至我們每天在不經意間也已經做了該事。比如windows的自動更新,就是增量更新的一種。先撇開系統軟件的升級不說,作為一個業務應用開發者,筆者這裡就自己所了解,介紹一下業務應用在做增量升級方面都采用哪些方法。

升級方法比較:
方法一:逐個文件拷貝覆蓋
這個是最原始的增量升級方式,雖然簡單,但繁瑣且易漏易錯,相信稍有點規模的應用都不會采用這種方式。想想如果有分布在不同子目錄中的上百個文件被修改過了,你得執行拷貝覆蓋多少次,更悲催的是,你花了九牛二虎之力才把文件拷貝好,結果卻發現覆蓋錯了。

方法二:使用類似rsync的文件同步服務器
相對來說,使用rsync可以確保文件不會被誤覆蓋,也能保持目錄結構的一致性。但個人覺得這只是一種文件同步,跟升級還是有一定的區別,如果我們的升級僅僅是涉及文件的覆蓋或刪除,或許采用rsync是一個不錯的選擇。但如果想在升級的同時自動執行某些定制的程序或腳本,那麼rsync就顯得有點愛莫能助了。另外rsync的引入,也需要額外的成本去搭建和監控它,自然也就需要額外的維護成本。而且rsync與版本庫的無縫結合也是個值得考驗的問題,能否由rsync直接從版本庫中獲取增量的部分,還是得額外寫個腳本將增量部分寫到rsync的同步目錄中,再由rsync客戶端來獲取?

方法三:由開發人員手工編寫升級腳本
一般來說,采用這種方法,首先需要開發人員記錄下哪些文件涉及改動,當然可通過查看版本歷史的方式來判斷哪些文件需要做更新;然後再針對這些文件,逐條編寫相應的用於覆蓋或刪除線上應用的copy或rm語句;最後將包含這些語句的腳本隨增量文件一起打包給運維人員,讓運維人員到線上執行。從可靠性的方面考慮,這種方式還不如第二種方法,但相對來說,這種方式的可控性比較靈活,可以靈活自定義升級腳本,而不是簡單的同步文件。比如可以定義在升級的同時執行某個特定的程序,最常見的就是在升級的同時重啟原來的某些服務。

方法四:自動增量升級
該方法是對方法三的一種增強,一方面是升級腳本是根據版本歷史自動生成的,不再需要人工編寫;另一方面,支持自定義升級擴展,也就說除了生成簡單的增量覆蓋升級腳本外,還支持以可插拔式的方式將自定制的程序讓升級腳本自動執行。這是筆者選擇的升級方法,也是本文的講述重點。下面針對這種方法具體展開描述。

自動增量升級:
下面先從流程方面來大概介紹一下自動增量升級的整個思路,然後再從程序的角度解釋一下本文中所涉及的腳本的作用。

升級流程:
升級流程分兩個階段,第一階段為增量打包操作,一般由開發人員執行;第二階段為升級操作,可由運維人員執行。

增量打包流程:
流程描述:更新版本庫 ===> 生成增量清單文件 ===> 檢查並修剪清單文件(以及編寫自定義升級程序) ===> 生成增量補丁包
對應命令或腳本:svn update ===> gen_manifest.sh(需將結果重定向到PATCH_MANIFEST清單文件) ===> 添加或刪除清單文件(PATCH_MANIFEST)中無需做更新的記錄(同時根據需要編寫想讓升級程序自動執行的腳本,如demo_custom_script.sh) ===> gen_patch.sh

升級流程:
流程描述:獲取增量包 ===> 執行升級操作並生成增量包的回滾備份包
對應命令或腳本:可通過wget獲取增量包 ===> patch.sh(執行完後會生成增量回滾包,如patch_recover_20130626113450)

程序解釋:
生成清單文件gen_manifest.sh:
$ ./gen_manifest.sh
Usage: ./gen_manifest.sh revision1[:revision2] [sub_dir]
該腳本用於生成增量清單文件,既然是增量,就需要有一個相對版本,所以至少需要傳入revision1這個版本參數,其值為上次程序發布時的版本庫版本號加1。默認情況,該腳本會生成當前目錄及其所有子目錄下(遞歸)的增量清單,如果只需要針對某個子目錄,則可指定sub_dir。因一般情況下該腳本生成出來的清單都需做一定的修剪,為了可直接供管道使用,這裡並沒有讓它輸出到文件,而是直接輸出到標准輸出,使用者可根據需要直接重定向到PATCH_MANIFEST(這個文件名是gen_patch.sh腳本約定好使用的,不能為其它名字)文件。

清單文件PATCH_MANIFEST,大體如下:
#revision:A/D/C:src_file[:dest_dir]
r2061:A:sub_dir/dir1/a.java
r2065:A:sub_dir/dir2/b.sh
r2069:A:script/dir3/c.ini:sub_dir/script/dir3
#r2111:D:sub_dir/test/kkk/tt.txt
#r2112:A:sub_dir/test/kkk2
#r2112:D:sub_dir/test/kkk
#r2113:A:sub_dir/test/kkk2/tt2.txt
r2124:A:sub_dir/conf/log4j.properties
#r2197:A:sub_dir/conf
#r2197:A:sub_dir/conf/config.conf
xxxxx:A:sub_dir/db/patch.sql
xxxxx:C:patch_script/demo_custom_script.sh:sub_dir/autoscript 

這裡分幾點來解釋一下這個清單文件:
1. 行首帶#號的為注釋行,gen_patch.sh不會解析。由於有些配置文件(如這裡的config.conf)我們在版本庫上雖做了修改,但我們不能更新到線上應用去,畢竟配置不一樣,故直接把相應的行注釋掉即可(注意記得把相應的目錄也注釋掉,如這裡的”#r2197:A:sub_dir/conf“行)。

2. 第一行是一個樣例,標識每行記錄需遵守的格式,一行最多只有4項,每項用冒號分隔。revision為版本號;A/D/C分別表示為“添加或修改(Add)/刪除(Delete)/自定義命令(Comand)“;src_file為涉及文件在版本庫中的目錄結構;dest_dir(這裡是目錄,而不是文件)為src_file在發布包中的目錄結構,如果沒指定則表示涉及的文件在版本庫和發布包中的目錄結構一樣。

3.後面的版本號為xxxxx的行是一些自定義操作行,這些操作並沒有或者無法在版本庫中體現。如
xxxxx:A:sub_dir/db/patch.sql ===> patch.sql文件在指定的版本號范圍內並沒有相應的更改歷史,也許它根本就不在版本庫內,但我們又想讓它隨本次的增量包拷貝到線上應用去,所以采用這種定制的方式委婉的將它納入增量包中。

4.值得注意的是操作為"C"的行,如這裡的最後一行:
xxxxx:C:patch_script/demo_custom_script.sh:sub_dir/autoscript ===>C操作的行並非簡單的表示將src_file拷貝到dest_dir,事實上它並沒有被拷貝到線上應用中去,而只是僅僅打進增量包中,然後作為一種自動化的程序,在運維人員執行升級(patch.sh)操作時被自動執行的程序,有點被回調的味道。該程序一般需要開發人員根據實際需要編寫,一般是一些執行服務的操作,如重啟某些服務。如這裡提到的demo_custom_script.sh:
自定義升級腳本demo_custom_script.sh:
#!/bin/env bash
 
src_dir=$1  ### 由升級程序patch.sh傳遞進來,表示增量包在線上被解壓的臨時目錄
dest_dir=$2 ### 由升級程序patch.sh傳遞進來,表示線上應用所在的目錄(即patch.sh所在的目錄)
 
export LANG=en_US.UTF-8
 
target_dir=my_target/bin
target_proc=my_service
 
function err_out()
{
echo "Reload my_service failed"    >&2
    exit 1
}
 
cd $dest_dir/$target_dir && \
./my_service reload  ### 升級時(一般是執行完增量清單中的其它操作之後)重啟我的服務
 
if [ $? -ne 0 ]; then
err_out
fi
 
exit 0

生成增量包gen_patch.sh:
$ ./gen_patch.sh
Usage: ./gen_patch.sh <OUTPUT>
<OUTPUT>: patch file like <OUTPUT>-patch20130607.tar.gz will be generated
Attention: a manifest file named 'PATCH_MANIFEST' is needed under current directory

gen_patch.sh的功能很簡單,就是根據之前生成的清單文件PATCH_MANIFEST生成增量包,所以前提是確保清單文件是准確的,當然也可以通過查看生成後的增量包是否符合實際要求來進一步確認。

執行升級操作patch.sh:
$ ./patch.sh
Usage: ./patch.sh patch.tar.gz

顧名思義,該腳本的作用就是用於給當前的應用打上補丁,一般由線上的運維人員執行。該腳本應該在程序第一次發布的時候包含進去,且應該與放置應用代碼的根目錄同級。如下
myapp-1.1.0-rc5-bin-x86_64 |– approot |– app-patch20130624.tar.gz |– patch.sh |– patch_recover_20130613182709 ===> 升級時生成的增量回滾快照 |– patch_20130626.log ===> 升級時執行的日志
其中的app-patch20130624.tar.gz即為前面通過gen_patch.sh生成的增量升級包,而patch_recover_20130613182709目錄是執行升級前自動生成的增量備份,如果發現升級有誤的話,可立即通過將該備份目錄下的內容拷回原來的位置,即可完成回滾。

結束:
雖然前面洋洋灑灑寫了好多,感覺好像很復雜的樣子,其實想要表達意思的很簡單,就下面三個步驟:
生成增量包:
$ ./gen_manifest.sh 2061 >PATCH_MANIFEST
$ ./gen_patch.sh app ===>生成app-patch20130624.tar.gz

執行升級:
$ ./patch.sh app-patch20130624.tar.gz
Copyright © Linux教程網 All Rights Reserved