Some field notes on imposing memory resource limits on users on Ubuntu 18.04

September 27, 2019

As I mentioned in my entry on how we implement per-user CPU and memory limits, we have a number of shared general use servers where we've decided we need to impose limits on everyone all of the time so no one person can blow up the machine. Over the course of doing this, we've built up some practical experience and discovered a surprise or two.

As discussed, we impose our memory limits by setting systemd's MemoryLimit. In theory perhaps we should use MemoryMax, but for two issues. First, our scripts still need to work on Ubuntu 16.04, where MemoryMax isn't supported. Second, it's not clear if systemd makes this work if you're not using unified cgroups (cgroup v2), and the Ubuntu 18.04 default is to use the original v1 cgroups instead of the new cgroups. Since my impression is that there are still assorted issues with v2 cgroups, we're not inclined to switch away from the Ubuntu default here.

As documented, systemd's MemoryLimit sets the memory.limit_in_bytes cgroup attribute, which is sort of documented in the kernel's memory.txt. The important thing to know, which is only implicitly discussed in memory.txt, is that this only limits the amount of RAM that you can use, not the amount of swap space. In the Ubuntu 18.04 configuration of cgroup v1, there is simply no way to limit swap space usage, and on top of that systemd doesn't expose the property that you'd need.

Our experience is that this doesn't seem to matter for processes that use a lot of memory very rapidly; they run into their user's MemoryLimit almost immediately without causing swap thrashing and get killed by the cgroups OOM killer. However, processes that slowly grow in memory usage over time will wind up pushing things out to swap, themselves included, and as a result their actual memory usage can significantly exceed your MemoryLimit setting if you have enough swap. So far, we haven't experienced swap thrashing as a result of this, but I suspect that it's possible. Obviously, how much swap space you have strongly affects how much total memory a user can use before the cgroups OOM killer triggers. All of this can make your memory limit much more generous than you expect.

(We normally don't configure much swap on our servers, but a few have several gigabytes of it for various reasons. And even with only one GB of swap, that might be close to a GB more of 'memory' usage than you may have expected.)

PS: I was going to say that fast-growing processes don't seem to swap much, but our Prometheus system stats suggest that that's wrong and we do see significant and rapid swap usage. Since much of our swap is on SSDs these days, I suppose that I shouldn't be too impressed with how fast our systems can write it out; a GB or three over a minute is not all that fast in today's world, and SSDs are very good at random IO.

Sidebar: What I expect us to set with systemd v2 cgroups

If Ubuntu switches to v2 cgroups by default, I currently think we'd set a per-user MemorySwapMax that was at most a GB or half our swap space, whichever was smaller, make our current MemoryLimit be MemoryMax, and set MemoryHigh to a value a GB or so lower than MemoryMax. The thing I'm least certain about is what we'd want to set the swap limit to.

Written on 27 September 2019.
« A file permissions and general deployment annoyance with Certbot
Understanding when to use and not use the -F option for flock(1) »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Sep 27 22:34:45 2019
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.