• 灰度发布


    一、什么是灰度发布?

    灰度发布就是将自己的产品首先拿出来给一部分目标人群使用,通过她们的使用结果和反馈来修改产品的一些不足,做到查漏补缺,完善产品的功能,使产品的质量得到提高。这样产品尽早的与用户接触能为以后产品的正式发布打下基础。

    二、灰度发布的步骤

    1)定义目标
    2)选定策略:包括用户规模、发布频率、功能覆盖度、回滚策略、运营策略、新旧系统部署策略等
    3)筛选用户:包括用户特征、用户数量、用户常用功能、用户范围等
    4)部署系统:部署新系统、部署用户行为分析系统(web analytics)、设定分流规则、运营数据分析、分流规则微调
    5)发布总结:用户行为分析报告、用户问卷调查、社会化媒体意见收集、形成产品功能改进列表
    6)产品完善
    7)新一轮灰度发布或完整发布

    三、作用

    灰度发布系统的作用在于,可以根据自己的配置,来将用户的流量导到新上线的系统上,来快速验证新的功能修改,而一旦出问题,也可以马上的恢复,简单的说,就是一套A/BTest系统。

    其中分为几个部分:

    • 接入层,接入客户端请求,根据下发的配置将符合条件的请求转发到新旧系统上.
    • 配置管理后台,这个后台可以配置不同的转发策略给接入层.
    • 新旧两种处理客户端请求的业务服务器.

    四、灰度发布的一些问题

    (1)样本选择要多样化,样本的组合涵盖大部分核心功能
    (2)产品设计考虑产品量化指标,结果分析依据量化指标而不是感觉
    (3)前期产品策划重点考虑这些问题,包括:回滚方案、 新旧系统兼容方案、用户体验的一致性、用户使用习惯的延续性、新旧系统数据模型兼容性
    (4)善待吃螃蟹的样本用户,包括给予参与测试的用户小奖励
    (5)通过邮件、论坛、社区、Blog、Twitter等新媒体与用户形成互动
    (6)提供产品功能向导。在hotmail最近的升级后的功能tip,gmail的tip都有类似的产品功能导向。在产品中会提示类似于:你知道吗,xx还提供xx功能,通过它你可以xx 。

    五、Nginx实现灰度发布

    灰度发布常见一般有三种方式:

    • Nginx+LUA方式
    • 使用http头信息判断+权重实现灰度发布
    • 通过调节负载均衡权重实现灰度发布

    方式一:使用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;
    }
    

    方式二:通过调节负载均衡权重

    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来实现,但是这种方式只适合修改节点的行为,而且要求应用都是一模一样的,其实质作用是,节点增加或删除之后,对负载能力的调节,最终目的是为了让流量最终保持均衡。

    方式三:使用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, "/");
    }
    ?>
    

    不同的方式

    (1)根据Cookie判断
    1、通过nginx配置的IF指令
    根据Cookie查询Cookie键为version的值,如果该Cookie值为V1则转发到hilinux_01,为V2则转发到hilinux_02。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

    upstream hilinux_01 {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream hilinux_02 {
        server 192.168.1.200:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream default {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    server {
      listen 80;
      server_name  www.hi-linux.com;
      access_log  logs/www.hi-linux.com.log  main;
    
      #match cookie
      set $group "default";
        if ($http_cookie ~* "version=V1"){
            set $group hilinux_01;
        }
    
        if ($http_cookie ~* "version=V2"){
            set $group hilinux_02;
        }
    
      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;
      }
     }
    

    2、通过map指令
    在Nginx里面配置一个映射,$COOKIE_version可以解析出Cookie里面的version字段。$group是一个变量,{}里面是映射规则。

    如果一个version为V1的用户来访问,$group就等于hilinux_01。在server里面使用就会代理到http://hilinux_01上。version为V2的用户来访问,$group就等于hilinux_02。在server里面使用就会代理到http://hilinux_02上。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

    upstream hilinux_01 {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream hilinux_02 {
        server 192.168.1.200:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream default {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    map $COOKIE_version $group {
    ~*V1$ hilinux_01;
    ~*V2$ hilinux_02;
    default default;
    }
    
    server {
      listen 80;
      server_name  www.hi-linux.com;
      access_log  logs/www.hi-linux.com.log  main;
    
      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;
      }
     }
    

    3、Nginx根据来路IP
    如果是内部IP,则反向代理到hilinux_02(预发布环境);如果不是则反向代理到hilinux_01(生产环境)。

    upstream hilinux_01 {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream hilinux_02 {
        server 192.168.1.200:8080 max_fails=1 fail_timeout=60;
    }
    
    upstream default {
        server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
    }
    
    server {
      listen 80;
      server_name  www.hi-linux.com;
      access_log  logs/www.hi-linux.com.log  main;
    
      set $group default;
      if ($remote_addr ~ "211.118.119.11") {
          set $group hilinux_02;
      }
    
    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;
      }
    }
    

    如果你只有单台服务器,可以根据不同的IP设置不同的网站根目录来达到相同的目的。

    server {
      listen 80;
      server_name  www.hi-linux.com;
      access_log  logs/www.hi-linux.com.log  main;
    
      set $rootdir "/var/www/html";
        if ($remote_addr ~ "211.118.119.11") {
           set $rootdir "/var/www/test";
        }
    
        location / {
          root $rootdir;
        }
    }
    

    更具细颗粒度的灰度发布

    ABTestingGateway是新浪开源的一个动态路由系统。ABTestingGateway是一个可以动态设置分流策略的灰度发布系统,工作在7层,基于nginx和ngx-lua开发,使用redis作为分流策略数据库,可以实现动态调度功能。
    ABTestingGateway:https://github.com/CNSRE/ABTestingGateway(比较老了,有新的帮忙推荐下)

  • 相关阅读:
    Java中的多态polymorphism
    Java中的“继承”
    面向对象(Oriented Object Programing)的本质
    Java设计方法原则
    Motor Parameter
    Motor Vocabuary
    JD
    CAN
    多个TXT文件合成一个,输出到excel里
    正则表达式
  • 原文地址:https://www.cnblogs.com/tongxiaoda/p/8473586.html
Copyright © 2020-2023  润新知