-
Notifications
You must be signed in to change notification settings - Fork 550
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
UVTimer leaks #37
Comments
Would it be possible for you to share the program code, or to reduce it to a smaller size that can be shared? I'd suggest to build a debug version of uvloop with async def print_debug(loop):
while True:
print(chr(27) + "[2J") # clear screen
loop.print_debug_info()
await asyncio.sleep(0.5, loop=loop) to create an asyncio task -- |
Also, how exactly do you use Gunicorn with uvloop? Do you use aiohttp? Do you use the worker from aio-libs/aiohttp#878? |
Hello, Unfortunately I can't share the program code in this instance as it contains trade secrets. We have a "scoreboard" facility (like Apache) -- would it be possible to get the text from We used the UVLoop provides a significant CPU usage reduction over the default loop, so we are very eager to help in whatever way we can. Of note is that we haven't ported the application to Python 3.5 |
Based on what I see here: https://github.com/MagicStack/uvloop/blob/master/uvloop/loop.pyx#L832-L918 it will need to be modified, but no worries, we can do that modification and send it as a pull request. |
NP. Can you tell me more about the app though? What modules does it use; for instance, do you use some async driver for memcache/redis/database/etc? Also, can you try to create a simple version of your app that still has the leak? It might help us to understand what's going on here. |
We use a custom asyncio driver for Aerospike, code available at http://github.com/kaniini/aerospike-py as well as aioredis. We also use an async client to talk to the BIRD BGP routing daemon (but this is being replaced for various reasons, and has been determined not responsible for the leak). Other than that, it is a pretty simple aiohttp.web application. |
And, just to confirm, you can see the leak only when you're running the app behind Gunicorn? |
We haven't really bothered to test outside of Gunicorn as we use Gunicorn to manage our workers -- retooling to use aiohttp directly (even though the aiohttp worker basically replaces the entirety of Gunicorn's actual web serving infrastructure) is not something we're eager to do right now. I will add the loop debug info to the scoreboard tomorrow and post some stats. |
Hello, So we have added uvloop debugging to the scoreboard module, and I wonder if there is an issue with the way callback handles are being cleaned up, because the "total callback handles" number is going up at a rate that is proportional to the memory increase. TCPTransport and UVTimer objects are the most heavily used, which is unsurprising. An interesting note is that the Read callbacks number is much smaller than the total callback handles number. |
But the "current" number of callbacks is still low (not steadily increasing?) Please try to remove
It's a different kind of callbacks -- "read callbacks" is the number of times libuv reads something from the socket and sends it back to uvloop. |
How many |
Hello, Yes, the current number of callbacks is low. Here is one of the UVHandles dumps from a worker, which should answer the other questions:
I will make the requested modifications shortly, and report back. |
Hello, I applied the modifications and now it is leaking heavily. Roughly 1MB per second per worker. |
Seems the leak rate is now slowing down on the modified server, so I will monitor for a bit more and give an update. |
I think it's UVTimer.
|
Right now what I am seeing is heavy CPU use (probably due to GC pressure), and a much slower leak rate, but it is still leaking a little: an asyncio default event loop worker started at the same time with the same load is using about 210mb RSS, while the uvloop is using about 250mb. I agree that it may be UVTimer, do you want me to put the freelists back for the non-timer case? |
It's definitely UVTimer. I wrote a small program that creates thousands of them, and it's leaking super fast. I don't think it's related to freelists... |
Awesome! Is there anything I can do on my end to help with getting a fix going? I'm unfortunately not very familiar with libuv internals, but if it is a bug on their side I may be able to help fix it. |
No, it's a uvloop bug. Somehow UVTimers do not free memory of their uv_timer_t handles. Looking into that now. I also have a refactoring branch where I remove most of |
If you can make that branch public, I'm more than happy to deploy it and give it a go. |
This should fix a memory leak discovered in [1]. It will also make everything slightly faster. [1] #37
Pushed to the master branch. Please test. |
Looks good so far, will run it for 24 hours and see where it's at. Thanks! |
Thanks a lot for discovering this and for your help with debug. I'll release a new version of uvloop shortly, as the bug is pretty severe; perhaps it affected other handles, such as Poll or TCP. |
3 hours later and no leak, I think we can call this one done. Will deploy uvloop 0.4.33 to all workers, thanks so much! |
Awesome! Thanks! |
BTW, did you guys do any benchmarking of your app? How much faster is it when it's run on uvloop? |
The main advantage for the app (a real-time ad server DSP/SSP engine) in question is that UVLoop provides more stable latencies (due to more performant socket I/O and polling provided by libuv). CPU is cut by about 30% over baseline, so it is a nice performance improvement there. The key thing though is that latencies are more stable. We have been testing with libuv for about a month now and finally had diagnosed uvloop as the only remaining culprit, hince the report :) Each server has 8 workers and processes approximately 6000-12000 requests per second. |
This is a different fix for issue #37. The original fix that removed dynamic memory allocation of uv_handles had to be reverted.
Please try uvloop v0.4.34. I've made several changes to make sure we won't introduce similar memory leaks in the future:
|
we will deploy it on one of our nodes and verify there are no regressions, thanks! |
We've deployed uvloop 0.4.34 and see no regressions in terms of memory leaks. |
Awesome, thanks! |
We are seeing a serious memory leak that only shows up when using UVLoop on Gunicorn. Examining the GC state does not show anything useful, which indicates to me that it is likely inside native code, so I report this here. Under moderate load, we see each Gunicorn worker taking 2GB ram within 18-24 hours.
We are presently retesting under 0.4.32 and will update if we still see it. If you have any suggestions for debugging it that may be helpful, that would be useful too. We only see this leak under UVLoop and not the default asyncio loop, so it has to be related to UVLoop.
The text was updated successfully, but these errors were encountered: