定义

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

灰度发布

一个系统往往有接入层比如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端需要引入一个插件:

io.jmnarloch

ribbon-discovery-filter-spring-cloud-starter

2.1.0

然后需要准备一个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源码、架构、算法和面试。

php灰度发布,灰度发布浅析相关推荐

  1. 蓝绿部署滚动部署金丝雀发布(灰度发布)A/B测试

    在一般情况下,升级服务器端应用,需要将应用源码或程序包上传到服务器,然后停止掉老版本服务,再启动新版本.但是这种简单的发布方式存在两个问题,一方面,在新版本升级过程中,服务是暂时中断的,另一方面,如果 ...

  2. 首富带你畅谈:蓝绿部署、滚动发布、灰度发布/金丝雀发布

    首富带你畅谈:蓝绿部署.滚动发布.灰度发布/金丝雀发布 笔者: 张首富 时间: 2019-01-24晚 QQ群: 895291458 博客地址: www.zhangshoufu.com 根据2018年 ...

  3. 线上发版如何做到分批发的?详解蓝绿部署,滚动升级,A/B 测试,灰度发布/金丝雀发布

    过去的 10 年里,很多大公司都在使用蓝绿部署,安全.可靠是这种部署方式的特点.蓝绿部署虽然算不上" Sliver Bullet ",但确实很实用.在有关于"微服务&qu ...

  4. 蓝绿发布金丝雀发布灰度发布滚动发布AB测试

    金丝雀不是说它外形漂亮或有特点,而是说它对瓦斯很灵敏. 这些名字玄而又玄,逼格十分高大上.到底是些啥?好像不了解一下,就完全看不懂当下流行的吹哔哔技术PPT了. 一.蓝绿发布 不停老版本,部署新版本然 ...

  5. 掌门1对1微服务体系Solar第1弹:全链路灰度蓝绿发布智能化实践

    掌门教育自2014年正式转型在线教育以来,秉承"让教育共享智能,让学习高效快乐"的宗旨和愿景,经历云计算.大数据.人工智能.AR/VR/MR以及现今最火的5G,一直坚持用科技赋能教 ...

  6. php免登录接口,PHPWind 8.0 论坛免登陆发布接口发布

    PHPWind 8.0 论坛免登陆发布接口发布 作者:小文 发布于:2010-10-16 9:44 Saturday 分类:免费接口 PHPWind 8.0 论坛免登陆发布接口使用说明 一.功能特性 ...

  7. miui12怎么自定义开机动画_MIUI12正式官宣,5天后发布!网友:发布是发布,12月才能更新?...

    小编在前段时间看到知名数码博主表示小米将会在月底正式发布小米的最新系统MIUI12,而且将会不少重磅的新功能,这不今天MIUI官方正式官宣,MIUI12将和小米的5G新品在5天后,也即时4月27日正式 ...

  8. 微信小程序如何发布?发布流程怎么样

    现如今微信已经是每部手机必装的软件,微信小程序也已经应用到了各个行业生活中是非常广泛的.许多线下实体的店家都想制作微信小程序来进行线上购物模式,那么如何把一个微信小程序搭建起来呢?微信小程序软件代码的 ...

  9. 网站发布网(发布号) 自媒体新闻小偷程序伪静态版 V1.0

    网站发布网(发布号) 自媒体新闻小偷程序伪静态版 V1.0 演示:https://news.aikisport.com/ 下载:https://news.aikisport.com/wzfbw.rar ...

  10. Odometry的发布和发布odom到base_link的tf变换

    这里面我觉得重要的话,而且我还看到了twist,这不正是前阵子普罗米修斯群里问的T265发布的带不带速度信息所说到的twist? 导航包使用tf来确定机器人在世界中的位置,并将传感器数据与静态地图相关 ...

最新文章

  1. scheduled sampling_seq2seq
  2. FESCAR:阿里重磅开源分布式事务解决方案
  3. javascript:闭包的总结
  4. python语言浮点数可以不带小数部分吗_python 浮点数四舍五入需要注意的地方
  5. 计算机网络之数据链路层:9、ALOHA协议-随机访问介质访问控制
  6. mysql 避免重复添加_MySql三种避免重复插入数据的方法
  7. EF+MVC+Bootstrap 项目实践 Day11
  8. 关于nginx file not found
  9. 双系统win+ubuntu14.04使用360随身wifi 3代
  10. iocomp iPlot使用说明13 Limits绘图界限
  11. Java初级程序员面试总结(三)--Lock篇
  12. 单片机|CC2530实验入门
  13. 计算语言学之句法理论(1)
  14. docker下载gcr.io镜像
  15. 一款【免费+简单+好用+性能强大】的词云(Wordcloud)制作工具(含详细介绍)
  16. 如何在知网下载硕士、博士论文PDF?
  17. java校招笔试题目_Java校招笔试题
  18. Android Studio之高德地图实现定位和3D地图显示
  19. 广州先达MES系统在冲压行业的应用
  20. 夜莺:2019年运营微信个人号的3个营销价值

热门文章

  1. sql 预先_预先联合查询
  2. php option explicit,option explicit语句不可以放在
  3. 【树莓派】python3脚本 自动上报ip到万网域名解析
  4. Linux驱动_Beep蜂鸣器
  5. Java实现 LeetCode 173 二叉搜索树迭代器
  6. iMovie剪辑原理
  7. R 中 paste的使用
  8. 项目管理之Scrum
  9. 水货笨叔介绍MCS锁
  10. 大佬打造的400集Python视频合集免费学起来,学完万物皆可爬