温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何理解灰度发布

发布时间:2021-10-22 16:48:02 来源:亿速云 阅读:121 作者:iii 栏目:编程语言

这篇文章主要讲解了“如何理解灰度发布”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解灰度发布”吧!

定义

灰度发布就是已一种平滑过渡的方式来发布,通过切换线上新旧版本之间的路由权重,逐步从旧版本切换到新版本;比如要上线新功能,首先只是更新少量的服务节点,通过路由权重,让少部分用户体验新版本,如果没有什么问题,再更新所有服务节点;这样可以在出现问题把影响面降到最低,保证了系统的稳定性。

灰度发布

一个系统往往有接入层比如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--获取请求iplocal_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");endlocal 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: 8765eureka:
  instance:metadata-map:  route: 1

同时准备请求地址/hiGray,返回值为route1;

server:
  port: 8766eureka:
  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,具体如下:

@Configurationpublic class GrayFilter extends ZuulFilter {@Overridepublic Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String ip = request.getRemoteAddr();//ipv6本地地址,也就是127.0.0.1if ("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然后观察路由

感谢各位的阅读,以上就是“如何理解灰度发布”的内容了,经过本文的学习后,相信大家对如何理解灰度发布这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI