前言
中期匯報會后,對Tars Subset功能更加熟悉,並根據TarsGo的實現方式,對Java JDK實現代碼進行翻新改造。於是有了以下兩篇分析文章:
第5篇 基於TarsGo Subset路由規則的Java JDK實現方式(上篇)
https://www.cnblogs.com/dlhjw/p/15245113.html
第6篇 基於TarsGo Subset路由規則的Java JDK實現方式(下篇)
https://www.cnblogs.com/dlhjw/p/15245116.html
其中,《上篇》注重TarsGo分析,《下篇》注重TarsJava實現方式。不出意外的話,最終提交的考核成果就在下面的GitHub代碼倉庫中(以下簡稱“最終代碼”),后續可能會有些許地方需要更改:
TarsJava 實現Subset路由規則JDK GitHub開源地址
https://github.com/dlhjw/TarsJava/commit/cc2fe884ecbe8455a8e1f141e21341f4f3dd98a3
最終代碼與中期代碼在整體思想邏輯上都是一致的都是:先判斷Subset路由規則,再根據規則路由到定義的節點。不同點在於:中期在處理整個過程時,用一個方法filterEndpointsBySubset()
實現;而最終的實現方式則是以subsetEndpointFilter()
方法作為整個Subset流量路由的入口,通過subsetManager
管理器調用getSubset()
方法獲取到路由規則的String類型的subset
字段,與節點自身的subset
字段一一比較過濾節點;其中Subset路由規則的判斷封裝在getSubset()
方法里;
總的來說就是最終代碼是在處理subset規則邏輯中增加了很多細節,比如:通過新增的registry接口獲取subsetConf配置項;將獲取到是配置項存入緩存中;以及將“判斷Subset路由規則”進行層層封裝,最終返回一個簡單的String類型的subset
字段與節點自身的subset
字段比較等;
因此,在測試方案上相比較中期有些許區別,但總體上的單元測試原則是不變的:
- 首先構建前置條件;
- 調用測試方法;
- 輸出測試結果;
其中的區別主要體現在前置條件的構建上,本篇將結合最終代碼的實現邏輯,重點介紹其測試方案的設計;首先介紹測試方案的設計原則,接着針對五種情況(按比例單次、按比例多次、按參數精確、按參數正則路由與默認規則)做詳細介紹與展示測試結果。
最終代碼的Subset執行流程分析請參考下面這篇文章:
第8篇 TarsJava Subset最終代碼的執行流程與原理分析
https://www.cnblogs.com/dlhjw/p/15245124.html
《測試方案設計》與《執行流程分析》兩篇文章相輔相成,相互觀閱能更快更好地理解整個Subset的業務流程與輸出示例;
1. SubsetConf配置項的結構
在中期,筆者使用一個map來模擬subset的流量規則;而在最終代碼里,是用多個對象來模擬Subset的配置,這些對象是理解整個Subset流量過濾規則的基礎的,因此很有必要在這里做個介紹;
1.1 SubsetConf
public class SubsetConf {
private boolean enanle;
private String ruleType;
private RatioConfig ratioConf;
private KeyConfig keyConf;
private Instant lastUpdate;
……
}
可以看出SubsetConf配置項里有以下屬性:
- enanle:表示是否開啟Subset流量管理功能;
- true:開啟;false:關閉;
- ruleType:表示流量管理的類型;
- 目前有
ratio
按比例和key
按參數兩種模式;
- 目前有
- RatioConfig:表示按比例路由配置項;
- 里面定義了路由比例與路徑等信息,詳情請參考《1.2 RatioConfig》
- KeyConfig:表示按參數路由配置項;
- 里面定義了規則key與路由路徑等信息,詳情請參考《1.3 KeyConfig》
- lastUpdate:表示該配置項上次更新時間,將在緩存那里起作用;
1.2 RatioConfig
public class RatioConfig {
private Map<String, Integer> rules;
……
}
RatioConfig里只有一個map類型的rules
路由規則,其中key為一個String類型的subset字段,用來跟節點的subset字段匹配,value為路由權重,如:{ {"v1" , 20} , {"v2" , 60} , {"v3" , 20} }表示路由到subset字段為v1的節點的概率為0.2;路由到subset字段為v2的節點的概率為0.6;路由到subset字段為v3的節點的概率為0.2;
1.3 KeyConfig
public class KeyConfig {
private String defaultRoute;
private List<KeyRoute> rules;
……
}
KeyConfig里有兩個屬性,一個是defaultRoute
默認路由路徑;另一個是list類型的rules
,里面是KeyRoute
,其定義了按參數匹配的類型、規則key與路徑,詳情請見《1.4 KeyRoute》
1.4 KeyRoute
public class KeyRoute {
private String action = null;
private String value = null;
private String route = null;
public static final String TARS_ROUTE_KEY = "TARS_ROUTE_KEY";
……
}
KeyRoute里面有四個String類型的屬性,如下:
- action:用來定義參數匹配的類型;
- 目前可設置的類型有:equals精確匹配、match正則匹配、default默認匹配;
- value:這就是大名鼎鼎的規則key了。當action=equals時,還需滿足規則key與請求key匹配,才能進行精確匹配;當action=match時,還需滿足規則key與請求key正則匹配,才能進行正則匹配;action=default對規則key沒要求;
- route:用來規定路由路徑,其值為一個String類型的subset字段,匹配到節點的subset字段;
- TARS_ROUTE_KEY:一個常量字段,為Tars請求體里的status(map類型)的key;
1.5 SubsetConf的結構示意圖
上述提到的配置類聯系結構圖如下:
2. 測試方案設計
這里的測試主要指測試subsetEndpointFilter()根據subset過濾節點這一核心方法,在測試中構建前置條件最為復雜,因此將在2.1仔細介紹;
2.1 構建前置條件
從SubsetConf的結構圖可以看出,按比例與參數路由的一些前置條件不同,比如按參數路由需要一個list類型的KeyRoute,而按比例路由則是用一個map類型的數據結構實現類似KeyRoute的功能;
除此之外,KeyRoute里的value為規則的key,其作用是與請求key做對比匹配,是參數匹配的必要不充分條件;這就要求構建前置條件時要考慮從Tars的請求體TarsServantRequest
中的status屬性(map類型)獲取到鍵TARS_ROUTE_KEY的值value,而Tars的請求體又要通過分布式上下文信息DistributedContext
獲取;默認路由又不用考慮染色key……
因此,按比例與默認路由方式的前置條件包括:
- 一個Subset過濾器;
- 核心方法
subsetEndpointFilter
的傳入參數;- objectName:對象名;
- routeKey:上下文的染色key;
- activeEp:存活的節點列表及存活的節點;
- 一個SubsetManager管理器;
- RatioConfig比例路由規則;
- subsetConf配置項;
- 等;
可以通過以下代碼實現、模擬:
//創建Subset過濾器
Subset subsetFilter = new Subset();
//模擬objectName
String objectName = "objectName";
//模擬routeKey
String routeKey = "routeKey";
//存活節點list列表
List<EndpointF> endpointFList = new ArrayList<EndpointF>();
Holder<List<EndpointF>> activeEp = new Holder<List<EndpointF>>(new ArrayList<EndpointF>());
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置比例路由規則
RatioConfig ratioConf = new RatioConfig();
Map<String , Integer> map = new HashMap<>();
map.put("v1",20);
map.put("v2",80);
//map.put("v3",20);
ratioConf.setRules(map);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("ratio");
subsetConf.setRatioConf(ratioConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
而按參數匹配路由方式的前置條件包括:
- 一個Subset過濾器;
- 核心方法
subsetEndpointFilter
的傳入參數;- objectName:對象名;
- routeKey:上下文的染色key;
- activeEp:存活的節點列表及存活的節點;
- 一個SubsetManager管理器;
- KeyConfig參數路由規則;
- KeyRoute參數路由屬性;
- subsetConf配置項;
- Tars的請求體TarsServantRequest;
- 一個Session域,用來構建Tars請求體
- 分布式上下文信息DistributedContext;
- 等;
可以通過以下代碼實現、模擬:
//創建Subset過濾器
Subset subsetFilter = new Subset();
//模擬objectName
String objectName = "objectName";
//模擬routeKey
String routeKey = "routeKey";
//存活節點list列表
List<EndpointF> endpointFList = new ArrayList<EndpointF>();
Holder<List<EndpointF>> activeEp = new Holder<List<EndpointF>>(new ArrayList<EndpointF>());
//定義一個Session域,用來構建Tars請求體
Session session;
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置參數路由規則,這里的KeyRoute的value為 “規則的染色key”
KeyConfig keyConf = new KeyConfig();
List<KeyRoute> krs = new LinkedList<>();
krs.add(new KeyRoute("match","routeKey","v1"));
keyConf.setRules(krs);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("key");
subsetConf.setKeyConf(keyConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
//1.4.1 創建Tars的請求體TarsServantRequest
TarsServantRequest request = new TarsServantRequest( session );
//1.4.2 往請求體的status添加{TARS_ROUTE_KEY, "routeKey"}鍵值對
Map<String, String> status = new HashMap<>();
status.put("TARS_ROUTE_KEY", "routeKey");
request.setStatus(status);
//1.4.3 構建分布式上下文信息,將請求放入分布式上下文信息中,因為getSubset()的邏輯是從分布式上下文信息中取
DistributedContext distributedContext = new DistributedContextImpl();
distributedContext.put(DyeingSwitch.REQ,request);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
2.2 調用測試方法
調用測試方法比較簡單,用如下語句實現即可:
//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
2.3 輸出測試結果
輸出測試結果也比較簡單,在過濾前后都遍歷一些節點列表,判斷其是否起到過濾功能即可,可以用如下代碼實現:
//3. 輸出過濾前信息
System.out.println("過濾前節點信息如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//5. 輸出過濾結果
System.out.println("過濾后節點信息如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
System.out.println(endpoint.toString());
}
如此,一個大概的測試方案就成型了,下面將介紹各路由方式的測試代碼與測試結果;
3. 按比例路由規則 - 單次測試
測試代碼如下:
/**
* 按比例路由規則 - 單次測試
* 沒有測試registry獲取subsetConf功能
*/
@Test
public void testRatioOnce() {
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置比例路由規則
RatioConfig ratioConf = new RatioConfig();
Map<String , Integer> map = new HashMap<>();
map.put("v1",20);
map.put("v2",80);
//map.put("v3",20);
ratioConf.setRules(map);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("ratio");
subsetConf.setRatioConf(ratioConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//3. 輸出過濾前信息
System.out.println("過濾前節點信息如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
//5. 輸出過濾結果
System.out.println("過濾后節點信息如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
System.out.println(endpoint.toString());
}
}
測試結果如下:
在上述情況下,如果我們將所有v2節點刪除,即模擬經過按比例權重查找后匹配到節點subset字段為v2集合,但原來存活節點里卻沒有subset字段為v2的節點這種情況,將會輸出一句錯誤信息,如下:
4. 按比例路由規則 - 多次測試
測試代碼如下:
/**
* 按比例路由規則 - 多次測試
* 沒有測試registry獲取subsetConf功能
*/
@Test
public void testRatioTimes() {
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置比例路由規則
RatioConfig ratioConf = new RatioConfig();
Map<String , Integer> map = new HashMap<>();
map.put("v1",20);
map.put("v2",80);
map.put("v3",20);
ratioConf.setRules(map);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("ratio");
subsetConf.setRatioConf(ratioConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//3. 循環times次
int times = 1000000;
int v1Times = 0;
int v2Times = 0;
int v3Times = 0;
int errTimes = 0;
for (int i = 0; i < times; i++) {
//對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
String subsetValue = filterActiveEp.getValue().get(0).getSubset();
if("v1".equals(subsetValue)){
v1Times++;
} else if("v2".equals(subsetValue)){
v2Times++;
} else if("v3".equals(subsetValue)){
v3Times++;
} else {
errTimes++;
}
}
//輸出結果
System.out.println("一共循環次數:" + times);
System.out.println("路由到v1次數:" + v1Times);
System.out.println("路由到v2次數:" + v2Times);
System.out.println("路由到v3次數:" + v3Times);
System.out.println("路由異常次數:" + errTimes);
}
測試結果如下:
這里如果我們將語句subsetConf.setEnanle(true);
中的true置為false,可以發現沒有起到路由功能,所有結點路由到v1那邊,如下圖所示:
如果我們給方法subsetEndpointFilter(objectName, routeKey, activeEp)
中的routeKey傳入參數為空字符串""
,則會等比例隨機路由,測試結果如下:
5. 按參數路由規則 - 精確匹配測試
測試代碼如下:
/**
* 測試參數匹配 - 精確匹配
* 沒有測試registry獲取subsetConf功能
* 注意要成功必須routeKey和match匹配上
*/
@Test
public void testMatch() {
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置參數路由規則,這里的KeyRoute的value為 “規則的染色key”
KeyConfig keyConf = new KeyConfig();
List<KeyRoute> krs = new LinkedList<>();
krs.add(new KeyRoute("match","routeKey","v1"));
keyConf.setRules(krs);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("key");
subsetConf.setKeyConf(keyConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
//1.4.1 創建Tars的請求體TarsServantRequest
TarsServantRequest request = new TarsServantRequest( session );
//1.4.2 往請求體的status添加{TARS_ROUTE_KEY, "routeKey"}鍵值對
Map<String, String> status = new HashMap<>();
status.put("TARS_ROUTE_KEY", "routeKey");
request.setStatus(status);
//1.4.3 構建分布式上下文信息,將請求放入分布式上下文信息中,因為getSubset()的邏輯是從分布式上下文信息中取
DistributedContext distributedContext = new DistributedContextImpl();
distributedContext.put(DyeingSwitch.REQ,request);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//3. 輸出過濾前信息
System.out.println("過濾前節點信息如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
//5. 輸出過濾結果
System.out.println("過濾后節點信息如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
System.out.println(endpoint.toString());
}
}
測試結果如下:
這里如果我們使規則key與請求key不匹配,將起不到過濾功能,並輸出一句錯誤日志,如下圖所示:
6. 按參數路由規則 - 正則匹配測試
測試代碼如下:
/**
* 測試參數匹配 - 正則匹配
* 沒有測試registry獲取subsetConf功能
* 注意要成功必須routeKey和match匹配上
*/
@Test
public void testEqual() {
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置參數路由規則,這里的KeyRoute的value為 “規則的染色key”
KeyConfig keyConf = new KeyConfig();
List<KeyRoute> krs = new LinkedList<>();
krs.add(new KeyRoute("equal","routeKey","v1"));
keyConf.setRules(krs);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("key");
subsetConf.setKeyConf(keyConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
//1.4.1 創建Tars的請求體TarsServantRequest
TarsServantRequest request = new TarsServantRequest( session );
//1.4.2 往請求體的status添加{TARS_ROUTE_KEY, "routeKey"}鍵值對
Map<String, String> status = new HashMap<>();
status.put("TARS_ROUTE_KEY", "route*");
request.setStatus(status);
//1.4.3 構建分布式上下文信息,將請求放入分布式上下文信息中,因為getSubset()的邏輯是從分布式上下文信息中取
DistributedContext distributedContext = new DistributedContextImpl();
distributedContext.put(DyeingSwitch.REQ,request);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//3. 輸出過濾前信息
System.out.println("過濾前節點信息如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
//5. 輸出過濾結果
System.out.println("過濾后節點信息如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
System.out.println(endpoint.toString());
}
}
測試結果如下:
這里如果我們使規則key與請求key正則匹配不上,跟精確匹配一樣將起不到過濾功能,並輸出一句錯誤日志,如下圖所示:
7. 無路由規則測試
測試代碼如下:
/**
* 測試默認路由
* 沒有測試registry獲取subsetConf功能
*/
@Test
public void testDefault() {
//1. 給過濾器設置過濾規則
//1.1 創建SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();
//1.1 設置參數路由規則,這里的KeyRoute的value為 “規則的染色key”
KeyConfig keyConf = new KeyConfig();
List<KeyRoute> krs = new LinkedList<>();
krs.add(new KeyRoute("default","","v1"));
keyConf.setRules(krs);
//1.2 設置subsetConf,並加入緩存
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("key");
subsetConf.setKeyConf(keyConf);
subsetConf.setLastUpdate( Instant.now() );
Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);
//1.3 給過濾器設置過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);
//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//3. 輸出過濾前信息
System.out.println("過濾前節點信息如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
//5. 輸出過濾結果
System.out.println("過濾后節點信息如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
System.out.println(endpoint.toString());
}
}
測試結果如下:
最后
