Nginx 实现灰度发布的三种方式

来自Linux78|wiki
Bob讨论 | 贡献2019年11月11日 (一) 14:42的版本 (创建页面,内容为“灰度发布的主要原理是访问路由的控制,重点是保证每次访问的是同一个节点。 ==== 通过调节负载均衡权重 ==== 负载均衡 建…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

灰度发布的主要原理是访问路由的控制,重点是保证每次访问的是同一个节点。

通过调节负载均衡权重

负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

简单配置如下:

http {  
   upstream cluster {  
       ip_hash; #如果你的系统中没有使用第三方缓存管理工具 ,建议使用此方式
       server 192.168.1.210:80 weight=5;  
       server 192.168.1.211:80 weight=3;  
       server 192.168.1.212:80 weight=1;  
   }    
   server {  
       listen 80;  
       location / {  
   proxy_next_upstream     error timeout;
   proxy_redirect          off;
   proxy_set_header        Host $host;
   #proxy_set_header        X-Real-IP $remote_addr;
   proxy_set_header        X-Real-IP $http_x_forwarded_for;
   proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
   client_max_body_size    100m;
   client_body_buffer_size 256k;
   proxy_connect_timeout   180;
   proxy_send_timeout      180;
   proxy_read_timeout      180;
   proxy_buffer_size       8k;
   proxy_buffers           8 64k;
   proxy_busy_buffers_size 128k;
   proxy_temp_file_write_size 128k;
   proxy_pass http://cluster;  
       }  
   }  
}  

这种方式灰度发布通过weight来实现,但是这种方式只适合修改节点的行为,而且要求应用都是一模一样的,其实质作用是,节点增加或删除之后,对负载能力的调节,最终目的是为了让流量最终保持均衡。


使用nginx+lua实现web项目的灰度发布

location / {

content_by_lua '

           myIP = ngx.req.get_headers()["X-Real-IP"]
           if myIP == nil then
               myIP = ngx.req.get_headers()["x_forwarded_for"]
           end
           if myIP == nil then
               myIP = ngx.var.remote_addr
           end
           if myIP == "公司出口IP" then
               ngx.exec("@client")
           else
               ngx.exec("@client_test")
           end
       ';
} 

location @client{

   proxy_next_upstream     error timeout;
   proxy_redirect          off;
   proxy_set_header        Host $host;
   #proxy_set_header        X-Real-IP $remote_addr;
   proxy_set_header        X-Real-IP $http_x_forwarded_for;
   proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
   client_max_body_size    100m;
   client_body_buffer_size 256k;
   proxy_connect_timeout   180;
   proxy_send_timeout      180;
   proxy_read_timeout      180;
   proxy_buffer_size       8k;
   proxy_buffers           8 64k;
   proxy_busy_buffers_size 128k;
   proxy_temp_file_write_size 128k;
   proxy_pass http://client;
}
location @client_test{
   proxy_next_upstream     error timeout;
   proxy_redirect          off;
   proxy_set_header        Host $host;
   #proxy_set_header        X-Real-IP $remote_addr;
   proxy_set_header        X-Real-IP $http_x_forwarded_for;
   proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
   client_max_body_size    100m;
   client_body_buffer_size 256k;
   proxy_connect_timeout   180;
   proxy_send_timeout      180;
   proxy_read_timeout      180;
   proxy_buffer_size       8k;
   proxy_buffers           8 64k;
   proxy_busy_buffers_size 128k;
   proxy_temp_file_write_size 128k;
   proxy_pass http://client_test;
} 

由于使用了nginx+lua模块,这种方式适合很多场景,非常强大,但是问题是你可能需要学习很多lua的语法。


使用http头信息判断+权重(灰度值)

http请求传输过程中,会自动带上User-Agent,Host,Referer,Cookie等信息。我们只需要判断ip地址段,用户代理,Cookie中的信息等。这里以Cookie为例。

当然,这里需要解决两个问题:

①首次访问静态页面可能不会产生cookie

②我们需要通过代码动态设置路由

③通过weight控制灰度值

可以通过一个例子来解决上述中的②与③的问题

upstream tts_V6 {
       server 192.168.3.81:5280 max_fails=1 fail_timeout=60;
}
upstream tts_V7 {
       server 192.168.3.81:5380 max_fails=1 fail_timeout=60;
}
upstream default {   #通过upstream default + weight节点控制权重
       server 192.168.3.81:5280 max_fails=1 fail_timeout=60 weight=5;
       server 192.168.3.81:5380 max_fails=1 fail_timeout=60 weight=1;
}
server {
       listen 80;
       server_name  test.taotaosou.com;
       access_log  logs/test.taotaosou.com.log  main buffer=32k;
       #match cookie
       set $group "default";
       if ($http_cookie ~* "tts_version_id=tts1"){ #动态控制路由
               set $group tts_V6;
       }
       if ($http_cookie ~* "tts_version_id=tts2"){
               set $group tts_V7;
       }
       location / {                       
               proxy_pass http://$group;
               proxy_set_header   Host             $host;
               proxy_set_header   X-Real-IP        $remote_addr;
               proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
               index  index.html index.htm;
      }
}

对于问题①,可以在index页面通过script来访问动态页面:

<script src="https://test.taotaosou.com/cookieinfo.php" /><script>

此外,还要在cookieinfo.php中判断和生成cookie

<?php
if(!session_id())
{
 session_start();
}
if(!isset($_COOKIE["tts_version_id"]))
{
 $cookieValue = $_SERVER['SERVER_PORT']==5280?"tts1":"tts2";
 setcookie("tts_version_id", $cookieValue, time()+3600, "/");
}
?>