Library that helps to limit memory consumption of your Go service.
As of Go 1.18, all applications written in Go are leaking memory and will be eventually stopped by OOM killer. The memory leak is because Go runtime knows nothing about the limitations imposed on the process by the operating system (for instance, using cgroups). However, an emergency termination of a process is highly undesirable, as it can lead to data integrity violation, distributed transaction crashes, cache resetting, and even cascading service failure. Therefore, services should degrade gracefully instead of immediate stop due to SIGKILL.
A universal solution for programming languages with automatic memory management comprises two parts:
- Garbage collection intensification. The more often GC starts, the more garbage will be collected, the fewer new physical memory allocations we have to make for the service’s business logic.
- Request throttling. By suppressing some of the incoming requests, we implement the backpressure: the middleware simply cuts off part of the load coming from the client in order to avoid too many memory allocations.
MemLimiter represents a memory budget automated control system that helps to keep the memory consumption of a Go service within a predefined limit.
The core of the MemLimiter is a special object quite similar to P-controller, but with certain specifics (more on that below). Memory budget utilization value acts as an input signal for the controller. We define the
-
$NextGC$ (from here) is a target size for heap, upon reaching which the Go runtime will launch the GC next time; -
$RSS_{limit}$ is a hard limit for service's physical memory (RSS) consumption (so that exceeding this limit will highly likely result in OOM); -
$CGO$ is a total size of heap allocations made beyondCgoborders (withinC/C++/.... libraries).
A few notes about Cgo, you need to figure out how much memory is allocated “on the other side”– otherwise MemLimiter won’t be able to save your service from OOM.
If the service doesn't use Cgo, the
The controller converts the input signal into the control signal according to the following formula:
This is not an ordinary definition for a proportional component of the PID-controller, but still the direct proportionality is preserved: the closer the
You can adjust the proportional component control signal strength using a coefficient
The control signal is always saturated to prevent extremal values:
Finally we convert the dimensionless quantity debug.SetGCPercent) and