首页 > 解决方案 > quarkus http 调用负载测试结果 1000 个请求 - 16 秒 vs 65 秒

问题描述

测试1:

@Path("/performance")
public class PerformanceTestResource {

    @Timeout(20000)
    @GET
    @Path("/resource")
    @Produces(MediaType.APPLICATION_JSON)
    public Response performanceResource() {

        final String name = Thread.currentThread().getName();
        System.out.println(name);

        Single<Data> dataSingle = null;

                try {
                    dataSingle = Single.fromCallable(() -> {
                        final String name2 = Thread.currentThread().getName();
                        System.out.println(name2);
                        Thread.sleep(1000);
                        return new Data();
                    }).subscribeOn(Schedulers.io());

                } catch (Exception ex) {
                    int a = 1;
                }

        return Response.ok().entity(dataSingle.blockingGet()).build();
    }

}

测试本身也参见定义callPeriodically

@QuarkusTest
public class PerformanceTestResourceTest {

        @Tag("load-test")
        @Test
        public void loadTest() throws InterruptedException {

            int CALL_N_TIMES = 1000;
            final long CALL_NIT_EVERY_MILLISECONDS = 10;

            final LoadTestMetricsData loadTestMetricsData = LoadTestUtils.callPeriodically(
                                                                                    this::callHttpEndpoint,
                                                                                    CALL_N_TIMES,
                                                                                    CALL_NIT_EVERY_MILLISECONDS
                                                                            );

            assertThat(loadTestMetricsData.responseList.size(), CoreMatchers.is(equalTo(Long.valueOf(CALL_N_TIMES).intValue())));

            long executionTime = loadTestMetricsData.duration.getSeconds();

            System.out.println("executionTime: " + executionTime + " seconds");

            assertThat(executionTime , allOf(greaterThanOrEqualTo(1L),lessThan(20L)));
        }

结果测试1:

执行时间:16 秒

测试 2:相同但没有 @Timeout注释:

执行时间:65 秒

问:为什么?我认为即使是 16 秒也很慢。问:如何使其更快:假设 1000 次通话需要 2 秒。

我意识到我.blockingGet()在资源中使用,但我仍然希望重新使用阻塞线程。

PS 我试图更“被动”地返回SingleCompletionStage从响应中返回 - 但这似乎还没有准备好(在轻松休息方面有问题)。所以我选择简单的 .blockingGet()` 和 Response。

更新:反应式 / RX Java 2 方式

@path("/performance")
public class PerformanceTestResource {

//@Timeout(20000)
@GET
@Path("/resource")
@Produces(MediaType.APPLICATION_JSON)
public Single<Data> performanceResource() {

    final String name = Thread.currentThread().getName();

    System.out.println(name);
    System.out.println("name: " + name);

    return Single.fromCallable(() -> {

        final String name2 = Thread.currentThread().getName();
        System.out.println("name2: " + name2);

        Thread.sleep(1000);
        return new Data();
    });
}
}`

pom.xml

io.smallrye smallrye-context-propagation-propagators-rxjava2 org.jboss.resteasy resteasy-rxjava2

然后在运行相同的测试时:

执行时间:64 秒

输出将类似于:

name: vert.x-worker-thread-5 vert.x-worker-thread-9 name: vert.x-worker-thread-9 
name2: vert.x-worker-thread-9 
name2: vert.x-worker-thread-5

所以,我们阻塞了工作线程,即在 REst/Resource 端使用。就是这样。然后

如果我use:Schedulers.io()在 sleep-1000-call 的单独执行上下文中:

return Single.fromCallable(() -> { ... }).subscribeOn(Schedulers.io());

执行时间:16秒

输出将是这样的(见一个新人:RxCachedThreadScheduler)

name: vert.x-worker-thread-5
name2: RxCachedThreadScheduler-1683
vert.x-worker-thread-0
name: vert.x-worker-thread-0
vert.x-worker-thread-9
name: vert.x-worker-thread-9
name2: RxCachedThreadScheduler-1658
vert.x-worker-thread-8

似乎不管:无论我是否明确使用blockingGet(),我都会得到相同的结果。

我假设如果我不阻止它,它会在2-3 秒左右

问:我有办法从这一点上修复/调整这个吗?

我假设在这一点上使用Schedulers.io()它会带来RxCachedThreadScheduler瓶颈,所以我最终得到16 秒,默认情况下200 io / io 线程是限制?但是那些应该被重用而不是真正被阻止。(不要认为将限制设置为 1000 是个好主意)。

问:或者无论如何:如何让应用程序像 Quarkus 那样具有响应性/反应性/高性能。或者我错过了什么?

谢谢!

标签: quarkus

解决方案


Ok. Maybe it is me. In my callPeriodically(); i pass CALL_NIT_EVERY_MILLISECONDS = 10 milliseconds. 10 * 1000 = 10 000 - + ten seconds just to add the requests.

This, I set it to 0.

And got my 6 seconds for server 1000 simulations requests.

Still not 2-3 seconds. But 6.

Seems there is no difference if I use .getBlocking and return Response or returning Single.

--

But just to mention it, this hello world app take 1 second to process 1000 parallel requests. While Quarkus one is 6 seconds.

public class Sample2 {

    static final AtomicInteger atomicInteger = new AtomicInteger(0);

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

        final List<Single<Response>> listOfSingles = Collections.synchronizedList(new ArrayList<>());

        for (int i=0; i< 1000; i++) {

//            try {
//                Thread.sleep(10);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            final Single<Response> responseSingle = longCallFunction();

            listOfSingles.add(responseSingle);

        }

        Single<Response> last = Single.merge(listOfSingles).lastElement().toSingle();

        final Response response = last.blockingGet();

        long end = System.currentTimeMillis();

        System.out.println("Execution time: " + (end - start) / 1000);

        System.out.println(response);

    }

    static Single<Response> longCallFunction() {
        return Single.fromCallable( () -> { // 1 sec
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(1000);
            int code = atomicInteger.incrementAndGet();
            //System.out.println(code);
            return new Response(code);
        }).subscribeOn(Schedulers.io());
    }

}

推荐阅读