General Recommendations
For applications with many endpoints, prefer fewer and smaller session variables over many or
large ones.The session scope is serialized and deserialized every time a message crosses
an endpoint, even a VM endpoint. So if an application has a lot of endpoints, it will involve many
serializations/deserializations. Using fewer and smaller session variables helps minimize this
overhead.
When it comes to performance, not all formats are equal. Some payload formats allow faster
access to data than others. Bean payloads tend to be the fastest for Mule applications. So if it is
a viable option given other considerations, create payloads in Java objects.
Mule Expression Language (MEL) can be used to extract data from messages.8 In terms of
performance, allowing MEL to extract data can be preferable to using a scripting language.
Scripting languages are dynamically typed. Some are even interpreted at runtime. Those factors
can generate overhead that may degrade performance.
Flow references are a pleasantly direct way to enable flow communication within an application.
Flow references are preferred for communications between flows than VM endpoints. Flow
references inject messages into the target flow without intermediate steps. Although the
VM connector is an in-memory protocol. It emulates transport semantics that serialize and
deserialize parts of messages. The phenomenon is especially notable in the Session scope. As
such, flow references are superior to VM endpoints for the purpose of inter-flow communication
because the former avoid unnecessary overhead generated by serialization and deserialization.
JVM and GC flags can be set for Mule in wrapper.conf .
It is easy to get passionate about a particular Java Virtual Machine (JVM) or garbage collection
(GC) method. JRockit versus HotSpot, parallel mark-and-sweep (MS) versus G1.
- MuleSoft uses HotSpot, the standard Oracle JVM. HotSpot is
well-supported and easy to customize for a variety of purposes.
MuleSoft’s performance testing emphasizes throughput, and thus
parallel GC. HotSpot is also easy to optimize for response time. The
tips in the following sections show how to calibrate HotSpot for
throughput or response time.
Designate the initial and maximum heap sizes to be the same value.
This can be done by setting MaxMetaspaceSize=MetaspaceSize and
MaxNewSize=NewSize . Doing so can avoid the need for the JVM to
dynamically allocate additional memory during runtime. The flags are
set in wrapper.conf .
e.g.
wrapper.java.additional.16=-XX:NewSize=1365m
wrapper.java.additional.17=-XX:MaxNewSize=1365m
wrapper.java.additional.18=-XX:MetaspaceSize=256m
wrapper.java.additional.19=-XX:MaxMetaspaceSize=256m
wrapper.java.additional.20=-Xms=2048m
wrapper.java.additional.21=-Xmx=2048m
There are at least two reasons why such dynamic reallocation can
hinder performance. First, the JVM performs a major GC for each heap
resize. A full GC stops all threads for a period of time. That holds
even when using concurrent mark-and-sweep (CMS). World-stopping
should always be minimized, other things being equal. This is
especially crucial for applications prioritizing low response times.
Dynamic heap resizing creates a second worry when memory is tight.
Suppose the JVM increases its heap size during runtime and the system
does not have enough free memory pages readily available. As a
result, some pages for a kernel-chosen process might be swapped out
to disk. The circumstance would incur slowdown due to increased disk
IO.
Garbage Collection
HotSpot is equipped with three canonical garbage collection (GC) mechanisms. These are
serial, parallel, and concurrent mark-and-sweep (CMS).18 Garbage First (G1) has recently been
added to the list.19 The JVM uses parallel GC by default on machines with 2 or more physical
processors and 2 or more GB of physical memory.
Parallel GC is the default garbage collection algorithm in HotSpot JVM. When triggered, it uses
multiple threads to scan, move and collect the unreachable objects in the heap.
CMS GC (Concurrent-Mark-Sweep)
Concurrent mark-and-sweep (CMS) GC is designed to reduce application pauses by running
most of the cleaning phases concurrently with the application threads, hence it offers more
control over the stall time which affects the application response time.
Here is an example demonstrating how to set the JVM to use CMS, plus other options. Set the
following in Mule’s wrapper.conf file. Section 6, “Sample Configuration Files” gives additional
context in which the flags are set.
wrapper.java.additional.22=-XX:+UseConcMarkSweepGC
wrapper.java.additional.23=-XX:CMSInitiatingOccupancyFraction=65
wrapper.java.additional.24=-XX:UseCMSInitiatingOccupancyOnly
The flag -XX:CMSInitiatingOccupancyFraction designates a percentage of the total heap
usage. When that percentage is reached, the JVM will trigger a CMS GC. A value of 40 to
70 typically suffices for applications running on Mule. If the value is too low, it could result in
excessive, premature collections. It is usually recommend to start at a relatively higher value for
-XX:CMSInitiatingOccupancyFraction and decrease it as needed to optimize for the fewest CMS
events for the best performance.
Specify -XX:+UseCMSInitiatingOccupancyOnly when designating -XX:
+CMSInitiatingOccupancyFraction . Otherwise, the JVM attempts to dynamically adjust the value
for -XX:+CMSInitiatingOccupancyFraction. A changing value is undesirable in most production
scenarios. That is because dynamic adjustment is based on statistical analysis that may not
reliably account for load spikes.
GC logging is a good idea for performance tests. The GC log, once enabled, provides
extremely valuable information about the activities in the heap and how they affect the runtime
performance. GC logging tends to have little overhead for disk IO.
Here is an example of how to enable various aspects of GC logging. Add these configurations to
Mule’s wrapper.conf file.
wrapper.java.additional.4=-XX:+PrintGCApplicationStoppedTime
wrapper.java.additional.5=-XX:+PrintGCDetails
wrapper.java.additional.6=-XX:+PrintGCDateStamps
wrapper.java.additional.7=-XX:+PrintTenuringDistribution
wrapper.java.additional.8=-XX:ErrorFile=%MULE_HOME%/logs/err.log
wrapper.java.additional.9=-Xloggc:%MULE_HOME%/logs/gc.log
wrapper.java.additional.10=-XX:+HeapDumpOnOutOfMemoryError