Tars | 第3篇 Tars中期汇报测试文档(Java语言实现Subset路由规则)
前言
本篇为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。
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!
Tars | 第3篇 Tars中期汇报测试文档(Java语言实现Subset路由规则)的更多相关文章
- Tars | 第4篇 Subset路由规则业务分析与源码探索
目录 前言 1. Subset不是负载均衡 1.1 任务需求 1.2 负载均衡源码结构图 1.3 负载均衡四种调用器 1.4 新增两种负载均衡调用器 1.5 Subset应该是"过滤&quo ...
- Tars | 第6篇 基于TarsGo Subset路由规则的Java JDK实现方式(下)
目录 前言 1. 修改.tars协议文件 1.1 Java源码位置及逻辑分析 1.2 Java语言实现方式 1.3 通过协议文件自动生成代码 1.4 变更代码的路径 2. [核心]增添Subset核心 ...
- Tars | 第5篇 基于TarsGo Subset路由规则的Java JDK实现方式(上)
目录 前言 1. 修改.tars协议文件 1.1 Go语言修改部分 1.2 修改地方的逻辑 1.3 通过协议文件自动生成代码 2. [核心]增添Subset核心功能 2.1 Go语言修改部分 2.2 ...
- 测试文档锁:doc.LockDocument()
/// <summary> /// 总结:用到DocumentManager.Open(filePath)时,如果是ForWrite,就需要用到lock文档锁. /// </summ ...
- ASP.NET WebAPI使用Swagger生成测试文档
ASP.NET WebAPI使用Swagger生成测试文档 SwaggerUI是一个简单的Restful API测试和文档工具.简单.漂亮.易用(官方demo).通过读取JSON配置显示API .项目 ...
- ElasticSearch入门 第五篇:使用C#查询文档
这是ElasticSearch 2.4 版本系列的第五篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...
- ASP.NET WebAPI 测试文档 (Swagger)
ASP.NET WebAPI使用Swagger生成测试文档 SwaggerUI是一个简单的Restful API测试和文档工具.简单.漂亮.易用(官方demo).通过读取JSON配置显示API .项目 ...
- html/css基础篇——DOM中关于脱离文档流的几种情况分析
所谓的文档流,指的是元素排版布局过程中,元素会自动从左往右,从上往下的流式排列.并最终窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素.脱离文档流即是元素打乱了这个排列,或是从排版中拿走. ...
- 使用 Swagger 自动生成 ASP.NET Core Web API 的文档、在线帮助测试文档(ASP.NET Core Web API 自动生成文档)
对于开发人员来说,构建一个消费应用程序时去了解各种各样的 API 是一个巨大的挑战.在你的 Web API 项目中使用 Swagger 的 .NET Core 封装 Swashbuckle 可以帮助你 ...
随机推荐
- elementUI的el-input和el-select宽度 一致
在用vue时,用到了element组件的 el-input 和 el-select(多选框)组件,但是宽度显示不一样,查看了多选框的css,发现element-style是写死的 添加style=&q ...
- SQL Server CPU 利用率毛刺的分析定位与解决
一.背景 1.1 问题描述 近期发现一台SQL Server的CPU利用率很不稳定,发现不定时的飙升到100%,更可怕的是在业务繁忙时,影响了业务调用,失败率明显增加,所以,减低CPU的利用率,是迫切 ...
- Dubbo 实现一个Route Factory(用于灰度发布)
Dubbo 可以实现的扩展很多, 官方文档在这: https://dubbo.apache.org/zh/docs/v2.7/dev/impls/ (太简单了....) 下面我们实现一个Route F ...
- 8.7考试总结(NOIP模拟)[Smooth·Six·Walker]
前言 踩了挺多以前没踩过的坑... T1 一开始是打了一个 60pts 的 DFS ,在与暴力拍了几组数据保证正确性之后, 突然想到 BFS 可能会更快一些,然后就又码了一个 BFS,又和 DFS 拍 ...
- Java流程控制04——Switch选择结构
switch 多选择结构 switch case 语句判断一个变量与一系列值中某个值是否相等,每个支撑位一个分支. switch语句中的变量类型可以是: byte short int 或者 char ...
- RHCSA_DAY10
分区过程 添加新硬盘--分区--格式化文件系统--挂载使用 扇区是磁盘存储数据的最小单元,默认一个扇区可以存储512字节的数据 磁盘类型介绍 IDE接口类型:主要用于个人家用计算机领域,优点价格便宜, ...
- 第3篇-CallStub新栈帧的创建
在前一篇文章 第2篇-JVM虚拟机这样来调用Java主类的main()方法 中我们介绍了在call_helper()函数中通过函数指针的方式调用了一个函数,如下: StubRoutines::cal ...
- 面试反杀「GitHub 热点速览 v.21.33」
作者:HelloGitHub-小鱼干 作为一个应聘者,面试的时候经常会被面试官问:你有什么问题要问我吗?为了避免这种临时想不到问题的尴尬,reverse-interview-zh 会教你下反向操作,提 ...
- 带你读AI论文丨用于目标检测的高斯检测框与ProbIoU
摘要:本文解读了<Gaussian Bounding Boxes and Probabilistic Intersection-over-Union for Object Detection&g ...
- vue项目中踩过的element的坑
前言:在现在这种大的社会背景下,人们的需求更加的个性化了,而之前为了解放开发复杂的原生开发状态,现有的组件库已经远远不能满足人们高质量的需求了,这两天开发发现了一些element UI交互上的缺陷,当 ...