Camel Framework: Comparing HTTP and AHC Components

This article compares the operation of the simplest services implemented using the Camel framework and its two components: HTTP and AHC. We will not delve into the structure and work with the framework itself, it is assumed that the reader is already a little familiar with it.





We will consider a simple Camel service that receives requests from the jetty component, processes them, for example, displays them in the log, calls another service via http, and processes the response from it, for example, writes to the log.





For testing, JMeter scripts were used to call our service in accordance with the planned frequency and intervals, as well as a small Http service that plays the role of external to our service and performs a delay of 5 seconds. All communication occurs on a local loop (127.0.0.1), so network latencies are not taken into account, but they are not needed for comparative analysis.





HTTP component

This section will look at the standard HTTP component for HTTP communication. Simple service code:





from("jetty:http://localhost:8080/test")
     .log("receive request body ${body}")
     .removeHeaders("CamelHttp*")
     .to("http://{{another.url}}")
     .log("finish process body ${body}");
      
      



Note: Removing headers starting with "CamelHttp" is necessary because they are exposed in the Jetty component and may affect the operation of the Http component.





To test the operation of this service, let's run the JMeter script that sends 25 simultaneous requests.





Samples





Min





Max





Error%





25





5012





7013





20.000%





, 20% 5 25 (Read timed out). , http- 20 . connectionsPerRoute





from("jetty:http://localhost:8080/test")
     .log("receive request body ${body}")
     .removeHeaders("CamelHttp*")
     .to("http://{{another.url}}?connectionsPerRoute=200")
     .log("finish process body ${body}");
      
      



25 . – jetty-, 200. 4 JMeter:





  1. 200





  2. 300





  3. 300 5 , 5





  4. 200 5 , 5





1 JVM 214 , .





:





 









200





0%





300





34.667%





300 5





71.733%





200 5





0%









300 , 200 jetty-, 100 jetty, 5 , 10. 34% – 100 .





, – 300 5 , 5 , .. 60 , 200 5 , .





, , , , jetty- .





, jetty-, JVM 1 , Docker- , . .





AHC-

AHC- - Camel HTTP. AsyncHttpClient, () . – http- , , .. 5 . , . :





from("jetty:http://localhost:8080/test")
     .log("receive request body ${body}")
     .removeHeaders("CamelHttp*")
     .to("ahc:http://{{another.url}}")
     .log("finish process body ${body}");
      
      



, 300 . , http- . JVM:





, . :





 









300 5





0%





800 5





0%





1200 5





1.533%





1600 5





15.02%





, , .





, , 1200 1600 http-, - , .





AHC-

AHC-, . :





from("jetty:http://localhost:8080/test")
     .log("receive request body ${body}")
     .removeHeaders("CamelHttp*") 
     .setHeader("rand", ()->new Random().nextInt(10000) )
     .toD("ahc:http://{{another.url}}?rand=${headers.rand}")
     .log("finish process body ${body}");

      
      



After running the script with a one-time start of 300 requests, the state of the threads in the JVM:





As you can see, there is too much flow. The fact is that by default, the AHC component for each endpoint creates its own instance of the AsyncHttpClient object, each of which has its own pool of connections and threads, as a result, for each request, 2 threads are created - one I / O thread, another timer thread for control timeouts and keep connections in KeepAlive state. To avoid this, you need to configure the AsyncHttpClient instance at the component level, which will be passed to the endpoint when it is created.





AhcComponent ahc = getContext().getComponent("ahc", AhcComponent.class);
ahc.setClient(new DefaultAsyncHttpClient());
      
      



After that, the creation of many AsyncHttpClient instances will stop.








All Articles