最早提到测试的优点时,有一个就是执行效率提升,可能是 ui 层面执行的 n 倍。但是今天我要分享的这个案例这个优点的升级版本。文章源自玩技e族-https://www.playezu.com/345387.html
某个参数倒是不多,但是每个参数的范围略大,最大的将近 500 个枚举范围,小的也是 20 个。如果把所有参数组合穷举完,粗略估计可能 10 亿级别的。文章源自玩技e族-https://www.playezu.com/345387.html
需求就是要把这部分所有参数组合都遍历进行测试,然后我就开始了踩坑了。文章源自玩技e族-https://www.playezu.com/345387.html
初版方案
一开始的想法就是多个循环嵌套,然后并发发起请求,实现起来非常简单方便。如下:文章源自玩技e族-https://www.playezu.com/345387.html
@log4j2
class tt extends monitorrt {
static void main(string[] args) {
["types参数集合"].each {
def type = it
["id类型集合"].each {
def id = it
2.upto(99) {
def a = it
2.upto(99) {
def b = it
2.upto(99) {
def c = it
def params = new jsonobject()
params.id = id
params.endtime = 0
params.type = type
params.parammap = parse("{"a":"${a}","b":"$b","c":"$c"}")
fun {
gethttpresponse((url,params))
}
}
}
}
}
}
}
}
但是方案的缺陷显而易见。文章源自玩技e族-https://www.playezu.com/345387.html
- 数量太大,导致后面的异步任务直接被线程池拒绝
- 无法控制 qps 和并发数
针对这第一个问题,我是增加了异步线程池等待的长度,可以我发现了新的问题,就是内存压力太大,这个会在后面的中也遇到。文章源自玩技e族-https://www.playezu.com/345387.html
升级版
针对存在第二个问题,我回归到性能测试框架中,通过动态调整 qps 的功能来调整 qps 或者并发数,这里我选择了 qps,这个更容易更可控。我的思路是,先把所有参数遍历一遍,存在一个 list 当中,然后在去遍历这个 list,通过动态 qps 压测模型把所有请求发出去。文章源自玩技e族-https://www.playezu.com/345387.html
static void main(string[] args) {
def list = []
["types参数集合"].each {
def type = it
["id类型集合"].each {
def id = it
2.upto(99) {
def a = it
2.upto(99) {
def b = it
2.upto(99) {
def c = it
def params = new jsonobject()
params.id = id
params.endtime = 0
params.type = type
params.parammap = parse("{"a":"${a}","b":"$b","c":"$c"}")
}
}
}
}
}
atomicinteger index = new atomicinteger()
def test = {
def increment = index.getandincrement()
if (increment >= list.size()) funqpsconcurrent.stop()
else gethttpresponse((url, list.get(increment)))
}
new funqpsconcurrent(test,"遍历10亿参数组合").start()
}
但是新的问题立马就来了,当我运行改代码的时候,发现本机的 cpu 疯狂飙升,仔细看了一下,原来是 gc 导致的。存放这么多的数据,内存撑不住了。下面就着手解决内存的问题,这里参考10 亿条日志回放 chronicle 性能测试中的思路。文章源自玩技e族-https://www.playezu.com/345387.html
终版
这里用到了线程安全的java.util.concurrent.linkedblockingqueue
以及对应长度的等待功能,再配合异步生成请求参数,基本上完美解决需求。这里依旧使用休眠 1s 来进行缓冲,避免长度过大,只有长度足够 1s 的 2 倍消费即可。文章源自玩技e族-https://www.playezu.com/345387.html
static void main(string[] args) {
def ps = new linkedblockingqueue()
fun {
["types参数集合"].each {
def type = it
["id类型集合"].each {
def id = it
2.upto(99) {
def a = it
2.upto(99) {
def b = it
2.upto(99) {
def c = it
def params = new jsonobject()
params.id = id
params.endtime = 0
params.type = type
params.parammap = parse("{"a":"${a}","b":"$b","c":"$c"}")
if (ps.size() > 10_0000) sleep(1.0)
ps.put(params)
}
}
}
}
}
}
atomicinteger index = new atomicinteger()
def test = {
def params = ps.poll(100, timeunit.milliseconds)
if (params == null) funqpsconcurrent.stop()
else gethttpresponse((url, params))
}
new funqpsconcurrent(test, "遍历10亿参数组合").start()
}
随着对的学习和使用,最近自己也想写一个 10 亿级别的日志回放功能,到时候对比chronicle
看看性能如何,敬请期待。文章源自玩技e族-https://www.playezu.com/345387.html
文章源自玩技e族-https://www.playezu.com/345387.html
免责声明:本文内容来自用户上传并发布或网络新闻客户端自媒体,玩技博客仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请联系删除。
17f
文章背景写的是接口测试。。
16f
这是个需求,不是测试场景。也不是测试用例。
15f
这是个需求。
14f
没遇到这种场景,这是个需求,不是测试场景。
13f
这是个需求,实现的意义就是满足需求。
12f
谢谢
11f
超过 1 小时,小于 4 小时,没太关注具体时间。