您好,登录后才能下订单哦!
使用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的实现屏蔽了开发测试环境中非这个环境网段启动的应用,并且比对请求的标签和本地的标签,来控制路由给哪一个服务器。
@Override public AbstractServerPredicate getPredicate() { OfflineEnvMetadataAwarePredicate offlineEnvMetadataAwarePredicate = new OfflineEnvMetadataAwarePredicate(); offlineEnvMetadataAwarePredicate.setEnv(env); return offlineEnvMetadataAwarePredicate; }
那么我们注意到请求头上的标签要在初始时就拿到,所以需要一个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); } } }
看完上述内容,你们掌握使用Spring Cloud体系怎么实现标签路由的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。