这是我参与11月更文挑战的第16天,活动详情查看:11月更文挑战
在微服务中, 通常为了高可用, 同一个服务往往采用集群方式部署, 即同时存在几个相同的服务,而灰度的核心就 是路由, 通过我们特定的策略去调用目标服务线路
1 灰度路由的简介
灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度.
关于SpringCloud微服务+nacos的灰度发布实现, 首先微服务中之间的调用通常使用Feign方式和Resttemplate方式(较少使用),因此 , 我们需要指定服务之间的调用, 首先要给各个服务添加唯一标识, 我们可是使用一些特殊的标记, 如版本号version等, 其次,要干预微服务中Ribbon的默认轮询调用机制, 我们需要根据微服务的版本等不同, 来进行调用, 最后, 在服务之间, 需要传递调用链路的信息, 我们可以在请求头中,添加调用链路的信息.
整理思路为:
1 在请求头中添加调用链路信息
2 微服务之间调用时,使用feign拦截器,增强请求头
3 微服务调用选择时,根据指定的策略(如唯一标识版本等)从nacos中获取指定的服务,调用
2 灰度路由的使用
案列
基础服务
一个父服务,一个工具服务
父服务
pom依赖
1 | xml复制代码 <parent> |
工具服务
feign拦截器
1 | java复制代码@Slf4j |
灰度路由属性类
1 | java复制代码@ConfigurationProperties(prefix = "spring.cloud.nacos.discovery.metadata.gray-route", ignoreUnknownFields = false) |
路由属性类
1 | java复制代码@Data |
灰度路由规则类(继承ZoneAvoidanceRule类)
微服务在拦截处理后, Ribbon组件会从服务实例列表中获取一个实现进行转发, 且Ribbon默认的规则是ZoneAvoidanceRule类, 我们定义自己的规则, 只需要继承该类,重写choose方法即可.
1 | java复制代码@Slf4j |
业务服务
一个client服务;两个consumer服务,分版本v1和v2;两个provider服务,分版本v1和v2
client服务
Controller控制器
1 | java复制代码@RestController |
Feign接口
1 | java复制代码@FeignClient(value = "consumer-a") |
Application启动器
1 | java复制代码@SpringBootApplication |
application.yml
1 | yml复制代码server: |
pom依赖
1 | xml复制代码 <!--自定义commons工具包--> |
consumer1服务
Controller控制器
1 | java复制代码@RestController |
Feign接口
1 | java复制代码@FeignClient(value = "provider-a") |
Application启动类
1 | java复制代码@EnableDiscoveryClient |
application.yml
1 | java复制代码server: |
pom依赖
1 | xml复制代码 <dependencies> |
consumer2服务
consumer2服务和consumer1服务一样,只是灰度路由版本不一样(同一个服务器时,其端口也不一致)
application.yml
1 | yml复制代码server: |
provider1服务
Controller控制器
1 | java复制代码@RestController |
Application启动类
1 | java复制代码@EnableDiscoveryClient |
application.yml
1 | yml复制代码server: |
provider2服务
provider2服务和provider1服务相比, 就是灰度路由版本不一致(同一个服务器时,其端口也不一致)
application.yml
1 | yml复制代码server: |
验证测试
1 启动本地nacos服务
2 启动五个项目服务
此时,在nacos中,存在服务列表中存在三个, 分别是client-test服务(1个),provider-a服务(2个实例),consumer-a服务(2个实例)
3 使用postman进行测试
1 不指定请求头灰度路由
1 | txt复制代码"我是客户端,8000 \"我是consumerA,8081 \\\"我是 providerA,9091 \\\"\"" |
调用四次, 采用的是Ribbon中默认的轮询策略.
2 指定请求头灰度路由
请求头中设置gray-route = {"all":"v1"}
1 | txt复制代码"我是客户端,8000 \"我是consumerA,8081 \\\"我是 providerA,9091 \\\"\"" |
四次测试结果, 每个服务都是v1版本, 灰度路由生效.
请求头中设置{custom":{"consumer-a":"v1","provider-a":"v1"}}
1 | txt复制代码"我是客户端,8000 \"我是consumerA,8081 \\\"我是 providerA,9091 \\\"\"" |
四次测试结果, 每个服务都是v1版本, 灰度路由生效.
请求头中设置{custom":{"consumer-a":"v1","provider-a":"v2"}}
1 | txt复制代码"我是客户端,8000 \"我是consumerA,8081 \\\"我是 providerB,9092 \\\"\"" |
四次测试结果, consumer服务都是v1版本, provider服务都是版本2,灰度路由生效.
请求头中设置{custom":{"consumer-a":"v1"}}
1 | txt复制代码"我是客户端,8000 \"我是consumerA,8081 \\\"我是 providerA,9091 \\\"\"" |
四次测试结果, consumer服务都是v1版本, provider服务没有指定,所以采用默认轮询机制,灰度路由生效.
参考资料:
本文转载自: 掘金