您好,登錄后才能下訂單哦!
使用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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。