Have you actually done this yourself for Go programs that you've deployed into production? If so, what were the circumstances? Was it your solution to latency spikes?
Have you actually done this yourself for Go programs that you've deployed into production? If so, what were the circumstances? Was it your solution to latency spikes?
Java is an example of the most widely deployed garbage-collected language in production around the world, deployment number and scale-wise. Most of the world's missing critical systems today run on Java. Java can run as a process or in a container. Containerised Java deployments do not require unique operational SRE arrangements, nor do they require any unique/dedicated permissions to run in a container.
Upon start-up, the JVM checks whether the system has sufficient memory to satisfy the max heap size constraint, and it will duly fail to start up if not. Afterwards, the JVM will allocate the required amount of memory, and it will mlock it. Multi-terabyte[0] RAM JVM deployments[1] do exist and exhibit exactly the same behaviour. Java has had such behaviour since its inception.
The prevailing number of Java deployments run on systems with swap enabled, and, from the operational standpoint, it is pure insanity to run mission critical (banking, payments, government etc) apps without a swap. Swapless JVM deployments are virtually unknown or are operational negligence.
The principal exceptions for running a JVM on a system without a swap are hard real-time scenarios and embedded systems. That is it.
What makes Go different or unique that it can't use mlock and that it would require special permissions or unique/distinct SRE/operational arrangements? It is eluding me.
[0] The Azul JVM supports up to 20 Tb of RAM which it will mlock.
[1] See the published Azul/Forrester evidence for reference. It is an interesting read regardless of the mlock debate.
Java is generally simpler to run without swap since you know in advance how large the heap can be, so it's just a small amount of variability in the jvm internals to consider.
You don't want swap of heap/stack, or paged out code pages. The latency hit is pretty bad even for non-"real"-time systems. And really, you should know how much memory you are going to use (to within some fair bounds).
Adding only a small amount of swap for very cold pages does not save very much ram. And using it for anything else is very bad for interactive systems. In the same vein paging out code pages you won't ever run just does not save very much.
It requires some discipline in monitoring, load testing, etc, but you should be doing that anyway.
The alternative (which I’ve also done), is to put the binary in tmpfs, after making sure it’s not bloated.
Or did someone else do this work and you assumed it was effective? Or did you personally implement this change and then validate that the before/after metrics improved as a result?
The impact is pretty obvious.
Just seems kinda weird to give advice on forums when you're not speaking from actual relevant experience. I'm getting meat proxy answers and confident replies from people who've never done what they're suggesting others do.
I ultimately change the runtime environment to no longer allow any local durable storage for job (with a handful of exceptions), including swap and binary staging. The fact that almost everything was already using mlock made the transition simpler.