Vladimir Dyuzhev, author of MockMotor

Vladimir Dyuzhev
MockMotor Creator

Best GC for MockMotor

To have stable RT with MockMotor, use ZGC, but don't use Generational ZGC

Unstable RT, but Why?

While running a high-volume test that simulated a few GraphQL backends, we noticed that the response time (RT) fluctuates every few minutes. Despite the configured RT being 500ms, a pack of responses was occasionally coming back in 3 or even 5s.

That was unacceptable.

I noticed that the CPU usage during those unfortunate moments was reaching 1/16 of CPU capacity, i.e. exactly one CPU. Clearly, the execution of one thread was blocking the whole JVM.

Desperately Looking for MockMotor Issues

I spent two weeks checking and eliminating possible bottlenecks in the MockMotor code.

I found some legitimate performance issues and fixed them. The overall performance was not improving, though.

I had to look at the JVM itself. And then it dawned on me - the garbage collector!

The default GC for OpenJDK 17 is G1. Not a bad collector, but the MockMotor’s usage pattern appears too much for it. The mock scripts created too many small objects, and G1 couldn’t keep up.

ZGC Saves the Day

On a hunch, I switched the MockMotor JVMs to ZGC.

And what a miracle! The RT suddenly became stable.

ZGC uses hardware bits to achieve a high concurrency in collecting unused objects without the necessity to stop the whole JVM.

ZGC is Now the Default for MockMotor

In alignment with MockMotor’s general principle, “don’t make me think,” if the admin didn’t specify the GC in the JVM options, MockMotor silently selects ZGC.

But Beware of Generational ZGC

I also tried the new incarnation of ZGC, which is available in Java 21 - Generational ZGC. And the supposedly newer and better version of ZGC reverted to the unstable RT that G1GC exhibited!

Oh well. That GC is too early for PROD usage, methinks.