日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

代码迁移之旅(二)- 渐进式迁移方案

發布時間:2025/4/16 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 代码迁移之旅(二)- 渐进式迁移方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說在前面

這是代碼遷移的第二篇文章,也是最后一篇了,由于個人原因,原來的遷移我無法繼續參與了,但完整的方案我已經準備好了,在測試環境也已經可以正常進行了。 上篇文章 代碼重構之旅(一) 項目結構 介紹了遷移代碼的前期準備和項目結構的設計,本篇文章來介紹一下可實施的遷移方案。

使代碼的遷移過程更簡單、更安全是我們要追求的目標,在遷移之前,代碼的可用性我們一定也只能畫一個問號。

文章歡迎轉載,但請注明來源:http://www.cnblogs.com/zhenbianshu/p/8110912.html, 謝謝。


問題抽象分析

首先要看一下一次完整的遷移需要滿足什么要求:

  • 灰度發布,誰也無法保證一次將整個系統遷移到另一個系統不會發生問題,而以接口或接口部分流量為單位進行遷移則可以大大提升可控性。
  • 客戶端無感知,即遷移平滑,長時間的系統不可用是完全無法接受的。
  • 可回滾,一旦出現異常問題可以快速回滾,避免造成較大影響。
  • 易實現,盡量避免大量地操作,操作多意味著犯錯的可能性更大,回滾的難度也大。

只有實現了以上要求,才算是一次成功的遷移。那么先分析一下目前的情況:

如上圖是我們兩個系統的目前狀態:

  • 兩個系統共享一個 Nginx 服務器,而且在 Nginx 中,由于新老系統的 Host::Ip 也不需要變動,所以新老系統還共享一個同一個 Server。
  • 新舊兩個模塊分別對應著兩個版本控制目錄,舊模塊將 Http 請求進行 url 重寫后直接分發到各 PHP 腳本,例如:rewrite ^/api/common/test.json?(.*)$ /api_test.php?$1;
  • 新模塊將 Http 請求直接分發到 index.php 后,由 index.php 進行內部路由轉發。

兩個模塊初始狀態相安無事,現在的問題是如何將舊模塊的接口逐漸過渡到新模塊中。由于舊模塊的分發入口在 Nginx 中,最簡單的辦法自然是修改其原來的重定向規則。


Nginx重定向

先看一個典型的 Nginx Http 服務器配置:

http {upstream stream_name{}server {listen port;server_name domain_name host_name;rewrite ori destA;location pathA {rewrite ori destB type;}location pathB {if(match){rewrite ori destC type;}rewrite ori destD type; }} }

我們要使用的就是 Nginx 強大的路由重定向功能。

location

location 是一個 URI 捕獲語句,它被定義在 server 模塊內,會對 server 內的所有請求進行 uri 匹配,一旦匹配,則進入 location 模塊內部執行。

location 常見的使用形式是:

location path_pattern {operation; }

