本文源碼: GitHub·點這裡 || GitEE·點這裡
一、基本邏輯
請求通過8001服務,在灰階規則中,會讀取下次請求的服務清單,根據版本号參數規則,選中路由的服務。

配置版本号,區分灰階版本和預設正常版本;
自定義攔截器,管理版本号或其他辨別參數在請求中傳遞;
自定義服務選中政策,基于版本辨別路由服務;
如果灰階服務不存在,則基于規則選中預設服務;
二、版本配置
在node12-server叢集配置兩個服務:在8002端口配置版本v7.0.0,在8003端口配置版本v7.0.1,用來測試灰階版本選擇。
8002服務
eureka:
metadata-map:
version: v7.0.0
8003服務
eureka:
metadata-map:
version: v7.0.1
Eureka注冊中心,服務清單:
三、參數傳遞
微服務下通過實作RequestInterceptor接口,管理服務之間的Feign請求攔截器,在請求路由到服務前,可以對請求執行一些處理操作,常見操作例如傳遞版本号,使用者Token等請求頭等屬性。
/**
* 請求攔截器
*/
@Component
public class GrayReqInterceptor implements RequestInterceptor {
private static final String VERSION_KEY = "versionId" ;
/**
* 處理請求頭參數攜帶問題
*/
@Override
public void apply(RequestTemplate requestTemplate) {
HttpServletRequest request =
((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
String versionId = request.getHeader(VERSION_KEY);
if (StringUtils.isNotEmpty(versionId)){
requestTemplate.header(VERSION_KEY,versionId);
}
}
}
這裡就傳遞一個versionId參數,作為下次請求路由服務的核心辨別。
四、灰階規則
在請求頭的Header中添加要通路的版本号,如果有比對的服務,則路由所有請求的灰階服務,如果沒有則傳回預設服務。
@Configuration
public class GrayRule extends ZoneAvoidanceRule {
@Bean
public GrayReqInterceptor grayReqInterceptor(){
return new GrayReqInterceptor();
}
private static final String VERSION_KEY = "versionId" ;
@Override
public Server choose(Object key) {
HttpServletRequest request =
((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
String versionId = request.getHeader(VERSION_KEY);
// 服務比對
List<Server> serverList = this.getPredicate().getEligibleServers(this.getLoadBalancer().getAllServers(), key);
Server toServer = getServer(serverList,versionId);
if (toServer != null){
return toServer ;
} else {
return getServer(serverList,GrayConstant.VERSION_DEF);
}
}
private Server getServer (List<Server> serverList,String version){
Server toServer = null ;
for (Server server : serverList) {
Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
String metaVersion = metadata.get("version");
if (!StringUtils.isEmpty(metaVersion)) {
if (metaVersion.equals(version)) {
toServer = server;
}
}
}
return toServer ;
}
}
在實際的過程中,服務的選擇是十分複雜的,如果沒有灰階服務,需要根據實際情況制定服務比對的規則,例如根據響應時間,或者預設輪詢等。
更需要注意的一點是,一旦使用底層API的二次封裝,項目的整體就會受到架構版本更新的影響,需要持續關注架構的環境。
五、測試流程
1.啟動相關服務,觀察注冊中心服務清單;
2.請求8001服務的接口,并帶上版本号;
3.觀察不同版本号的路由服務;
4.不攜帶版本号,觀察預設服務選擇;
六、源代碼位址
GitHub位址:知了一笑
https://github.com/cicadasmile/spring-cloud-base
GitEE位址:知了一笑
https://gitee.com/cicadasmile/spring-cloud-base