聊聊微服务中的多环境隔离
一、背景
a. 公司有容器环境,则独立部署一整套容器环境即可 b. 或者把代码提交到公共的开发环境,直接在上面验证 c. 开发者本地启动所依赖的全套服务,完成功能的验证
二、方案概述
前端提供一个设置统一请求头的方法,设置后往后的发的请求都会带上该请求头;通过设置请求头,对流量染色 网关识别这个染色的流量,先去找同色的服务进行路由,如果没提供则用基准环境的提供的服务 微服务内部调用时,如果是染色流量,则先找同色的服务提供者,如果没有,则用基准环境的服务提供者
假设小王开发的业务A1涉及到Service A和Service C中代码的修改,因此小王本地启动了Service A和Service C 小王在浏览器或app中设置流量染色头为A1,这样流量就能顺利的流入小王 本地的ServiceA _A1和ServiceC_A1;参考上图中染色环境A1的流量流转 小王能够顺利的完成常规的业务操作,说明全链路下其开发的功能都已正常通过测试
小吴是前端开发人员,开发业务A1相关的前端页面,现在他需要找小王进行联合调试 因为小王上面已经启动了本地的ServiceA_A1和ServiceC_A1,因此小吴只需要在开发工具中,设置流量染色头为A1 这样小吴的前端请求,就可以精准的流入到小王的本地环境;小王未提供的服务接口,由基准环境提供
基准环境的流量是不会流入开发者本地的,因此不用担心开发者本地的服务影响基准环境
三、方案实现介绍
服务可以按照流量的染色信息路由到相应的染色服务中 如果未找到相应的染色服务,则由基准环境提供 DB、Redis、MQ等中间件,和基准环境共用一套
web端、app端支持设置请求头,对流量进行染色 - SpringCloudGateway支持对染色流量自定义转发策略,将其转发到染色的服务
- 自定义ribbon负载均衡策略,识别到染色请求时优先调用染色的服务
- 染色头的透传,保证染色头在各个服务之间传递不丢失
- 开发者本地启动的服务注册到自定义的nacos分组中,防止影响基准环境,分组名必须和染色头对应上,如上面的染色头为A1,则注册的分组名也必须为A1
f nacos跨组调用的实现
3.1 流量染色的实现
3.2 网关层的改动
/**
* 根据serviceId 筛选可用服务
* @param serviceId 服务ID
* @param request 当前请求
* @return
*/
@Override
public ServiceInstance choose(String serviceId, ServerHttpRequest request) {
try {
String propertiesGroup = this.nacosDiscoveryProperties.getGroup();
NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());
List<Instance> instances;
String grayGroup = request != null ? request.getHeaders().getFirst(GrayConstant.GRAY_HEADER)
: null;
if (StringUtils.isNotBlank(grayGroup)) {
instances = namingService.selectInstances(serviceId, grayGroup, true);
if (CollectionUtils.isEmpty(instances)) {
log.debug("no instance in service {} by group {}", serviceId, grayGroup);
String defaultGroup = propertiesGroup.equals(grayGroup) ? getNacosDefaultGroup() : propertiesGroup;
instances = namingService.selectInstances(serviceId, defaultGroup, true);
}
} else {
instances = namingService.selectInstances(serviceId, propertiesGroup, true);
}
if (CollectionUtils.isEmpty(instances)) {
log.error("no instance in service {}", serviceId);
return null;
}
Instance instance = ExtendBalancer.getHostByRandomWeight2(instances);
return hostToServiceInstance(instance, serviceId);
}
catch (Exception e) {
log.warn("NacosRule error", e);
return null;
}
}
3.3 Feign调用的改动
3.4 流量染色头的透传方案介绍
3.5 nacos跨组调用的实现
String grayGroup = GrayGroupContextHolder.getGrayGroup();
if (StringUtils.isNotBlank(grayGroup)) {
// 跨分组查询实例
instances = namingService.selectInstances(serviceName, grayGroup, true);
if (CollectionUtils.isEmpty(instances)) {
log.debug("no instance in service {} by group {}", serviceName, grayGroup);
String defaultGroup = propertiesGroup.equals(grayGroup) ? getNacosDefaultGroup() : propertiesGroup;
instances = namingService.selectInstances(serviceName, defaultGroup, true);
}
} else {
instances = namingService.selectInstances(serviceName, propertiesGroup, true);
}
3.6 最终效果示意图
四、总结
通过流量染色的方式,对流量进行识别并让其流入开发者本地服务,完成开发者本地服务的调试,提高开发效率 通过ThreadLocal + copy请求头的方式,保证染色头的透传 通过自定义负载均衡策略 + nacos跨组调用实现染色请求调用到染色分组的服务且不影响基准环境
五、未来展望
全链路染色和隔离,包含Redis/MQ等 这个染色的方案,可用于实现灰度的功能,只要将流量染色的操作放在网关识别用户信息后就能实现部分用户访问灰度环境服务的功能
作者:zeng1994
出处:http://www.cnblogs.com/zeng1994/
本文版权归作者和博客园共有,欢迎转载!但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接!