Spring Cloud體系實現(xiàn)標(biāo)簽路由的方法示例
如果你正在使用Spring Cloud體系,在實際使用過程中正遇到以下問題,可以閱讀本文章的內(nèi)容作為后續(xù)你解決這些問題的參考,文章內(nèi)容不保證無錯,請務(wù)必仔細(xì)思考之后再進(jìn)行實踐。
問題:
1,本地連上開發(fā)或測試環(huán)境的集群連調(diào),正常測試請求可能會請求到本地,被自己的debug阻塞。
2,測試環(huán)境維護(hù)時,多項目并發(fā)提測,維護(hù)多個相同的集群進(jìn)行測試是否必要,是否有更好的方案。
一般,我們在使用Spring Cloud全家桶的時候,會選擇zuul作為網(wǎng)關(guān),Ribbon作為負(fù)載均衡器,F(xiàn)eign作為遠(yuǎn)程服務(wù)調(diào)用模版。使用過Spring Cloud的同學(xué)對這些組件的作用必然非常熟悉。這里就拿這些組件組合成的微服務(wù)集群來實現(xiàn)標(biāo)簽路由的功能。
實現(xiàn)的效果如圖所示,在頭上帶上標(biāo)簽的請求會在經(jīng)過網(wǎng)關(guān)和各個應(yīng)用時進(jìn)行標(biāo)簽判斷流量應(yīng)該打到哪一個去,而每一個應(yīng)用自己本身的標(biāo)簽是通過eureka上的matedate實現(xiàn)的。

如下圖可以構(gòu)想動態(tài)修改標(biāo)簽控制應(yīng)用所能承接的請求,這里暫時不描述mq部分的功能:
答案:
實現(xiàn)一個ZoneAvoidanceRule的繼承類,重寫getPredicate方法:
@Override
public AbstractServerPredicate getPredicate() {
OfflineEnvMetadataAwarePredicate offlineEnvMetadataAwarePredicate = new OfflineEnvMetadataAwarePredicate();
offlineEnvMetadataAwarePredicate.setEnv(env);
return offlineEnvMetadataAwarePredicate;
}
Predicate的實現(xiàn)屏蔽了開發(fā)測試環(huán)境中非這個環(huán)境網(wǎng)段啟動的應(yīng)用,并且比對請求的標(biāo)簽和本地的標(biāo)簽,來控制路由給哪一個服務(wù)器。
@Override
public AbstractServerPredicate getPredicate() {
OfflineEnvMetadataAwarePredicate offlineEnvMetadataAwarePredicate = new OfflineEnvMetadataAwarePredicate();
offlineEnvMetadataAwarePredicate.setEnv(env);
return offlineEnvMetadataAwarePredicate;
}
那么我們注意到請求頭上的標(biāo)簽要在初始時就拿到,所以需要一個ServletRequestListener,將拿到的zone放入RequestZoneLabelContext。我們知道在一個請求中如果是一個io線程執(zhí)行到底,我們只需要利用threadlocal來存儲線程變量,可是如果一個請求中會產(chǎn)生不定的子線程完成,數(shù)據(jù)在線程間的傳遞就成為問題,這里使用了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();
}
}
那么在應(yīng)用之間調(diào)用的feign中我們是需要繼續(xù)把這個zone通過header傳遞下去的,所以又?jǐn)U展了RequestInterceptor:
public class FeignZoneHeaderInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String requestZone = RequestZoneLabelContext.getRequestZone();
if(StringUtils.isNotBlank(requestZone)){
template.header("zone", requestZone);
}
}
}
至此就基本實現(xiàn)了最初的想法。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springmvc conver實現(xiàn)原理及用法解析
這篇文章主要介紹了Springmvc conver實現(xiàn)原理及用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
詳解在IDEA中使用MyBatis Generator逆向工程生成代碼
這篇文章主要介紹了詳解在IDEA中使用MyBatis Generator逆向工程生成代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06

