蓝绿发布、金丝雀发布(灰度发布)、AB测试

首先,了解下这几种发布方式的基础概念。

目前常见的发布策略有蓝绿发布、金丝雀发布(灰度发布)、AB测试这几种,在国内的开发者中,对这几个概念有独立的理解。蓝绿发布通常被大家成为热部署;金丝雀发布在国内的名头完全被他的变种发布方式盖过了,主要是灰度发布与AB测试,下面来详细的为大家解释一下他们之间的异同。

蓝绿发布

在发布的过程中用户无感知服务的重启,通常情况下是通过新旧版本并存的方式实现,也就是说在发布的流程中,新的版本和旧的版本是相互热备的,通过切换路由权重的方式(非0即100)实现不同的应用的上线或者下线。

金丝雀发布

通过在线上运行的服务中,新加入少量的新版本的服务,然后从这少量的新版本中快速获得反馈,根据反馈决定最后的交付形态。

灰度发布

灰度发布是通过切换线上并存版本之间的路由权重,逐步从一个版本切换为另一个版本的过程。虽然有很多人包括专业大牛认为灰度发布与金丝雀发布是等同的,但是在具体的操作和目的上面个还是有些许差别的。金丝雀发布更倾向于获取快速的反馈,而灰度发布更倾向于从一个版本到另一个版本平稳的切换。

AB测试

AB测试和灰度发布非常像,但是从发布的目的上,可以简单的区分灰度发布与AB测试,AB测试侧重的是从A版本或者B版本之间的差异,并根据这个结果进行决策。最终选择一个版本进行部署。因此和灰度发布相比,AB测试更倾向于去决策,和金丝雀发布相比,AB测试在权重和流量的切换上更灵活。

在Spring cloud架构体系中基于eureka、ribbon实现灰度发布,是本篇要讲的知识。

我们要发布版本了,在不确定正确性的情况下,我们选择先部分节点升级,然后让一些特定的流量进入到这些新节点,完成测试后再全量发布。

我们知道,在eureka中注册各个服务后,如果一个服务有多个实例,那么默认会走ribbon的软负载均衡来进行分发请求。

我们要完成灰度发布,要做的就是修改ribbon的负载策略(rule),通过一些特定的标识,譬如我们可以选择header里带有foo=1的全部路由到金丝雀服务上,其他的还走原来的老版本。或者可以设置个比重,虽然roll个小于4的正数,将等于1的路由到金丝雀,这样就会有1/4的请求到达金丝雀。诸如此类,我们可以定制各种规则来进行灰度测试。

在SpringCloud体系中,完成这件事,模式比较固定,就是根据eureka的metadata进行自定义元数据,然后修改ribbon的Rule规则。

使用很简单,我们直接上例子,注意我这里只发出来目标服务和zuul的代码,eureka的就不放了。eureka很简单,就是一个eureka server项目,什么也没有。

我们的目标服务是User,在User的application.yml里,由于我要启动2个,所以使用不同的端口

application.yml

server:
port: 8888
eureka:
instance:
prefer-ip-address: true
metadata-map:
lancher: 2
client:
service-url:
defaultZone: http://localhost:10000/eureka/
application-dev.yml
server:
port: 8889
eureka:
instance:
metadata-map:
lancher: 1

就是那个metadata-map元数据,这是一个map,里面就自定义一些key-value键值对。将来匹配时就用这个键值对。
然后分别启动这两个实例,启动后就有两个user注册到了eureka。

zuul配置:

在zuul项目里添加依赖,https://github.com/jmnarloch/ribbon-discovery-filter-spring-cloud-starter

<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>

这个就是做ribbon的Rule的。

package com.example.zuul_route;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import io.jmnarloch.spring.cloud.ribbon.support.RibbonFilterContextHolder;
import org.springframework.context.annotation.Configuration; import javax.servlet.http.HttpServletRequest; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.*; /**
* @author log4geek.cc wrote on 2018/11/17.
*/
@Configuration
public class PreFilter extends ZuulFilter {
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
} @Override
public String filterType() {
return PRE_TYPE;
} @Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
// a filter has already forwarded
// a filter has already determined serviceId
return !ctx.containsKey(FORWARD_TO_KEY)
&& !ctx.containsKey(SERVICE_ID_KEY);
} @Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (request.getParameter("foo") != null) {
// put the serviceId in `RequestContext`
RibbonFilterContextHolder.getCurrentContext()
.add("lancher", "1");
} else {
RibbonFilterContextHolder.getCurrentContext()
.add("lancher", "2");
} return null;
}
}

这个是zuul的filter,关键代码在run方法,

RibbonFilterContextHolder.getCurrentContext() .add("lancher", "1");

这句话就代表将请求路由到metadata-map里lancher为1的那个服务。
整个过程很简单,我们就可以在这里定制各种规则了,把符合什么条件的请求,只发送到某个实例

最新文章

  1. Linux安全基础:grep命令的使用
  2. 攻城狮在路上(贰) Spring(二)--- Spring IoC概念介绍
  3. [Linux] 解决终端显示乱码问题
  4. Python进阶05 循环设计
  5. wcf-1
  6. c++primerplus(第六版)编程题——第4章(复合类型)
  7. 游戏开发设计模式之状态模式 &amp; 有限状态机 &amp; c#委托事件(unity3d 示例实现)
  8. python爬爬(网友提供学习)
  9. Delphi 取外网IP
  10. MFC:重绘Button,定制CButton,自画CPngButton,求赐教(各种bug包括性能bug)谢谢谢谢
  11. AngularJs开发——指令与控制器间的通信
  12. 互怼、IPO、雷潮、寒冬,2018 互联网圈的那些事儿
  13. .Net Core2.0下使用Dapper遇到的问题
  14. ubuntu 安装 eclipse 及其CDT
  15. Day7--------------虚拟机网络服务
  16. 从零开始学 Web 之 Vue.js(一)Vue.js概述,基本结构,指令,事件修饰符,样式
  17. 解决ScrollView嵌套RecyclerView出现item显示不全的问题
  18. ODAC(V9.5.15) 学习笔记(四)TOraDataSet
  19. javascript多种继承方式(函数式,浅复制,深复制,函数绑定和借用)
  20. Qt信号槽的一些事

热门文章

  1. 第08组 Beta冲刺(2/5)
  2. Computer-Hunters——项目需求分析
  3. 每日一问:Android 中内存泄漏都有哪些注意点?
  4. 提取文件中的每一个mask,并将mask命名为文件名字
  5. c++primer(第五版) 阅读笔记_第1章
  6. Java一个对象占用多少字节
  7. spark 资源动态分配
  8. Python3.7 - Argparse模块的用法
  9. CUDA 到底什么玩意
  10. 「HAOI2015」树上操作(非树剖)