它的 path_pattern 有以下幾種形式,優先級從高到低為:

  • 完全相等匹配 location = uri {}
  • 前綴匹配 location prefix {} 或 location ^prefix ~ {}
  • 正則匹配 location ~ regex {} 或不區分大小寫正則匹配 location *~ regex {}
  • 通用匹配 location / {}
  • 不同的 pattern 類型匹配順序與定義順序無關,而是由優先級從高到低進行匹配,同一類型的,優先使用 pattern 串更長的進行匹配,因為長串會更精確。

    它的 operation 一般是 rewrite 或 proxy_pass 語句,對捕獲到的請求進行重寫或轉發。用于轉發的 proxy_pass 語句很簡單, proxy_pass proxy_name; 即可,下面具體說一下路由重寫功能。

    if

    if 語句可以對 uri 進行更加靈活的判斷和操作,它的常見使用形式是:

    if (match) {rewrite ori destA type; }rewrite ori destB type;

    在 match 語句中,可以使用如 $request_uri 等全局變量,常見的還有 $query_string,$uri,$remote_addr等。

    但是需要注意使用 if 語句是十分低效的行為,它就像普通的代碼一樣,每個 Http 請求碰到 if 語句都會進行一次 match 計算并判斷,雖然寫在 location 內部會好一些,但最好還是極力避免此語句。

    rewrite

    rewrite 是對匹配到的請求進行 uri 重寫,它可以被寫在 server/location/if 模塊中,使用方式 是 rewrite ori dest type;。在 server 模塊中,rewrite 和 location 的執行順序為:server中的rewrite -> location -> location中的rewrite

    我們可以使用正則或全相等來匹配 ori,并將正則結果應用于 dest 上,如 rewrite ^/api/common/test.json?(.*)$ /api_test.php?$1; 則將 ori 內部的 query_string 匹配出來并使用 $1 賦值給 dest。

    rewrite 默認將 uri 重寫后并不直接將請求分發到 CGI,而是將結果 uri 作為一個新的請求再次進行 server 模塊內處理,如果循環重入超 10 次 nginx 會直接返回 500 internal server error,而控制 rewrite 匹配后的行為 主要依靠其 type 參數:

    • last 結束此模塊(server/location) 匹配,并重入 server 模塊處理,rewrite 默認使用此項;
    • break 結束所有模塊匹配,直接將請求分發到 CGI;
    • redirect 直接分發請求,返回 Http 狀態碼 302 臨時重定向;
    • permanment 直接分發請求,返回 Http 狀態碼 301 永久重定向;

    應用

    介紹完了 Nginx 的重定向功能,還需要考慮怎么使用此功能進行代碼的過渡。

  • 使用 location 捕獲對應接口;
  • 使用 if 進行部分流量分發(可選);
  • 將請求 rewrite 到新模塊。
  • 如:

    location ~ /api/test.json { # 匹配到 test 接口if ($remote_addr ~* 1$) { # 分流 IP 末位為 1 的請求root new_dir/public; # 設置新項目的目錄為根目錄rewrite ^(.*)$ /index.php$1 break; # 將請求分發到新項目的 index.php 入口文件}rewrite ^/api/test.json?(.*)$ /api_test.php?$1; # IP 末位不為 1 的請求繼續訪問舊項目 }

    Linux鏈接

    如上,我們發現如果針對每個接口進行一次 location 重定向,都需要寫 7 行代碼,即使不用 if 語句(多數情況如此),每次也需要 4 行代碼。

    location ~ /api/test.json { # 匹配到 test 接口root new_dir/public; # 設置新項目的目錄為根目錄rewrite ^(.*)$ /index.php$1 break; # 將請求分發到新項目的 index.php 入口文件 }

    如此下來,項目如果有 100 個接口,那么維護這100個 location 模塊也頗為廢勁。其實更多時刻,我們并不需要使用 location 語句,直接在 server 模塊內部使用 rewrite 即可,而阻止我們直接使用 rewrite 的,就是由于新舊模塊不在同一文件夾下,我們必須使用 root 語句將根目錄定義到新項目下。至于為什么不將新舊項目的父文件夾定義為 root,是因為舊項目中有一些路徑可能會有深坑。

    這里我們可以使用 linux 的 軟鏈接 來 把新項目“放置”在舊項目下:linux 中軟鏈接的功能就像 windows 中的快捷方式一樣,是一個指向文件或真實目錄的符號。至于其實現,就要說到 linux 文件結構中的重要概念 inode 了,不過這里不再多提。

    使用?ln -s /path/to/dir_new /path/to/dir_old/yaf 在舊項目目錄下創建一個 yaf 軟鏈接指向新項目目錄;

    這樣,就可以以舊項目目錄為根目錄,找到新項目目錄下的文件了,使用單行命令 rewrite ^(/api/test.json(.*)$) /yaf/public/index.php$1 break; 即可。


    框架內URL重寫

    通過上面 Nginx 的重定向,所有的請求都會被分發到 index.php 中, 接下來就需要在 yaf 內對 index.php 接收到的 Http 請求進行內部分發。

    yaf 提供了 Yaf_Route_Static、Yaf_Route_Simple、Yaf_Route_Supervar、Yaf_Route_Map、Yaf_Route_Rewrite、Yaf_Route_Regex 六種路由方式,各有其適合的場景,需要在 /conf/application.ini 中配置 application.dispatcher.defaultRoute.type="type"。

    我們的內部接口名完全不規則,有改寫為 .json 后綴的,也有保持 .php 的,有帶下劃線的,也有大小寫敏感的,找不到什么規律,于是使用了 map 類型,直接匹配 uri 然后映射向 controller 類。

    我們將 uri 和controller的映射統一保存在一個文件內,形如:

    return array(// 接口作用'key' => array('type' => 'rewrite', 'match' => '/api/test.json', 'route' => array('controller' => 'Api_Test'),),...);

    然后在 Bootstrap.php 內加載此配置文件:

    public function _initRouter() {$router = \Yaf\Dispatcher::getInstance()->getRouter();$config = getConfig('rewrite_file_name');$router->addConfig($config);}

    自此,關于遷移的配置就完成了。


    測試

    一次安全的遷移,完整的測試當然必不可少。在保證技術方案沒問題的前提下,還要進行完整的業務邏輯測試。在 QA 測試之前,開發首先要通過盡可能完整的測試,將 BUG 率降到最低。

    我們的系統對外提供服務都是通過接口,這也方便了我們進行測試。為了保證測試的完整性,可以將線上流量引入到新代碼中進行測試,而實行請求導流的最好媒介就是日志。

    一般來說,服務器都有完整的線上請求日志,如果有必要,在給特定接口添加特定日志以配合測試也是可以的。接入線上日志,構造跟線上一樣的請求到測試服務器,再對比原始服務器的響應內容,將異常響應記錄下來由開發分析并查找原因,直到最后新舊項目對所有請求的響應完全一致。


    小結

    項目的重構不是一個小事,特別是大規模的項目代碼遷移,執行它必須膽大心細,但每一次重構,無論是對自己的技術能力還是項目的生命周期都是很大的提升。

    雖然不鼓勵沒事就瞎折騰代碼,但一定要時刻警惕,走出代碼的舒適區,一定要提前預防根治代碼疾病,不要在代碼已經無可救藥時才想到重構。

    技術發展迅速,代碼總有過時的一天,所以經常對代碼有目的有計劃的小幅優化是非常有意義的。

    關于本文有什么問題可以在下面留言交流,如果您覺得本文對您有幫助,可以點擊下面的 推薦 支持一下我,博客一直在更新,歡迎 關注

    轉載于:https://www.cnblogs.com/zhenbianshu/p/8110912.html

    總結

    以上是生活随笔為你收集整理的代码迁移之旅(二)- 渐进式迁移方案的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。