-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
memguardian - backpressure #362
Conversation
memguardian/memguardian.go
Outdated
|
||
// Calculate the system absolute ratio of used RAM vs total available (as of now doesn't consider swap) | ||
func UsedRamRatio() (float64, error) { | ||
vms, err := mem.VirtualMemory() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that the virtual memory is the right metric? Virtual memory can be larger than the physical available memory. How about considering the real memory or physical memory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about retrieving directly via OS system call (eg. sysinfo but the gopsutil seems to do already a decent job about obtaining it with standard system tools/files (for example on linux by parsing /proc/meminfo
which according to linux kernel docs represent the avilable effective RAM). Do you think this is correct, or there is any better way on the metrics to monitor (for example swap is actually not considered)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will probably differ per OS:
On MacOS Virtual means something else:
https://apple.stackexchange.com/a/107
Additionally misleading info from gopls:
shirou/gopsutil#119
Windows is probably the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the links, I'll have a closer look and see if it makes sense to implement more specific os calls
I'd also leave this comment here: would it be better if instead of a memguardian there is a simple memory allocation rate limiter? For example if a buffer can be 10MB we can say at most 50 allocations per second regardless of the concurrency settings. This way if templates don't allocate memory they can be very concurrent while memory heavy templates will be less so. The rate limit can be implemented per template or make it global. |
During tests imposing a rate limiting on buffer allocations was leading anyway to OOM kill, just later in time as the rate of threads was anyway piling up. |
I can see how per-template rate limiter will still lead to OOM kill if there are enough concurrent templates. A global rate limiter that is tuned based on the amount of available memory at startup might be a good approach. You're basically doing this by controlling the concurrency with memguardian. Another suggestion is to have a tag for bruteforce templates that we know can take a ton of RAM. Or even a |
Adding
memguardian
component. It's goal is to allow detection of potential OOM kill conditions, and offer the caller the chance to activate mitigation actions to slow down execution.It can be used both as a standalone struct, or activated and controlled via the following environment variables:
In case environment variables are used, the component can be accessed through
memguardian.DefaultMemGuardian
.The warning state (activated when the used RAM exceedes the defined thresholds) offers two approaches to initiate the back-pressure mechanism:
MemGuardianInstance.Warning
The caller should insert in hot-paths reduction factors, or for global settings, either use the callback mechanism or check periodically the state and activate/disable mitigation actions.
Closes #361