前言
本篇為Tars專案上半程程式設計實踐的測試結果,經過上半程的原始碼學習、程式設計探索,現已初步實現Subset流量路由的三個核心功能:按比例路由、按引數路由與無規則路由。下面將介紹任務需求、測試模擬方案以及具體的測試結果。
1. 任務介紹
下圖為Subset流量管理任務需求 - 各語言SDK實現部分:
本人的任務是:使用Java語言實現Subset路由規則,核心點在新增三種模式的路由規則:
- 按比例路由;
- 按引數路由,分為精確路由與正則路由;
- 無規則路由;
具體流程是:
- 獲取路由規則引數;
- 獲取當前存活的服務節點;
- 對節點進行Subset規則過濾【核心】;
- 將過濾後的節點資訊存入status傳入下游;
現在,在中期彙報前已完成初步編碼,實現上述三種路由方式,下面將介紹筆者設計的測試方案,展示完成度。
2. 測試模擬方案
測試採用Java SpringBoot的單元測試功能;
測試思路是先模擬建立前置條件(新增路由規則與存活節點資訊),接著呼叫filterEndpointsBySubset()方法進行測試,最後做些格式化處理。在這過程中輸出過濾前後的節點資訊。因此測試方案分為以下六步:
- 新增路由規則;
- 新增過濾前節點資訊;
- 【輸出】輸出過濾前節點;
- 【核心】對存活節點按subset規則過濾;
- 對過濾後節點進行格式化處理;
- 【輸出】輸出過濾結果。
2.0 *前置工作
根據Java SpringBoot的單元測試規則,需要先構建一些測試用到的元件:
//通訊器配置項
CommunicatorConfig communicatorConfig = new CommunicatorConfig();
//查詢助手
QueryHelper queryHelper = new QueryHelper(new Communicator(communicatorConfig));
//服務代理配置項
ServantProxyConfig servantProxyConfig = new ServantProxyConfig("objectName");
//節點列表
List<EndpointF> endpointFList = new ArrayList<EndpointF>();
//存活的節點
Holder<List<EndpointF>> activeEp = new Holder<List<EndpointF>>(new ArrayList<EndpointF>());
2.1 新增路由規則
首先,根據任務需求文件說明書,可以知道新增路由規則的入參是類似下面JSON資料:
因此,筆者將上面資訊存入servantProxyConfig
服務代理配置項裡,rule_data用一個map格式的資料來裝配。下面程式碼用來模擬上游解析後的JSON資料,給通訊器新增路由規則:
//新增按比例路由規則
servantProxyConfig.setRuleType("proportion");
servantProxyConfig.setObjectName("objectName");
Map<String,String> map = new HashMap<>();
map.put("v1","20");
map.put("v2","80");
//map.put("v3",80);
servantProxyConfig.setRuleData(map);
2.2 新增存活節點
在TarsJava裡,節點儲存在list集合裡,直接add即可:
//新增存活節點
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.3 【輸出】遍歷輸出當前存活節點
//輸出過濾前節點資訊
System.out.println("過濾前節點資訊如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
2.4 【核心】對存活節點按subset規則過濾
這是核心點,核心方法為filterEndpointsBySubset()
按Subset規則過濾節點,這是筆者寫的和測試的方法,它能夠根據上述三種規則過濾節點:
//對存活節點按subset規則過濾
StringBuilder value = queryHelper.filterEndpointsBySubset(activeEp, servantProxyConfig);
2.5 後續格式化處理
這步將對過濾後的節點進行格式化處理:
//後續格式化相關工作
if (value.length() < 1) {
System.out.println("value.length() < 1");
return;
}
value.insert(0, Constants.TARS_AT);
value.insert(0, servantProxyConfig.getSimpleObjectName());
2.6 【輸出】輸出過濾結果
這步輸出過濾後的節點資訊:
//輸出過濾結果
System.out.println("過濾後節點資訊如下:");
System.out.println("result = " + value.toString());
筆者的測試方案設計就這樣分為六步,以下具體測試例項都是按照這六步進行。
3. 按比例路由規則 - 單次測試
具體測試方案為:節點有20%概率路由到Subset欄位為v1的節點,有80概率路由到Subset欄位為v2的節點【詳情檢視新增路由規則】。
測試程式碼如下:
/**
* 按比例路由規則 - 單次測試
*/
@Test
public void testProportionOnce() {
//新增按比例路由規則
servantProxyConfig.setRuleType("proportion");
servantProxyConfig.setObjectName("objectName");
Map<String,String> map = new HashMap<>();
map.put("v1","20");
map.put("v2","80");
servantProxyConfig.setRuleData(map);
//新增存活節點
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"));
activeEp.setValue(endpointFList);
//輸出過濾前節點資訊
System.out.println("過濾前節點資訊如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//對存活節點按subset規則過濾
StringBuilder value = queryHelper.filterEndpointsBySubset(activeEp, servantProxyConfig);
//後續格式化相關工作
if (value.length() < 1) {
System.out.println("value.length() < 1");
return;
}
value.insert(0, Constants.TARS_AT);
value.insert(0, servantProxyConfig.getSimpleObjectName());
//輸出過濾結果
System.out.println("過濾後節點資訊如下:");
System.out.println("result = " + value.toString());
}
測試結果如下:
結果分析:
可以看出成功路由到v2節點,但還是無法體驗到概率問題,於是有了下面按比例路由規則 - 多次測試。
4. 按比例路由規則 - 多次測試
具體測試方案為:迴圈10000000次,統計路由結果,判斷是否按比例路由。這裡設定的比例是v1:v2:v3 = 20:80:20。
測試程式碼如下:
/**
* 按比例路由規則 - 多次測試
*/
@Test
public void testProportionTimes() {
//新增按比例路由規則
servantProxyConfig.setRuleType("proportion");
servantProxyConfig.setObjectName("objectName");
Map<String,String> map = new HashMap<>();
map.put("v1","20");
map.put("v2","80");
map.put("v3","20");
servantProxyConfig.setRuleData(map);
//新增存活節點
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,"v2"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);
//迴圈times次
int times = 10000000;
int v1Times = 0;
int v2Times = 0;
int v3Times = 0;
int errTimes = 0;
for (int i = 0; i < times; i++) {
//對存活節點按subset規則過濾
StringBuilder value = queryHelper.filterEndpointsBySubset(activeEp, servantProxyConfig);
//獲取value的subset值
String subset = null;
if (value != null && value.length() > 3) {
subset = value.substring(value.length() - 2);
if("v1".equals(subset)){
v1Times++;
} else if("v2".equals(subset)){
v2Times++;
} else if("v3".equals(subset)){
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);
}
測試結果如下:
結果分析:
可以看出結果比例接近v1:v2:v3 = 20:80:20,更改比例對應結果改變,按比例路由方法測試成功。
5. 按引數路由規則測試
具體測試方案為:設定染色的key為uid123,路由規則為精確(uid123) / 正則匹配(uid12*),路由規則跟染色key匹配,則路由到設定的v1;如果路由規則跟染色key不匹配,則無法路由,丟擲錯誤資訊。
測試程式碼如下:
/**
* 按引數路由規則
*/
@Test
public void testParameterAccurate() {
//新增按精確匹配路由規則
servantProxyConfig.setRuleType("parameter");
servantProxyConfig.setObjectName("objectName");
Map<String,String> map = new HashMap<>();
//精確匹配測試
map.put("equal","uid123"); //精確匹配
//map.put("equal","uid12"); //當染色key和請求的rule_type對不上時
//正則匹配測試
//map.put("match","uid12*"); //正則匹配
//map.put("match","*d123"); //正則匹配
//map.put("match","uid123"); //正則匹配
//map.put("match","*id12*"); //正則匹配
//map.put("match","*i12d*");
map.put("route","v1");
servantProxyConfig.setRuleData(map);
//設定染色的key
servantProxyConfig.setRouteKey("uid123");
//新增存活節點
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"));
activeEp.setValue(endpointFList);
//輸出過濾前節點資訊
System.out.println("過濾前節點資訊如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//對存活節點按subset規則過濾
StringBuilder value = queryHelper.filterEndpointsBySubset(activeEp, servantProxyConfig);
//後續格式化相關工作
if (value.length() < 1) {
System.out.println("找不到節點,value.length() < 1");
return;
}
value.insert(0, Constants.TARS_AT);
value.insert(0, servantProxyConfig.getSimpleObjectName());
//輸出過濾結果
System.out.println("過濾後節點資訊如下:");
System.out.println("result = " + value.toString());
}
測試結果如下:
結果分析:
經過測試,發現精確匹配路由成功;而正則匹配也能成功;當路由規則跟染色key不匹配時,則無法路由,輸出結果如下圖:
6. 按無路由規則測試
具體測試方案為:無路由規則比較簡單,直接傳入{"default" , "v3" }路由規則即可,預設路由到v3;
測試程式碼如下:
/**
* 按無路由規則
*/
@Test
public void testDefault() {
//新增按比例路由規則
servantProxyConfig.setRuleType("default");
servantProxyConfig.setObjectName("objectName");
Map<String,String> map = new HashMap<>();
map.put("default","v3");
servantProxyConfig.setRuleData(map);
//新增存活節點
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);
//輸出過濾前節點資訊
System.out.println("過濾前節點資訊如下:");
for( EndpointF endpoint : endpointFList){
System.out.println(endpoint.toString());
}
//對存活節點按subset規則過濾
StringBuilder value = queryHelper.filterEndpointsBySubset(activeEp, servantProxyConfig);
//後續格式化相關工作
if (value.length() < 1) {
System.out.println("value.length() < 1");
return;
}
value.insert(0, Constants.TARS_AT);
value.insert(0, servantProxyConfig.getSimpleObjectName());
//輸出過濾結果
System.out.println("過濾後節點資訊如下:");
System.out.println("result = " + value.toString());
}
測試結果如下:
結果分析:
按照預設的預設規則能成功路由到v3。