On this article, I wish to share my expertise with making a native picture for EmbeddedKafka utilizing GraalVM. Using this picture in integration checks not solely accelerates the execution of take a look at eventualities but in addition reduces reminiscence consumption. Apparently, when in comparison with utilizing confluentinc/cp-kafka in Testcontainers, there’s a noticeable distinction in each pace and reminiscence utilization — and it is not in favor of the latter.
EmbeddedKafka, Testcontainers, and GraalVM
A quick overview of the important thing parts used within the undertaking:
EmbeddedKafka
EmbeddedKafka is a instrument that permits embedding a Kafka server straight right into a JVM utility or testing surroundings. That is helpful for integration testing of purposes that use Apache Kafka for knowledge stream processing or as a messaging system. EmbeddedKafka is primarily used for remoted testing of interactions with Kafka, simplifying setup and administration of checks resulting from its fast startup and shutdown. This ensures take a look at reproducibility in several environments and supplies management over the Kafka configuration. Nevertheless, working Embedded Kafka in a JVM utility will increase reminiscence utilization resulting from Kafka’s resource-intensive nature and the necessity for knowledge storage. This can be a trade-off between improvement comfort and extra reminiscence load, making an exterior Kafka server (relative to the JVM utility) extra preferable for manufacturing environments or in circumstances of restricted reminiscence sources.
Testcontainers
Testcontainers is a framework used to help automated integration checks utilizing Docker containers. It permits the creation, administration, and deletion of containers throughout take a look at execution. Utilizing Docker containers ensures consistency of the testing surroundings throughout totally different machines and platforms, simplifying native improvement and testing. Utilizing Kafka in Testcontainers affords a number of benefits, particularly with regards to testing in a extra life like and versatile surroundings. Testcontainers runs Kafka cases primarily based on the official Confluent OSS Platform photographs.
GraalVM
GraalVM is a platform for working applications, supporting numerous programming languages and applied sciences. Amongst different issues, it permits compiling Java purposes into statically linked executable information (native binaries). These native executable information run sooner, require much less reminiscence, and don’t require an put in JVM.
Take a look at State of affairs
For example the approaches to writing checks, I’ve ready code examples comparable to a easy take a look at state of affairs:
- Ship a message value1 to the subject topic1.
- Learn the message from the subject topic1.
- Confirm that the worth is the same as value1.
Examples will be discovered within the undertaking repository:
The repository construction facilitates the comparability of modules to judge the variations in construction and composition of code when utilizing every method.
Wrapping EmbeddedKafka in a Container
The primary process was to implement the launch of EmbeddedKafka inside a separate container. To do that, I took the next simple steps:
- Created an ordinary Spring Boot utility utilizing Spring Initializr.
- Within the utility, I arrange the launch of an occasion of the
org.springframework.kafka.take a look at.EmbeddedKafkaZKBroker
class with the mandatory parameters. - Described a Dockerfile and constructed the picture
All of the above actions are mirrored within the code of the emk-application module within the undertaking repository.
Launching EmbeddedKafka in a Container
The Testcontainers documentation supplies a information to launching a Kafka container utilizing the KafkaContainer
class as follows:
KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))
Nevertheless, this class was not appropriate for my wants, as it’s supposed to be used with confluentinc/cp-kafka appropriate photographs. However, analyzing it was helpful because it revealed an attention-grabbing logic across the dealing with of the KAFKA_ADVERTISED_LISTENERS
parameter:
- Firstly of the container, a substitution of
ENTRYPOINT
/COMMAND
directions is carried out. - After beginning, the
KAFKA_ADVERTISED_LISTENERS
parameters are handed to the container together with directions for beginning Kafka.
This course of is detailed within the accompanying diagram.
Why is that this obligatory? Throughout operation, a shopper could connect with any Kafka node to acquire the deal with for performing learn/write operations, even when Kafka is represented by a single node. An exterior deal with is required for an exterior person, and equally, an inner deal with for an inner person. By specifying KAFKA_ADVERTISED_LISTENERS
, we offer the dealer with details about its exterior deal with, which the dealer then communicates to the shopper. The shoppers will likely be exterior relative to the dealer for the reason that dealer is working in a container.
I applied the logic described above in a brand new class: EmbeddedKafkaContainer.java.
Making a Native Picture for EmbeddedKafka
The only solution to begin a brand new Spring Boot undertaking for GraalVM is to go to the location begin.spring.io, add the “GraalVM Native Support” dependency, and generate the undertaking. The undertaking comes with a HELP.md file, which supplies helpful ideas for getting began.
Metadata Assortment
The instrument for constructing a local picture depends on static evaluation obtainable through the execution of the applying code. Nevertheless, this evaluation shouldn’t be at all times able to totally predicting all use circumstances of Java Native Interface (JNI), Java reflection, dynamic proxy objects, and so forth. Subsequently, these use circumstances of dynamic features must be explicitly specified to the native picture construct instrument within the type of metadata. A technique to offer such metadata is thru JSON information positioned within the undertaking listing META-INF/native-image/
GraalVM affords a Tracing Agent for handy assortment of metadata and preparation of configuration information. This agent tracks all cases of dynamic operate utilization through the utility’s execution on an ordinary Java VM.
My method was as follows:
- I launched an occasion of a Spring utility with Embedded Kafka underneath the JVM with the Tracing Agent.
- I ran a big set of checks from one in every of my tasks, utilizing the launched utility as the primary Kafka dealer.
The information generated throughout this course of had been positioned within the undertaking listing META-INF/native-image.
Launch and Utilization
To exhibit the outcomes, I ready the next artifacts:
- A library with the
EmbeddedKafkaContainer
class: pw.avvero:emk-testcontainers:1.0.1 - Docker photographs:
avvero/emk
(JVM) andavvero/emk-native
(native, platform=linux/arm64) - An instance utilization comparable to the take a look at state of affairs will be discovered within the example-embedded-kafka-container module.
The KafkaContainerConfiguration is configured as follows:
@TestConfiguration(proxyBeanMethods = false)
public class KafkaContainerConfiguration {
@Bean
@RestartScope
@ServiceConnection
EmbeddedKafkaContainer kafkaContainer() {
return new EmbeddedKafkaContainer("avvero/emk-native:1.0.0");
}
}
To evaluate reminiscence utilization, I ran checks for about 7 minutes from one in every of my tasks. Based mostly on observations in docker stats, I observed the next traits in reminiscence consumption:
confluentinc/cp-kafka:7.3.3 | 1.331GiB |
avvero/emk | 677.3MiB |
avvero/emk-native | 126.4MiB |
Reminiscence evaluation (Younger + Previous + Meta house) by GC logs utilizing GCeasy confirmed the next:
confluentinc/cp-kafka:7.3.3 | 1.06 gb/866.92 mb (Allotted/Peak) |
avvero/emk | 567.62 mb/241.74 mb (Allotted/Peak) |
avvero/emk-native | 20.00M -> 15.50M? |
Analyzing GC logs for the native picture presents a extra advanced process for the reason that format and composition of information differ from “standard” GC logs. Sadly, I couldn’t discover an evaluation instrument appropriate for this objective that might present prepared analytics. Subsequently, under is a fraction of the log, which helps to estimate the final order of reminiscence utilization in my case.
[497.519s] GC(11371) Acquire on allocation
[497.520s] GC(11371) Eden: 4.50M->0.00M
[497.520s] GC(11371) Survivor: 0.00M->0.00M
[497.520s] GC(11371) Previous: 15.50M->15.50M
[497.520s] GC(11371) Free: 3.50M->8.00M
[497.520s] GC(11371) Incremental GC (Acquire on allocation) 20.00M->15.50M 0.896ms
GC log information are hooked up to the efficiency take a look at module.
Relating to startup time, I performed a sequence of efficiency checks utilizing JMH to evaluate the launch time and operational readiness of various Kafka container configurations:
testContainersKafkaStartAndReady
– Testcontainers with confluentinc/cp-kafka:7.3.3emkJvmKafkaStartAndReady
– avvero/emk (JVM)emkNativeKafkaStartAndReady
– avvero/emk-native (native, platform=linux/arm64)
The checks give attention to verifying each startup and readiness. Merely launching a Kafka container doesn’t at all times imply it’s prepared for operations. The readiness verify simulates a real-world state of affairs during which Kafka shouldn’t be solely launched but in addition totally operationally prepared. This supplies a extra complete view of the time required for Kafka to be totally operational in numerous containerized environments.
The efficiency take a look at outcomes are as follows:
Benchmark Mode Cnt Rating Error Models
TestContainersBenchmark.testContainersKafkaStartAndReady ss 10 3,091 ± 0,354 s/op
TestContainersBenchmark.emkJvmKafkaStartAndReady ss 10 2,659 ± 0,708 s/op
TestContainersBenchmark.emkNativeKafkaStartAndReady ss 10 0,521 ± 0,055 s/op
The avvero/emk-native:1.0.0 container demonstrates increased efficiency, displaying a median startup and readiness verify time of simply 0.521 seconds with a deviation of ±0,055.
Conclusion
Using a local picture for EmbeddedKafka with GraalVM in integration checks accelerates take a look at startup time and reduces reminiscence consumption, making it an environment friendly resolution in comparison with conventional strategies, resembling utilizing confluentinc/cp-kafka in Testcontainers.
Using GraalVM opens up new alternatives for builders aiming to enhance the efficiency and effectivity of integration checks. This method will be tailored and expanded for different related duties and applied sciences, underscoring its versatility and potential within the discipline of software program improvement.
Thanks on your consideration to the article, and good luck in your endeavor to put in writing efficient and quick checks!