-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
OOM kill on a small system with workqueue consumers at high speed resulting in fast memory growth - #5673
Comments
Will experiment with |
For controlling the memory and preventing such OOMs with high load on insufficient resources, you should use |
GOMEMLIMIT solves the immediate problem (I tried from 256MiB to 1024Mib), but the memory usage reported by the OS still vastly exceeds the limit I set. Also: I would expect the nats-server to self-limit to a reasonable memory footprint. My test system had 2.5GB of 4GB available for NATS when the tests starts |
I now created a state of the stream, where nats-server exceeds all limits during startup, recovering the stream and gets killed. |
Can you get a memory profile when the memory usage is inflated, either through |
Short of using We would need to figure out from profiles what is using the memory and whether that can be optimised for this case. |
Here are the memory profiles: Observations:
|
OOI how did you capture these profiles? They're in text rather than binary format which means the pprof visualiser can't parse them. Please make sure to use |
Human readable output via:
|
Testing under Windows now, as the memory growth happens here as well. (just no OOM kill) Binary Allocs: The more I look into the behavior the less deterministic it is. Under Windows is respected: Server shrinks back to the set size. BUT under Linux it didnt. In any case, memory temporarily growth to about the amount consumed during 10seconds by the consumers. Seems the buffer management relies on: https://pkg.go.dev/sync#Pool |
The In this case, looking at the profile, it appears as though lots of blocks are being loaded in from the filestore and held in the block cache. They should be held there for 10 seconds from the last access, after which the buffer will be returned to the pool. That would roughly explain why you see the correlation between the data accessed and the memory growth in that window. Perhaps exposing the cache expiry as a configurable, i.e. being able to set it to less than 10 seconds, would help reduce memory usage at the expense of potentially more I/O operations. As an experiment, you could potentially test with a custom build that changes |
Correct! If the behavior of the block cache would be documented (I can guess it exists, but I incorrectly assumed it to be of fixed size per connection) and its size or timeout configurable I would not have been surprised. Last post on observed behavior:
It does not happen:
In summary:
|
I will test with : DefaultCacheBufferExpiration in filestore.go to a lower value like time.Second * 2. |
Reducing the buffer timeout to 1s limits the memory consumption to around 600MB in my tests. At teh cost of reduced throughput, which is fine (still about 50MB/s from a workqueue) Tested with DefaultCacheBufferExpiration = time.Second * 1 |
Closing the investigation, but I would like the CacheBuffer configurable as a small enhancement request. |
If you could file an issue that would be great. |
What is the stream maxBytes that you were using? @roeschter |
I was not using maxbytes (unlimited). The effect is purely about the speed of consuming. |
Closing this in favor of a new CR - #5740 |
Observed behavior
Consuming from a workqueue with multiple consumers (subject segmented) at high speed (150MB/s) result in rapid memory growth and eventually exhaustion. Server will die with a range of symptoms, mostly silently OOM killed, sometimes throwing readloop processing time warning first.
Testing on a small system with 4Gb and 2 CPUs - This is deliberate to simulate an edge node.
This does not seem to be a memory leak per se. Repeated tests with a below threshold message volume do not trigger the effect.
Expected behavior
Self limits memory growth or throughput.
Server and client version
jnats-2.19.1.jar _ Java17
2.10.17 and 2.11-preview-rc3 (self compiled)
memory growth is not platform specific. Seen on Windows as well, but crashes observed only on smaller systems with <8GB.
Host environment
Linux - Old Kernel
Linux lvps5-35-240-105.dedicated.hosteurope.de 3.10.0-1160.80.1.vz7.191.4 #1 SMP Thu Dec 15 20:31:06 MSK 2022 x86_64 x86_64 x86_64 GNU/Linux
Steps to reproduce
playground.jar.zip
nats00_hosteurope.config.txt
source.zip
Full eclipse project available in private repo: https://github.com/roeschter/natsPlayground
Run on a system with 4GB (or less) - CPU count >=2
Java 17
/var/lib/java17/bin/java -cp playground.jar:jnats-2.19.1.jar com.synadia.test.config03_performance.C03JetstreamWorQueueSlowDeletes --user user --password dja673b48fh3kqp9 --messages 200000 --messageSize 10000 --fetchsize 10 --subjects 10 --consumemode fetch
--messages 200000 Should be sufficient on a 4GB system. Increase to 1000000 if not crashing.
--messageSize 10000 Increasing message size my speed the crash up. Not observable with small messages (throughput too low I presume)
Memory should increase rapidly when the consumers start. Rate should be 10000 msg/s or more
The text was updated successfully, but these errors were encountered: