Skip to content

Dapr Invoke Method has very low throughput compared to calling API directly #709

Description

@yschneider-bosch

Expected Behavior

invokeMethod sends requests asynchronously and parallel. The number of connections, threads etc can be configured. The performance should match calling the api endpoint directly.

Actual Behavior

We have started investigating as we noticed that under load, requests are processed almost sequentially, leading to very long processing time if the target method takes long time to complete.

There is no possibility to control the underlying http client or configure anything in order to mitigate this problem, which was only solved by increasing the number of instances.

Comparing to calling the rest endpoint directly, the throughput of invokeMethod is about 16 times slower.

Steps to Reproduce the Problem

Please find a modified version of the invoke example from the sdk. Request processing at the server side is 1 second to demonstrate the effect. HTTP Client call is commented out, please uncomment it and comment the invoke method for a comparison.

Also find modified logs of both executions, with the httpclient and with dapr invokeMethod.

As you can see, execution with the httpclient takes around 1 second for all 50 requests while with dapr invoke it takes around 16 seconds.

with-dapr-invoke.txt
with-http-client.txt

DemoServiceController.java

@PostMapping(path = "/say")
  public Mono<String> handleMethod(@RequestBody(required = false) byte[] body,
                                   @RequestHeader Map<String, String> headers) {
    return Mono.fromSupplier(() -> {
      try {
        String message = body == null ? "" : new String(body, StandardCharsets.UTF_8);

        Calendar utcNow = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

        // Handles the request by printing message.
        System.out.println(String.format("%s server request received", Instant.now().toEpochMilli()));
        Thread.sleep(1000);
        System.out.println(String.format("%s server request done", Instant.now().toEpochMilli()));

        return message + " received";
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    });
  }

DemoServiceController.java

public static void main(String[] args) throws Exception {
    var executor = Executors.newFixedThreadPool(50);
    try (DaprClient client = (new DaprClientBuilder()).build()) {
      for (var i = 0; i < 50; i++) {
        final String msg = "" + i;
        final Integer key = i;
        executor.execute(() -> {
          var timestamp = Instant.now().toEpochMilli();

          // use invokeMethod
          System.out.println(String.format("%d client invoke started", timestamp));
          client.invokeMethod(SERVICE_APP_ID, "say", "" + msg, HttpExtension.POST, null,
                  byte[].class).block();


          // use http client directly
          //          System.out.println(String.format("%d http client request started", timestamp));
          //          HttpClient httpClient = HttpClient.newHttpClient();
          //          HttpRequest request = HttpRequest.newBuilder()
          //                  .POST(HttpRequest.BodyPublishers.ofString("message"))
          //                  .uri(URI.create("http://localhost:3000/say"))
          //                  .build();
          //          httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
          //                  .thenApply(HttpResponse::body)
          //                  .thenAccept(System.out::println)
          //                  .join();
          //          System.out.println(String.format("%d client http request done", timestamp));

          timestamp = Instant.now().toEpochMilli();
          System.out.println(String.format("%d client invoke done", timestamp));
        });

      }

    }

  }

add this to the application properties:
server.tomcat.threads.max=400

Release Note

RELEASE NOTE:

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions