灰度发布浅析
定义
灰度发布就是已一种平滑过渡的方式来发布,通过切换线上新旧版本之间的路由权重,逐步从旧版本切换到新版本;比如要上线新功能,首先只是更新少量的服务节点,通过路由权重,让少部分用户体验新版本,如果没有什么问题,再更新所有服务节点;这样可以在出现问题把影响面降到最低,保证了系统的稳定性。
灰度发布
一个系统往往有接入层比如nginx(Openresty),网关层比如zuul,以及服务层比如各种rpc框架;在这几层都有路由功能,也就是说这几层都可以做灰度;接入层可以使用nginx+lua来实现灰度,网关层zuul可以结合ribbon来实现灰度,rpc框架如dubbo本身提供了路由功能可以直接做灰度处理;下面看看具体如何去实现;
接入层灰度
接入层我们这里使用功能更强大的Openresty,然后使用lua进行路由转发,相关的路由策略可以配置在分布式缓存redis里面,当然也可以持久化到数据库里面;
- 准备
准备一台Openresty,两台web服务器tomcat(端口分别是8081,8082),以及redis;为了方便模拟在redis里面配置白名单,如果在白名单里面就走8082,不在则走8081;
- Openresty配置
需要在Openresty中配置支持lua,以及相关路由的lua脚本,nginx.conf配置如下:
http { ... lua_package_path "/lualib/?.lua;;"; #lua 模块 lua_package_cpath "/lualib/?.so;;"; #c模块 upstream tomcat1 { server 127.0.0.1:8081; } upstream tomcat2 { server 127.0.0.1:8082; } server { listen 80; server_name localhost; location / { content_by_lua_file lua/gray.lua; } location @tomcat1 { proxy_pass http://tomcat1; } location @tomcat2 { proxy_pass http://tomcat2; } } ... }
配置了所有请求都会经过lua目录下的gray.lua脚本,如下所示:
local redis = require "resty.redis"; local redis_obj = redis:new(); redis_obj:set_timeout(2000); local ok,err = redis_obj:connect("127.0.0.1", 6379); if not ok then ngx.say("failed to connect redis ",err); return; end --获取请求ip local_ip = ngx.var.remote_addr; --redis中获取白名单 local whitelist = redis_obj:get("whitelist"); --判断是否在白名单然后转到对应服务 if string.find(whitelist,local_ip) == nil then ngx.exec("@tomcat1"); else ngx.exec("@tomcat2"); end local ok,err = redis_obj:close();
Openresty内置的功能模块可以直接连接redis,然后从redis里面取出白名单,看当前的请求ip是否在白名单内,然后做简单的路由功能;可以动态修改redis里面的白名单,实时更新。
localhost:0>set whitelist 127.0.0.1 "OK" localhost:0>get whitelist "127.0.0.1"
- 启动测试
分别启动tomcat1,tomcat2以及Openresty,访问http://localhost即可,可以动态修改redis里面的白名单,然后访问查看结果验证。
网关层灰度
网关层已zuul为例,zuul的灰度需要修改ribbon的负载策略,就是根据eureka的metadata进行自定义元数据,然后修改ribbon的策略规则;
- 准备
测试服务分别准备两台端口分别为:8765,8766,application.yml配置如下:
server: port: 8765 eureka: instance: metadata-map: route: 1
同时准备请求地址/hiGray,返回值为route1;
server: port: 8766 eureka: instance: metadata-map: route: 2
同时准备请求地址/hiGray,返回值为route2;用于区分是否走了灰度服务器;然后在zuul端需要引入一个插件:
<dependency> <groupId>io.jmnarloch</groupId> <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId> <version>2.1.0</version> </dependency>
然后需要准备一个pre类型的filter,具体如下:
@Configuration public class GrayFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String ip = request.getRemoteAddr(); //ipv6本地地址,也就是127.0.0.1 if ("0:0:0:0:0:0:0:1".equals(ip)) { RibbonFilterContextHolder.getCurrentContext() .add("route", "1"); } else { RibbonFilterContextHolder.getCurrentContext() .add("route", "2"); } return null; } ... }
以上也是使用白名单为例子,这里为了方便就没有把白名单配置在redis里面,配置的白名单地址为ipv6:0:0:0:0:0:0:0:1,如果是白名单地址则路由到8765端口服务,否则为8766端口服务;
- 测试
分别启动eureka-server,两个eureka-client,以及zuul网关,访问网关地址即可;分别通过127.0.0.1和本地ip访问即可测试;
服务层灰度
服务器已rpc框架dubbo为例,dubbo本身提供了各种路由规则包括:条件路由,脚本路由等,这里同样使用脚本路由为例,脚本路由规则支持JDK 脚本引擎的所有脚本,比如:javascript, jruby, groovy 等,这里使用缺省的JavaScript为例;
- 准备
注册中心zookeeper,两台Provider可以在本地分别指定端口为20881和20882,消费者,以及下面重点介绍的路由脚本:
function gray_rule(invokers, context) { var tag = context.getAttachment("tag"); var result = new java.util.ArrayList(invokers.size()); if(tag == "gray"){ for (i = 0; i < invokers.size(); i ++) { if (invokers.get(i).getUrl().getPort()==20881) { result.add(invokers.get(i)); } } } else { for (i = 0; i < invokers.size(); i ++) { if (invokers.get(i).getUrl().getPort()==20882) { result.add(invokers.get(i)); } } } return result; } (invokers,context)
dubbo在运行脚本的时候会传入三个参数分别是:invokers,Invocation以及RpcContext.getContext();通过在消费端在RpcContext中设置tag:
RpcContext.getContext().setAttachment("tag", "gray");
这样就可以在脚本中进行判断,tag为gray的消费端才走20881端口的服务端,其余走20882服务端;
以上的脚本需要注册到zookeeper中,手动注册代码如下,当然也可以使用dubbo提供的dubbo-admin来设置路由脚本:
URL registryUrl = URL.valueOf("zookeeper://127.0.0.1:2181"); ZookeeperRegistryFactory zookeeperRegistryFactory = new ZookeeperRegistryFactory(); zookeeperRegistryFactory.setZookeeperTransporter(new CuratorZookeeperTransporter()); Registry zookeeperRegistry = (ZookeeperRegistry) zookeeperRegistryFactory.createRegistry(registryUrl); URL routerURL = URL.valueOf("script://0.0.0.0/com.dubboApi.DemoService?category=routers&dynamic=false"); routerURL = routerURL.addParameter("rule", URL.encode("(..JavaScript脚本..)")); zookeeperRegistry.register(routerURL); // 注册
具体可以参考官方文档:旧路由规则
- 测试
启动zookeeper,然后分别启动两台生产者,启动消费者时通过修改tag然后观察路由;
总结
本文分别从接入层,网关层,服务层这三层简要的介绍了通过路由规则来实现灰度发布;已每层比较典型的中间件来介绍具体如何去实现简单的灰度发布;总体来说就是使用中间件的路由功能,动态加载外部自定义的一些路由策略脚本,以此来达到灰度发布的目的。
代码地址
感谢关注
可以关注微信公众号 「 回滚吧代码 」,第一时间阅读,文章持续更新;专注Java源码、架构、算法和面试

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
年轻人不讲武德,上班摸鱼,监控老板行踪!
虽然已融入打工人队伍多年,但学生时代,老师站在后窗外的阴影依然挥之不去。在刷头条,看B站的时候,总是担心着老板来了! 直到有了ESP-EYE 低成本的人脸识别开发板,结合云上IoT物联网服务,轻松搞定老板行踪监控。无论老板从何处来,钉钉摸鱼群总会收到实时提醒。 一、技术方案 首先,众筹一块ESP-EYE本地人脸识别开发板;其次,录入老板人脸信息;然后,把开发板连接云端IoT物联网平台;接着,通过规则引擎把数据流转到函数计算;最后,函数计算中调用钉钉群机器人,完成老板来了告警! 二、ESP-EYE人脸识别 ESP-EYE 是一款专注于本地图像识别的开发板,板载ESP32芯片,集成200万像素摄像头,拥有8 MByte PSRAM和4 MByte flash的丰富存储,支持Wi-Fi图像传输与Micro USB调试与供电,可广泛应用于 AI 智能物联网领域的应用开发。 2.1 烧录人脸识别程序 我们基于 Arduino编程来降低ESP-EYE人脸识别程序开发难度。 首先,我们在 Preferences 中新增 arduino-esp32 配置URL: https://raw.githubu...
- 下一篇
Android 样式系统 | 主题背景属性
在 Android 样式系统系列的前几篇文章中,我们介绍了主题背景与样式的区别,以及为什么说通过主题背景和公共主题背景属性来分解您要实现的内容是一个不错的主意,请点击链接回顾: Android 样式系统 | 主题背景和样式 Android 样式系统 | 常见的主题背景属性 这会让我们通过创建更少的布局或样式,以隔离主题背景中的修改。在实际开发中,您通常希望根据主题背景改变颜色,因此您应该始终通过主题背景属性来引用颜色。 这意味着您可以将如下代码视为有代码异味 (Code smell): <!-- Copyright 2019 Google LLC. SPDX-License-Identifier: Apache-2.0 --> <View … android:background="@color/white"/> 相反,您应该使用主题背景属性,它允许您按主题更改颜色,例如,在 深色主题 中提供一个不同的值: <!-- Copyright 2019 Google LLC. SPDX-License-Identifier: Apache-2.0 --> ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS关闭SELinux安全模块
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker使用Oracle官方镜像安装(12C,18C,19C)