分布式请求放大器实现

时间:2022-10-17 17:03:20

在很早之前我就有个想法,如果有一个服务能把我的请求放大N倍发送给服务端,那就可以更加灵活地将接口的功能测试用例和性能测试用例结合在一起。只需要设置一些参数,就可以在本地控制请求QPS,比如每秒100次,然后通过服务器放大100倍,那么请求到被测服务的QPS就是10000倍了。

但是由于当时技术水平比较菜,主要考虑到:1、当时面临被测服务的QPS有限,不需要这个功能;2、为了这个需求写个用不到的服务,无法落地。所以就放弃了。

在最近更新DCS_FunTester分布式压测框架的时候,我又回想起来这件事情,如此前面两个考虑的因素基本解决。说干就干,先上再说。计划主要用于以QPS为主要标准的压测,而非并发或线程。

思路

首先由master节点接受请求信息,然后分配给一个slave节点去按照倍数执行(采用for循环),不计入性能测试状态。

没有使用FunTester测试框架中的性能模板,因为放大倍数比较少,整体来说消耗不大。目前自己测试结果来讲,没有遇到大的问题,这跟用户就我一个人有关系。

定位就是在被测接口QPS在1万以内,通过本地请求,分布式执行放大请求倍数,达到性能测试的目的,当然比较粗略。

以后遇到新需求再优化,目前重点放在HTTP协议,其他协议接口未来会支持。

master节点

service

实现方法:

    @Override
    void runRequest(ManyRequest request) {
        def host = NodeData.getRunHost(1)
        MasterManager.runMany(host, request)
    }

工具类代码:

/**
 * 运行放大器
 * @param host
 * @param request
 * @return
 */
    static boolean runMany(String host, ManyRequest request) {
        String url = SlaveApi.RUN_MANY;
        def response = getPostResponse(host, url, request)
        isRight(response)
    }

slave节点

service

实现方法:

    @Async
    @Override
    public void runMany(ManyRequest request) {
        FunRequest funRequest = FunRequest.initFromJson(request.toJson());
        HttpRequestBase requestBase = funRequest.getRequest();
        Integer times = request.getTimes();
        try {
            for (int i = 0; i < times; i++) {
                FunLibrary.executeSimlple(requestBase);
            }
        } catch (Exception e) {
            FailException.fail(e.getMessage());
        }
    }

使用了异步执行,有机会评估异步和同步对服务性能影响。

执行请求

这里用到了FunTester测试框架的方法。

    /**
     * 简单发送请求,此处不用{@link CloseableHttpResponse#close()}也能释放连接
     *
     * @param request
     */
    public static String executeSimlple(HttpRequestBase request) throws IOException {
        CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
        return getContent(response.getEntity());
    }

slave节点用的是Java写的,后期DCS_FunTester可能会出一个纯Java版本。

参数对象

@ApiModel(value = "单请求放大器参数")
class ManyRequest extends AbstractBean {

    private static final long serialVersionUID = -49090532920398509L;

    @Pattern(regexp = "get|post|Get|Post|GET|POST", message = "请求方法错误!")
    String requestType

    @NotBlank
    @Pattern(regexp = "http.*", message = "请求url错误")
    String uri

    @NotNull
    JSONObject args

    @NotNull
    JSONObject params

    @NotNull
    JSONObject json

    @NotNull
    JSONArray headers

    @Length(min = 10, max = 100, message = "倍数范围错误")
    Integer times

}