-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Conversation
Problem: When creating streams inside of a domain, Domain#dispose() will not clean them up. This patch demonstrates this problem using a test case, and provides a possible fix by also adding implicit domain members to the domain. Considering that I don't understand the design decisions that went into only tracking explicit members at this point, this patch should be considered as a request for comment on the current behavior / to start a discussion on improving it.
In developing domains, I found that adding implicit members was a pretty significant performance hit. Can you try running |
Sorry, that won't do anything. Use this command:
But, running without domains should definitely not cause a performance impact, either :) |
Did some benchmarks: Not using domains:
Domains as in 0.8.0:
Domains as in 0.8.0 + implicit domain member tracking patch:
You're right: There is a significant performance penalty for tracking domain members implicitly. But IMO domains are useless without it. I mean it's cool that I can match exceptions up to my http requests with them, but without being able to clean up, my processes will leak resources. So even with the performance implications, I think domains should track implicit members by default. If there is a use case for domains without explicit member tracking (I don't think there is), we could easily make the behavior configurable on a per-domain basis. Let me know what you think, and I'll finalize this patch to also take care of timers. --fg |
There were two problems with the way domains were used in the benchmark: a) A global domain was created. IMO this is not how one would normally use domains, as an error caught by a global domain would be just as difficult to handle as an 'uncaughtException' one. More importantly: Setting up a global domain makes implicit domain member tracking expensive as per-request domains will now also be tracked as members of the global domain. b) The per-request domains created in the benchmark were never entered. While it didn't have an impact on the performance of the benchmark, it does seem a bit pointless to not enter the domains, so this patch causes them to be entered.
@isaacs Please have a look at my commit above. IMO the benchmark used to determine the impact of domains was flawed, and after fixing it, my patch for adding implicit member tracking no longer causes any performance problems: Fixed benchmark + without implicit member tracking patch:
Fixed benchmark + implicit member tracking patch:
So ... if you agree with my adjustment to the benchmark, what do you think about enabling implicit member tracking by default now? IMO it would make domains much more useful / easier to explain. Let me know and I'll come up with a final set of patches / tests for this. --fg |
@felixge That's fascinating. Let's discuss this in more detail after (or at) nodeconf. The dom.enter() should be mostly unnecessary, but also harmless. The request and response objects are bound to it, so they'll enter during their events. However, it's probably the server's connection event entering the global domain that is the bottleneck, since it's added implicitly to the gdom domain. I think it's clear that we need a better understanding of exactly where it's spending its time. Removing the explicit/implicit disparity would be nice, but we do have to be very careful we don't create performance regression landmines. |
@isaacs the main thing 44a0f74 was fixing was essentially a leak in the benchmark. If you do implicit member tracking, and you have a global domain + domains for each request, the domains for each request will all be added as children to the global domain, and never cleaned up. I remember our discussion at nodeconf where you said the global domain was useful in your scenario (where you'd shut down the process after any domain errors), but IMO the biggest use case I see for domains is keeping long-running connections alive. This means the process cannot be shutdown (to clean up leaks). So from your perspective: What would you like to see to move this forward? You mentioned a more detailed analysis on where time is spend? What about making the implicit member tracking optional, this way you can ignore the performance issues for your use case (having a global domain), and I can get good performance on my use case (not having a global domain) at the same time. |
Hi, Any news on this? I have a similar issue: From what I saw, it's because the underlying socket of the http.request is not destroyed, resulting in a starvation of the sockets pool. Calling Would be great to be able to use domains without worries :). |
Can one of the admins verify this patch? |
This patch is no longer relevant. @trevnorris is in the process of significantly refactoring how domains work in master, and |
Problem: When creating streams inside of a domain, Domain#dispose() will
not clean them up.
This patch demonstrates this problem using a test case, and provides a
possible fix by also adding implicit domain members to the domain.
Considering that I don't understand the design decisions that went into
only tracking explicit members at this point, this patch should be
considered as a request for comment on the current behavior / to start a
discussion on improving it.