场景
现在有一个 java 语言编写的服务接口需要做升级优化,为了确保原来的接口有用,也需要保证新的接口也可以使用,故需要做一次灰度发布。
场景设置
准备工作
DDTrace 采集器用于采集链路信息,进入到 DataKit 安装目录下,执行 conf.d/ddtrace/ ,复制 ddtrace.conf.sample 并重命名为 ddtrace.conf ,在 ddtrace.conf 配置新增 customer_tags=["test_flag"] ,将对应的 Baggage 转化为 tag 。
应用
调整应用的启动命令,假设端口 8091 为旧的接口应用。
 java \-javaagent:/home/liurui/agent/dd-java-agent-1.30.1-guance.jar \-Ddd.service.name=server \-Ddd.trace.header.baggage=test-flag:test_flag \-Dserver.port=8091 \-jar springboot-server.jar
       复制代码
 
端口 8092 为优化后的接口应用。
 java \-javaagent:/home/liurui/agent/dd-java-agent-1.30.1-guance.jar \-Ddd.service.name=server \-Ddd.trace.header.baggage=test-flag:test_flag \-Dserver.port=8092 \-jar springboot-server.jar --client=true
       复制代码
 
启动参数上基本上没啥区别。8092 添加了 --client=true ,会对请求造成异常,假设这个是新的代码调整。
Nginx 配置
采用 nginx 来实现业务分流操作,比如 user_agent 为 curl 的,让请求新的接口,其他的走原来的通道。同时追加 header,方便进行追踪。如 user_agent 为 curl 的相关请求,将自定义 header 值设置为 20240306 ,其他默认值为 normal 。
 map $http_user_agent $custom_header {      ~*curl "20240306";    default "normal";  }  
       复制代码
 
将 user_agent 为 curl 的请求分流到 backend2 ,默认分流到 backend1 。
 set $upstream_name 'backend1';  if ($http_user_agent ~* "curl") {      set $upstream_name 'backend2';  }
proxy_pass http://$upstream_name;
       复制代码
 
根据不同的 upstream_name 设置不同的 header 值。
 proxy_set_header   Test-Flag $custom_header; # 根据 upstream 地址设置不同的值
       复制代码
 
两个 upstream 。
     upstream backend1 {          server localhost:8091;     }      upstream backend2 {          server localhost:8092;      }  
       复制代码
 
通过 nginx -s reload 重启 nginx 。至此,nginx 配置基本上完成。
 root:/etc/nginx/conf.d# nginx -s reloadinfo: DATADOG TRACER CONFIGURATION - {"agent_url":"http://localhost:9529","analytics_enabled":false,"analytics_sample_rate":null,"date":"2024-03-06T15:30:24+0800","enabled":true,"env":"prod","lang":"cpp","lang_version":"201402","operation_name_override":"nginx.handle","report_hostname":false,"sampling_rules":"[]","service":"nginx","version":"v1.3.7"}
       复制代码
 
这里 nginx 接入了 ddtrace,非必须,如有需要,可参考文档 Nginx Tracing 。
Nginx 全文配置如下:
 map $http_user_agent $custom_header {      ~*curl "20240306";    default "normal";  }  upstream backend1 {      server localhost:8091; }  upstream backend2 {      server localhost:8092;  }  
server {        listen       80;        server_name  www.springboot.com;        client_max_body_size     100m;                location ^~ / {            set $upstream_name 'backend1';                if ($http_user_agent ~* "curl") {                  set $upstream_name 'backend2';              }              add_header 'Access-Control-Allow-Origin' *;            add_header 'Access-Control-Allow-Credentials' 'true';            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';            proxy_pass http://$upstream_name;            proxy_set_header X-datadog-trace-id $opentracing_context_x_datadog_trace_id;            proxy_set_header X-datadog-parent-id $opentracing_context_x_datadog_parent_id;
            proxy_set_header   X-Real-IP         $remote_addr;            proxy_set_header   Host              $http_host;            proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;            proxy_set_header   Test-Flag $custom_header; # 根据 upstream 地址设置不同的值        }
        error_page   500 502 503 504  /50x.html;        location = /50x.html {            root   html;        }     }
       复制代码
 测试
分别通过浏览器和 curl 请求接口 http://www.springboot.com/gateway 。其中 curl 返回结果如下:
 root:/etc/nginx/conf.d# curl www.springboot.com/gateway{"msg":"client 调用失败","code":500}
       复制代码
 
浏览器请求则返回如下信息:
 {"msg":"支付成功","code":200}
       复制代码
 
从观测云上通过链路追踪,可以发现所有的 span 都有 tag 为 test_flag ,其中值为 20240306 的链路为本次新发布的接口。
红色标记代表异常,说明当前链路处于异常状态。通过查看链路详情可以查看到堆栈信息,最终根据调整的代码进行再次发布,通过同样的方式进行再追踪、再验证。
后记
以上实践只是灰度发布的一部分,但笔者认为这是最核心、最重要的:确保业务的更新和正常使用。如何更有效率的确保发版成功,则需借助可观测性能力,让一切变得肉眼可见。
评论