-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Unrecoverable OOMKill during stream/consumer recovery on startup [v2.10.20] #5929
Comments
Do you properly set GOMEMLIMIT? |
Hi @derekcollison , yes, we've tried setting What's not clear to me is how to reproduce this crash condition and make NATs having to recover from such large message block. My team is still trying to find a deterministic way. |
I checked the profile with a 2.10.20 using Based on the errors in the banner and the profile, it looks like the server was trying to some of the message blocks but for some of them, that returned an error saying that they were not found, so that triggered a rebuild of the state. The memory profile shows that the server is preparing a slice of ~470MB to read a file based on the size indicated by the file stats:
This is really suspicious since by default message blocks are rather small (around 5MB). If you could check the |
The 476.24MB on the We still shouldn't be hitting that I wonder if we are loading in blocks more quickly than they are being expired in this case, or if we should be recycling the blocks more aggressively but aren't. |
I tried to fill a server with millions of 300 bytes messages and removed the index.db to cause a full restore. When doing the |
Sorry, we have cleared up the persistent storage to fix the cluster so that we can continue with other parts of testing. We are trying to reproduce the issue again so we can provide more information. Will post it here ASAP. |
@neilalexander But those buffers are put back into a sync.Pool, so we don't have really a control on how many and how long do they stay in the pool. Maybe we need to limit the size of a slice than can be put back into the pool? |
@kozlovic : my team have reproduced the issue and we have a snapshot of jetstream data volume available. Looking at
So I suspect the 540M one might be the source of trouble. If you want I can dump it somewhere to share with you. |
@jzhn can you share the stream config of the |
Stream
Consumer
|
Can you share the tarball of that directory? |
@derekcollison : the tarball will be ~70GB in size. I'm generating it. what's your preferred way to receive this file? |
wormhole or croc |
@derekcollison : i just sent you an URL through email, please take a look and let us know once you finish downloading. Thanks. |
This fixes that condition and also adds in compaction logic once we know the tombstones are no longer relevant. Resolves: #5929 (Why we have large block exceeding maximum block size) Signed-off-by: Derek Collison <[email protected]>
Observed behavior
NATs pod enters CrashLoopBackoff state as it gets OOMKilled immediately after startup.
Debug log shows no useful information. the last line of log mentions that NATs is
starting restore for stream
.GOMEMLIMIT
was set to819MiB
, nats golang process occupied ~1GB memory, reaching container memory limit.(*msgBlock).loadBlock
and(*msgBlock).rebuildStateLocked
both takes ~45% total memoryExpected behavior
NATs is able to recover stream and consumers on startup within the
GOMEMLIMIT
.Server and client version
nats:2.10.20-alpine
1.2.4
Host environment
m7i.2xlarge
)1Gi
GOMEMLIMIT: 819MiB
(roughly 80% of container memory limit)Steps to reproduce
Notes
2.10.18
and2.10.20
pprof memory dump
Since the nats process gets killed immediately after startup, it takes many attempts to capture the memory dump from
curl -o mem.pprof http://localhost:65432/debug/pprof/allocs
. Given that this memory dump uses pretty much the entire memory limit, it should represent the state just before OOMKill.mem.pprof.zip
The text was updated successfully, but these errors were encountered: