Skip to content
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

Explicitly set FD limit #545

Closed
ikavgo opened this issue Feb 17, 2022 · 19 comments
Closed

Explicitly set FD limit #545

ikavgo opened this issue Feb 17, 2022 · 19 comments

Comments

@ikavgo
Copy link

ikavgo commented Feb 17, 2022

Currently we don't set any FD limit, which means we are at mercy of host default settings which means Rabbit can OOM.

Please see here for the context: rabbitmq/cluster-operator#959

What has to be done: Something like CMD ulimit -n 1024 has to be added.

Happy to PR myself. Let me know

@michaelklishin
Copy link
Collaborator

1024 is unusable for a distributed data service that often has to sustain a lot of connections. 50K would be my recommended default. Our Production Checklist recommends basing this value on real world metrics but images such as this one cannot follow that route, of course.

@ikavgo
Copy link
Author

ikavgo commented Feb 17, 2022

Thank you @michaelklishin!

@ikavgo
Copy link
Author

ikavgo commented Feb 17, 2022 via email

@tianon
Copy link
Member

tianon commented Feb 17, 2022

I think Docker defaults to infinity on the daemon (https://github.com/moby/moby/blob/32e5fe5099d2806df489feb3e15d8e3e6eca73c1/contrib/init/systemd/docker.service#L31), and the limit I get inside a container on my local system isn't quite infinity, but it's still a very high 1048576.

Unfortunately, if we're set to something lower than we want, there's not really much we can do inside the container (besides including a warning in the container logs):

$ docker run -it --rm --ulimit nofile=1024:1024 bash
bash-5.1# ulimit -n 1048576
bash: ulimit: open files: cannot modify limit: Operation not permitted

@ikavgo
Copy link
Author

ikavgo commented Feb 18, 2022 via email

@ikavgo
Copy link
Author

ikavgo commented Feb 18, 2022

overriding ERL_MAX_PORTS env var also works. Should we still aim for sane defaults in the Dockerfiles?

@tianon
Copy link
Member

tianon commented Feb 18, 2022

I see your are not using rabbitmq image. The ulimit call work for rabbitmq

I'm not sure why it would be any different? This is part of the sandboxing that Docker provides: 😕

$ docker pull rabbitmq
Using default tag: latest
latest: Pulling from library/rabbitmq
Digest: sha256:3d4c70ec5fc84c27efaeb56c50aafcac4fd8583b61398cc028e4876f84ae73d8
Status: Image is up to date for rabbitmq:latest
docker.io/library/rabbitmq:latest

$ docker run -it --rm --ulimit nofile=1024:1024 rabbitmq bash
root@f41cafc78bb2:/# ulimit -n 1048576
bash: ulimit: open files: cannot modify limit: Operation not permitted

Should we still aim for sane defaults in the Dockerfiles?

Yes, absolutely, although I'm still not sure I understand what useful changes we could actually make here (since we can't control the ulimit settings from within the image). 😞

@ikavgo
Copy link
Author

ikavgo commented Feb 18, 2022

[dead@arch eventing-rabbitmq]$ docker run -it rabbitmq bash
root@99778c756269:/# ulimit -Hn
1048576
root@99778c756269:/# ulimit -n 1024
root@99778c756269:/# ulimit -Hn
1024
root@99778c756269:/# 

:-)

(since we can't control the ulimit settings from within the image).

we still can control what portion erlang consumes via ERL_MAX_PORTS

@tianon
Copy link
Member

tianon commented Feb 18, 2022

Yes, you can go down, but you cannot go up. 😅 (And the issue here is an environment where the default is too low, right?)

I'm not so sure about adding more shell code to set ERL_MAX_PORTS automatically (nor would I feel comfortable with my own calculations for what to set that to without some kind of "official" guidance 😅).
It seems like a lot for what's essentially a band-aid for a misconfigured host environment. 🙈

@ikavgo
Copy link
Author

ikavgo commented Feb 18, 2022

(And the issue here is an environment where the default is too low, right?)

nope, the issue here was an environment with fd max set to 11billion something

@michaelklishin
Copy link
Collaborator

@tianon modern Linux default for file handle limit was last good in 1998, as you know. We should use something at least in the 8K range. Our recommendation to most users is 50K+.

Setting ERL_MAX_PORTS sounds like an acceptable amount of work, especially given how many "non-environment" things env variables were used for in the past. This is an example of a true environment setting we'd offer a sane default for.

@tianon
Copy link
Member

tianon commented Mar 23, 2022

As far as I can find looking through RabbitMQ and Erlang source code to try and understand what's the issue here (and how these things are interacting), the relevant bit of RabbitMQ source code is probably https://github.com/rabbitmq/rabbitmq-server/blob/7abf749a60458aba9d6c9e6bdec1d3b0b2254007/deps/rabbit_common/src/file_handle_cache.erl#L1543-L1564 ?

That max_fds value being queried there is ulimit -n, even if ERL_MAX_PORTS is set (on Linux).

On Linux, ERL_MAX_PORTS defaults to 65,536 (in Erlang itself - on Windows, the default limit is a bit lower, but rabbitmq-env.bat sets it to 65,536 if it isn't set explicitly).

So, if ulimit -n is too high (as reported in this issue), I don't see where/how setting ERL_MAX_PORTS would fix it, and I feel like I have to be missing something important. Have we verified that setting ERL_MAX_PORTS explicitly does indeed fix the reported issue?

As far as a fix, I think the best we could do here is something in the entrypoint script (or maybe even in the rabbitmq-server or rabbitmq-env.sh scripts upstream?) that detects if ulimit -n is some fairly arbitrary "too high" value and tries to set it lower? We can't set a default or even a recommended value in the container image -- the best we can do is try to lower it at runtime if it's too high and anything else we have to assume will likely fail with the possibility that even trying to lower it fails (thus ulimit -n xxx || : to make sure we ignore failure). The alternative is to document that setting something like --ulimit nofile=65536 is recommended, but that doesn't work for Kubernetes, as noted above (kubernetes/kubernetes#3595).

(Another trick is that different versions of ulimit disagree on some of the flag names, but I think -n is reasonably consistent, at least between coreutils and BusyBox.)

@lukebakken
Copy link
Collaborator

lukebakken commented Aug 23, 2022

Have we verified that setting ERL_MAX_PORTS explicitly does indeed fix the reported issue?

Yes, see this discussion:

rabbitmq/erlang-rpm#104 (comment)

On Linux, ERL_MAX_PORTS defaults to 65,536 (in Erlang itself - on Windows, the default limit is a bit lower, but rabbitmq-env.bat sets it to 65,536 if it isn't set explicitly).

In both environments, the Erlang VM determines the max number of file descriptors available to it and uses that value. I can't exactly determine how at this time but that's the behavior we see. Grep the erlang/otp source for max_fds.

@tianon
Copy link
Member

tianon commented Aug 23, 2022

Ahh, Red Hat is the missing piece of the puzzle here (https://access.redhat.com/solutions/1479623 was specifically enlightening, especially the bits about RHEL 9). I spun up an Alma Linux machine and was finally able to reproduce.

On my Debian system, I cannot increase the nofile limit above 1048576 (no matter what I do, I get "operation not permitted"). On my new Alma Linux 9 VM, my containers are defaulting to 1073741816 and I can reproduce the OOM as described. 🎉

I've now also verified that either of --ulimit nofile=65536 or --env ERL_MAX_PORTS=65536 fix the OOM appropriately.

Given that this is exhibiting outside containers too, I wonder if maybe this is something that scripts/rabbitmq-server should handle in RabbitMQ itself? Are there use cases where huge nofile limits not only work but are desirable? (Would it be reasonable to require those users to set ERL_MAX_PORTS explicitly? Would they be already doing so?)

This is roughly the sort of implementation I had in mind, but it doesn't feel like docker-entrypoint.sh is necessarily the most appropriate place for it (or something like it): 😅

if [ -z "${ERL_MAX_PORTS:-}" ] && nofile="$(ulimit -n)" && [ "$nofile" -gt 65536 ]; then
    export ERL_MAX_PORTS=65536
fi

Should this maybe also consider the amount of memory the system has? Other system load? It feels like it's tough to come up with something generic here that isn't going to unexpectedly break large users who have been up until now perfectly happy with RabbitMQ using an enormous amount of RAM (and have configured it to do so on purpose). Perhaps it would be better/safer to test for 1073741816 explicitly and only handle that known-pathological case specially?

(Would love to hear your thoughts, @michaelklishin ❤️)

@michaelklishin
Copy link
Collaborator

I'd go with --env ERL_MAX_PORTS=65536 by default. My gut feeling is that overriding any ulimit would be difficult for the user but overriding an env variable should be straightforward.

We have discovered the same thing in rabbitmq/erlang-rpm#104: on CentOS Stream 9, the default file descriptor limit is dramatically higher, which is generally a good thing but in Erlang's case, increases initial memory allocation significantly.

@michaelklishin
Copy link
Collaborator

Testing for 1073741816 sounds good to me. A default of 65K or 100K should be fine. Several VMware products have been using comparable values for years and I don't recall it being an issue.

We should put a visible warning into release notes, too.

@lukebakken
Copy link
Collaborator

Given that this is exhibiting outside containers too, I wonder if maybe this is something that scripts/rabbitmq-server should handle in RabbitMQ itself?

This is a good point. @michaelklishin we should consider handling this in rabbitmq-server (cc @dumbbell)

@lukebakken
Copy link
Collaborator

See the linked PR for a starting point. I believe we can close the issue here.

@tianon
Copy link
Member

tianon commented Aug 30, 2022

Nice, sounds good; thanks! 👍

Closing in favor of rabbitmq/rabbitmq-server#5684 🤘

@tianon tianon closed this as completed Aug 30, 2022
mergify bot pushed a commit to rabbitmq/rabbitmq-server that referenced this issue Aug 31, 2022
mergify bot pushed a commit to rabbitmq/rabbitmq-server that referenced this issue Aug 31, 2022
…dows

See discussion here: docker-library/rabbitmq#545

(cherry picked from commit 28d6b19)
(cherry picked from commit a36657b)
mergify bot pushed a commit to rabbitmq/rabbitmq-server that referenced this issue Aug 31, 2022
…dows

See discussion here: docker-library/rabbitmq#545

(cherry picked from commit 28d6b19)
(cherry picked from commit a36657b)
(cherry picked from commit fa687d1)
t-lo added a commit to t-lo/Docker-DocumentServer that referenced this issue Sep 12, 2022
This change works around an issue in the rabbitmq-server version shipped
with Ubuntu 20.04. Large emptyfiles limits in docker
containers which run on hosts with low emptyfiles limits cause rabbitmq
to break. It will use use 100% CPU of a single core when started, then
time out (i.e. fail to start). An erlang process 'erl_child_setup'
will continue to use 100% CPU even after rabbitmq failed to
start (see docker-library/rabbitmq#545).

The change adds a default emptyfiles limit to rabbitmq-server via
/etc/default/rabbitmq-server, which is created in the Dockerfile before
rabbitmq is installed. The default is generous: 65536.

Additionally, the change ads a new container environment variable
RABBITMQ_EMPTYFILES_LIMIT which, when set, will override the default
above.
openstack-mirroring pushed a commit to openstack/openstack that referenced this issue Sep 12, 2022
* Update kolla-ansible from branch 'master'
  to 1b74b18c2eb4eff7c38e010965aa34f2a353c4c5
  - Merge "Add CentOS Stream 9 / Rocky Linux 9 host support"
  - Add CentOS Stream 9 / Rocky Linux 9 host support
    
    Added c9s jobs are non voting, as agreed on PTG to focus on Rocky Linux 9.
    Since both CS9 and RL9 have higher default fd limit (1073741816 vs
    1048576 in CS8) - lowering that for:
    * RMQ - because Erlang allocates memory based on this (see [1], [2], [3]).
    * MariaDB - because Galera cluster bootstrap failed
    
    Changed openvswitch_db healthcheck, because for unknown reason
    the usual check (using lsof on /run/openvswitch/db.sock) is hanging
    on "Bad file descriptor" (even with privileged: true).
    
    [1]: docker-library/rabbitmq#545
    [2]: rabbitmq/cluster-operator#959 (comment)
    [3]: systemd/systemd@a8b627a
    
    Depends-On: https://review.opendev.org/c/openstack/tenks/+/856296
    Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/856328
    Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/856443
    Needed-By: https://review.opendev.org/c/openstack/kolla/+/836664
    Co-Authored-By: Michał Nasiadka <mnasiadka@gmail.com>
    Change-Id: I3f7b480519aea38c3927bee7fb2c23eea178554d
openstack-mirroring pushed a commit to openstack/kolla-ansible that referenced this issue Sep 12, 2022
Added c9s jobs are non voting, as agreed on PTG to focus on Rocky Linux 9.
Since both CS9 and RL9 have higher default fd limit (1073741816 vs
1048576 in CS8) - lowering that for:
* RMQ - because Erlang allocates memory based on this (see [1], [2], [3]).
* MariaDB - because Galera cluster bootstrap failed

Changed openvswitch_db healthcheck, because for unknown reason
the usual check (using lsof on /run/openvswitch/db.sock) is hanging
on "Bad file descriptor" (even with privileged: true).

[1]: docker-library/rabbitmq#545
[2]: rabbitmq/cluster-operator#959 (comment)
[3]: systemd/systemd@a8b627a

Depends-On: https://review.opendev.org/c/openstack/tenks/+/856296
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/856328
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/856443
Needed-By: https://review.opendev.org/c/openstack/kolla/+/836664
Co-Authored-By: Michał Nasiadka <mnasiadka@gmail.com>
Change-Id: I3f7b480519aea38c3927bee7fb2c23eea178554d
openstack-mirroring pushed a commit to openstack/kolla-ansible that referenced this issue Feb 17, 2023
This is a backport from Zed.

cephadm bits to use package from distro backported from
I30f071865b9b0751f1336414a0ae82571a332530

Added c9s jobs are non voting, as agreed on PTG to focus on Rocky Linux 9.
Since both CS9 and RL9 have higher default fd limit (1073741816 vs
1048576 in CS8) - lowering that for:
* RMQ - because Erlang allocates memory based on this (see [1], [2], [3]).
* MariaDB - because Galera cluster bootstrap failed

Changed openvswitch_db healthcheck, because for unknown reason
the usual check (using lsof on /run/openvswitch/db.sock) is hanging
on "Bad file descriptor" (even with privileged: true).

Added kolla_base_distro_version helper var.

[1]: docker-library/rabbitmq#545
[2]: rabbitmq/cluster-operator#959 (comment)
[3]: systemd/systemd@a8b627a

Depends-On: https://review.opendev.org/c/openstack/ansible-collection-kolla/+/864993
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/864971
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/864973
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/870499

Co-Authored-By: Michał Nasiadka <mnasiadka@gmail.com>
Change-Id: I3f7b480519aea38c3927bee7fb2c23eea178554d
yvanzo added a commit to yvanzo/musicbrainz-docker that referenced this issue Sep 5, 2023
On Linux ERL_MAX_PORTS defaults to 65,536. But the Docker container for
the service `mq` rather uses the host ulimits. When ulimits is infinite,
it can make the container to take a very long time to start while using
a lot of CPU for nothing. It depends on the host settings.

This patch explicitely sets ulimits to 65,536 as recommended for `mq`.

See docker-library/rabbitmq#545 for details.
yvanzo added a commit to metabrainz/musicbrainz-docker that referenced this issue Oct 2, 2023
On Linux ERL_MAX_PORTS defaults to 65,536. But the Docker container for
the service `mq` rather uses the host ulimits. When ulimits is infinite,
it can make the container to take a very long time to start while using
a lot of CPU for nothing. It depends on the host settings.

This patch explicitely sets ulimits to 65,536 as recommended for `mq`.

See docker-library/rabbitmq#545 for details.
danielunderwood pushed a commit to Lidarr/musicbrainz-docker that referenced this issue Oct 24, 2023
On Linux ERL_MAX_PORTS defaults to 65,536. But the Docker container for
the service `mq` rather uses the host ulimits. When ulimits is infinite,
it can make the container to take a very long time to start while using
a lot of CPU for nothing. It depends on the host settings.

This patch explicitely sets ulimits to 65,536 as recommended for `mq`.

See docker-library/rabbitmq#545 for details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants