赞
踩
灰度发布是指在系统迭代的时候一种平滑过度上线发布方式。灰度发布是在原有的系统的基础上面,额外增加一个新版本,这个新版本包含新上线的需要验证的功能,通过负载均衡引入部分流量到新版本的应用上,如果在这个过程中没有出现问题,便可以平滑地把线上的应用一步步替换成新的版本,这样就完成了一次灰度发布。通过灰度发布的方式可以在用户无感的情况下完成系统发版升级。
这里使用一个开源的实现:ribbon-discovery-filter-spring-cloud-starter
在Eureka中有两种metadata:
eureka.instance.metadata-map.<key>=<value>
来配置,内部就是一个map来保存的。可以配置在远程的服务,也可以随着服务的注册保存到Eureka注册表中。基于Eureka的元数据实现完成灰度发布的原理是:通过获取Eureka的元数据信息,根据元数据信息的识别,最后在路由规则进行负载均衡。
依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- springboot web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <!--不用Tomcat,使用undertow --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
配置文件:这里通过配置文件配置三份配置,-1随机端口,node1和node2是v1版本,node3是v2版本。
server: port: 8877 spring: profiles: node1 application: name: usercenter eureka: client: serviceUrl: defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/ instance: prefer-ip-address: true metadata-map: version: release --- server: port: 8899 spring: profiles: node2 application: name: usercenter eureka: client: serviceUrl: defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/ instance: prefer-ip-address: true metadata-map: version: release --- server: port: 8866 spring: profiles: node3 application: name: usercenter eureka: client: serviceUrl: defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/ instance: prefer-ip-address: true metadata-map: version: gray
Controller:
@RestController
@RequestMapping("user")
public class UsercenterController {
@Value("${spring.profiles}")
private String profile;
@Value("${server.port}")
private Integer port;
@GetMapping("list")
public String list() {
return "active " + profile + " port " + port;
}
}
启动类:
@SpringBootApplication
@EnableDiscoveryClient
public class UsercenterApplication {
public static void main(String[] args) {
SpringApplication.run(UsercenterApplication.class, args);
}
}
配置文件:
server: port: 88 spring: application: name: zuul-server eureka: client: serviceUrl: defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/ instance: prefer-ip-address: true logging: level: org.springframework.cloud.netflix: debug zuul: routes: service-a: path: /usercenter/** serviceId: usercenter
依赖:
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
编写灰度发布过滤器:当携带请求gray_switch
并且值为open
时就会去请求灰度版本的应用。否则就是请求release
版本的应用。
现实中我们可以通过使用Nginx,然后将部分流量添加请求头,这样就可以切一部分的流量去做灰度了。
@Component public class GrayFilter extends ZuulFilter { @Override public String filterType() { return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); return !ctx.containsKey(FORWARD_TO_KEY) && !ctx.containsKey(SERVICE_ID_KEY); } @Override public Object run() throws ZuulException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); String mark = request.getHeader("gray_switch"); if (StringUtils.isNotBlank(mark) && "open".equals(mark)) { RibbonFilterContextHolder.getCurrentContext().add("version", "gray"); } else { RibbonFilterContextHolder.getCurrentContext().add("version", "release"); } return null; } }
分别启动Eureka、Zuul和UsercenterApplication。
在启动UsercenterApplication的使用指定active profile
:
例如通过IDEA启动时修改配置Active profiles
启动给三个分别设置 node1、node2、node3。
在UsercenterApplication所在的pomx文件下,mvn运行
mvn spring-boot:run -Dspring-boot.run.profiles=node1
mvn spring-boot:run -Dspring-boot.run.profiles=node2
mvn spring-boot:run -Dspring-boot.run.profiles=node3
访问接口时
http://localhost:88/usercenter/user/list
可以关注我的微信公众号,有更多的技术干货文章
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。