代码迁移的一起(二)- 渐进式迁移方案

说于前边

立刻是代码迁移的次篇稿子,也是最终一首了,由于个体因,原来的动迁我无法继续介入了,但整体的方案我一度准备好了,在测试环境也一度好健康开展了。
上篇文章 代码重构之同(一)
项目布局
介绍了搬迁代码的最初准备同种布局的计划,本篇文章来介绍一下可实行的搬方案。

倘若代码的迁徙过程又简约、更安全是咱们要追求的对象,在搬之前,代码的可用性我们肯定为只能写一个问号。

文章欢迎转载,但求注明来源:http://www.cnblogs.com/zhenbianshu/p/8110912.html,
谢谢。


题目抽象分析

首先使扣押一下平等赖完整的搬需要满足什么要求:

  • 灰度发布,谁呢无从确保平等不行用全方位系统迁移到任何一个网不会见生出问题,而因接口或接口部分流量为单位展开搬迁则足以大大升级可控性。
  • 客户端无感知,即搬平滑,长日子的系统未可用是全然无法接受之。
  • 而是回滚,一旦出现异常问题可迅速回滚,避免造成比较充分影响。
  • 易实现,尽量避免大量地操作,操作多表示犯错的可能还怪,回滚的难度啊大。

惟有实现了以上要求,才好不容易一不良得逞的搬迁。那么先分析一下时的景象:

图片 1

比方达到图是咱们有限个网的目前状态:

  • 个别只体系共享一个 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 有以下几种植形式,优先级从赛至低为:

  1. 净相等匹配 location = uri {}
  2. 前方缀匹配 location prefix {}location ^prefix ~ {}
  3. 正巧则相当配 location ~ regex {} 或无分轻重缓急写正则匹配配
    location *~ regex {}
  4. 通用匹配 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 的重定向作用,还亟需考虑怎么下这个功能拓展代码的连片。

  1. 使用 location 捕获对应接口;
  2. 应用 if 进行一些流量分发(可选);
  3. 以请求 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 率降到最低。

我们的网对外提供劳务还是经过接口,这吗便于了咱开展测试。为了确保测试的完整性,可以将丝及流量引入到新代码中开展测试,而实行请求导流的极其好媒介就是日记。

一般的话,服务器都起完全的丝及呼吁日志,如果有必要,在叫一定接口添加特定日志以配合测试呢是足以的。接入线上日志,构造跟线上同的请求到测试服务器,再比原始服务器的应内容,将特别应记录下由开发分析并找原因,直到最后新老路针对富有请求的应完全一致。


小结

种之重构不是一个琐事,特别是广泛的档次代码迁移,执行其必须胆大心细,但每一样糟糕重构,无论是对团结之技艺力量或者项目的生命周期都是可怜非常之晋级。

则不鼓励没事就瞎折腾代码,但得要是时刻警惕,走来代码的舒适区,一定要是提前防备根治代码疾病,不要当代码都无可救药时才想到重构。

艺提高很快,代码总起不合时宜的均等天,所以常对代码有目的来计划之宽窄优化是怪有含义的。

关于本文有什么问题得以在底下留言交流,如果您觉得本文对而发出扶持,可以点击下面的
推荐 支持一下本人,博客一直于创新,欢迎 关注

相关文章