How expensive operation is newClientBuilder (Java client)?

Hi,

I start a Zeebe workflow instance and do workflow correlation from behind a service with a rest api.
How expensive is the ZeebeClient.newClientBuilder operation if this is done for each message correlation in a process - for example as the code below?

Regards,
Ken

private void sendEvent(String messageName, String orderId) {
    try {
        final ZeebeClient client = ZeebeClient.newClientBuilder()
                // change the contact point if needed
                .gatewayAddress("127.0.0.1:26500")
                .usePlaintext()
                .build();

        Duration timeToLive = Duration.ofMinutes(60L);

        client.newPublishMessageCommand().
                messageName(messageName).
                correlationKey(orderId).
                timeToLive(timeToLive).
                send().
                join();
    }catch (Exception e){
        logger.error("", e);
    }
}

Hi @ken,

Interesting question. I ran a quick test on this, but in practise (with really sending commands ) it might be different so take it with a grain of salt.

I ran the following test:

@Test
  public void test() {
    measure(1);
    measure(10);
    measure(100);
    measure(1000);
    measure(10000);
    measure(100000);
  }

  private void measure(final int times) {
    final Instant first = Instant.now();
    for (int i = 0; i < times; i++) {
      buildClientAndClose();
    }
    final Instant second = Instant.now();
    System.out.println("Difference (" + times + "): " + Duration.between(first, second));
  }

  private void buildClientAndClose() {
    final ZeebeClient client =
        ZeebeClient.newClientBuilder()
            // change the contact point if needed
            .gatewayAddress("127.0.0.1:26500")
            .usePlaintext()
            .build();
    client.close();
  }

The outcome was:

Difference (1): PT5.76214S
Difference (10): PT0.006624S
Difference (100): PT0.050631S
Difference (1000): PT0.368002S
Difference (10000): PT2.453653S
Difference (100000): PT20.728081S

Process finished with exit code 0

Interesting to note is the initial 5 seconds, while all following calls are many orders of magnitude faster. (Speculation: this might be JVM warmup, classloading, reflection, setting up a connection that even when closed is kept alive). It may be dependent on your situation whether this initial cost must be payed with each of your calls from your service or not.

I think one way to find out is to run some more tests. Another might be to look into grpc itself, since the only things that really take time for the ZeebeClient’s construction is the ManagedChannel and GatewayStub construction (see ZeebeClientImpl constructors). Hope it helps. Good luck :+1:

PS: I guess I would still suggest to just build the client once, or a couple times (for a threadpool or so), and leave it at that.

Hi,
Thank you @korthout for taking the time on this!
I have been working on other things and returning to this now. As you say, I need to do some more testing.

Sure! No problem. I was interested as well :slightly_smiling_face:. Let me know when you find out more.

Interestingly enough, when doing the above sendEvent(messageName, orderId) from behind a rest service call, the results are the same. I have to look into the ManagedChannel and GatewayStub to see why this is the case. It seems that one can get by without some kind of client object pool.
Duration of client setup for sending event: PT5.279655S
Duration of client setup for sending event: PT0.019052S
Duration of client setup for sending event: PT0.025001S
Duration of client setup for sending event: PT0.018932S
Duration of client setup for sending event: PT0.020854S
@korthout

1 Like

Hey guys,

the current test’s you’re doing are not really expressive. The issue you’re seeing is that on the first run you have a cold start of the jvm. Afterwards the JVM has warmed up and the jit optimized the code, which means the code is much faster. For micro benchmarking I would suggest you use a framework build for that, like https://github.com/openjdk/jmh. This normally does the warm ups for you, before it really runs and benchmarks your code.

You can also read a related article https://www.baeldung.com/java-jvm-warmup and there is also other good resources out there about java performance testing.

As @korthout suggested I would also say you just create your client once and re-use it on your REST API calls, as far as I’m aware it should be thread safe.

Greets
Chris

1 Like

Yes, of course. Good points. Thank you, @Zelldon.

1 Like