如果你正在使用Spring Cloud体系,在实际使用过程中正遇到以下问题,可以阅读本文章的内容作为后续你解决这些问题的参考,文章内容不保证无错,请务必仔细思考之后再进行实践。

问题:

1,本地连上开发或测试环境的集群连调,正常测试请求可能会请求到本地,被自己的debug阻塞。

2,测试环境维护时,多项目并发提测,维护多个相同的集群进行测试是否必要,是否有更好的方案。

一般,我们在使用Spring Cloud全家桶的时候,会选择zuul作为网关,Ribbon作为负载均衡器,Feign作为远程服务调用模版。使用过Spring Cloud的同学对这些组件的作用必然非常熟悉。这里就拿这些组件组合成的微服务集群来实现标签路由的功能。

实现的效果如图所示,在头上带上标签的请求会在经过网关和各个应用时进行标签判断流量应该打到哪一个去,而每一个应用自己本身的标签是通过eureka上的matedate实现的。

如下图可以构想动态修改标签控制应用所能承接的请求,这里暂时不描述mq部分的功能:

答案:

实现一个ZoneAvoidanceRule的继承类,重写getPredicate方法:

@Override
public AbstractServerPredicate getPredicate() {
OfflineEnvMetadataAwarePredicate offlineEnvMetadataAwarePredicate = new OfflineEnvMetadataAwarePredicate();
offlineEnvMetadataAwarePredicate.setEnv(env);
return offlineEnvMetadataAwarePredicate;
}

Predicate的实现屏蔽了开发测试环境中非这个环境网段启动的应用,并且比对请求的标签和本地的标签,来控制路由给哪一个服务器。


/**
* 线下环境路由策略具体逻辑
*/
public class OfflineEnvMetadataAwarePredicate extends AbstractServerPredicate { private String env; public void setEnv(String env) {
this.env = env;
} @Override
public boolean apply(PredicateKey predicateKey) {
if(predicateKey == null || !(predicateKey.getServer() instanceof DiscoveryEnabledServer)){
return true;
}
DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer();
String serverZone = server.getInstanceInfo().getMetadata().get("zone");
String requestZone = RequestZoneLabelContext.getRequestZone();
// dev || sit 环境 本地不允许直接连调
if(env.equals("sit") || env.equals("dev")){
if(StringUtils.isBlank(requestZone) && !server.getHost().startsWith("10.0")){
return false;
}
} if(StringUtils.isNotBlank(serverZone)) {
return serverZone.equals(requestZone);
}else if(StringUtils.isNotBlank(requestZone)){
return requestZone.equals(serverZone);
} return true; }
}

那么我们注意到请求头上的标签要在初始时就拿到,所以需要一个ServletRequestListener,将拿到的zone放入RequestZoneLabelContext。我们知道在一个请求中如果是一个io线程执行到底,我们只需要利用threadlocal来存储线程变量,可是如果一个请求中会产生不定的子线程完成,数据在线程间的传递就成为问题,这里使用了InheritableThreadLocal来决解,在RequestZoneLabelContext中可以看到。

public class RequestZoneLabelContextListener implements ServletRequestListener {

    private static final String ZONE_LABEL_NAME = "zone";

    @Override
public void requestDestroyed(ServletRequestEvent sre) {
RequestZoneLabelContext.remove();
} @Override
public void requestInitialized(ServletRequestEvent requestEvent) {
HttpServletRequest request = (HttpServletRequest)requestEvent.getServletRequest();
String lbZone = request.getHeader(ZONE_LABEL_NAME);
if(StringUtils.isNotBlank(lbZone)){
RequestZoneLabelContext.setZone(lbZone);
}
}
}
/**
* 从request header上传递label到feign请求
*/
public class RequestZoneLabelContext { private static InheritableThreadLocal<String> zoneLabelThreadLocal = new InheritableThreadLocal<>(); public static void setZone(String zone){
zoneLabelThreadLocal.set(zone);
} public static String getRequestZone(){
return zoneLabelThreadLocal.get();
} public static void remove(){
zoneLabelThreadLocal.remove();
}
}

那么在应用之间调用的feign中我们是需要继续把这个zone通过header传递下去的,所以又扩展了RequestInterceptor:

public class FeignZoneHeaderInterceptor implements RequestInterceptor {

    @Override
public void apply(RequestTemplate template) {
String requestZone = RequestZoneLabelContext.getRequestZone();
if(StringUtils.isNotBlank(requestZone)){
template.header("zone", requestZone);
}
}
}

至此就基本实现了最初的想法。

这个实现方式仅供参考,如有跟好的方式,多多指教哈~

最新文章

  1. android px dp sp
  2. String 和 document 的相互转换总结
  3. Delphi中如何控制其他程序窗体上的窗口控件
  4. PV是什么意思
  5. Environment variable ORACLE_UNQNAME not defined. Please set ORACLE_UNQNAME to database unique name. 的解决方法
  6. Tomcat 配置 Probe 监控
  7. NSArray使用小结
  8. ajax+struts2 实现省份-城市-地区三级联动
  9. 一些有用的Java参考资料
  10. Java判断水仙花数
  11. Qt编写自定义控件属性设计器
  12. update-alternatives关键解疑
  13. 进程退出exit、_exit、abort
  14. 新手C#s.Split(),s.Substring(,)以及读取txt文件中的字符串的学习2018.08.05
  15. C#解析PDF
  16. 安装了Anaconda之后,Maya运行报错,Python 找不到 Maya 的 Python 模块
  17. 认证服务号Thinkphp微信支付
  18. python UI自动化实战记录二:请求接口数据并提取数据
  19. R语言学习笔记(二): 类与泛型函数
  20. 提取pfx证书公钥和私钥

热门文章

  1. TCP/UDP套接字 java socket编程实例
  2. iOS Programming Web Services and UIWebView
  3. R in action读书笔记(17)第十二章 重抽样与自助法
  4. 解决VS2010提示warning C4068: 未知的杂注
  5. 观锁和乐观锁——《POJOs in Action》
  6. Ubuntu14.04环境下java web运行环境搭建
  7. cesium 原理 之 command拼接
  8. CPU怎么计算1+1----CPU计算的电路基础
  9. web.xml的简单解释以及Hello1中web.xml的简单分析
  10. VC++检测硬件设备状态