-
Notifications
You must be signed in to change notification settings - Fork 30k
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
dns: implement light dns caching #49560
Conversation
Review requested:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need a better algorithm for this that avoids concurrent cache misses to trigger multiple dns requests.
a lookup for, say, "constructor" or "toString" results in a cache hit Co-authored-by: Ben Noordhuis <[email protected]>
I think I can implement a locking mechanism that would solve the concurrent cache missing problem. |
I think it should cache the lookup operation. |
cc @jasnell |
I would go for a separate object that tracks all pending requests by hostname (and all other options, to be accurate). This way every time a lookup finishes, all pending request for that host can benefit from the single resolve. I was thinking to something like:
My only concern here is to have an option to disable such feature. If some hosts are configured with DNS Round Robin, caching results (or return a single lookup response for all concurrent lookups request) might interfere with it. |
@mcollina @ShogunPanda I tested the new algorithm against multiple concurrent DNS requests with different websites, and it works just fine. I have written the test script now I am tweaking it so it's by the node guideline. Result for concurrent dns requests: |
Can you also upload the test script? |
@ShogunPanda I don't think there's an Working on the test script right now |
No, I'm talking about having See: https://nodejs.org/dist/latest-v20.x/docs/api/dns.html#dnslookuphostname-options-callback |
5b28d66
to
c32745b
Compare
lib/dns.js
Outdated
function lookup(hostname, options, callback) { | ||
let hints = 0; | ||
let family = 0; | ||
let all = false; | ||
let verbatim = getDefaultVerbatim(); | ||
|
||
const cacheKey = `${hostname}_${family || 'default'}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this (and the code added before the if(!hostname) should move to before const req= new GetAddrInfoReqWrap()
. The hostname variable should be used only after it passes validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache key should probably include if options.all is true or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought if there's a dns key for that domain that means it passed the validation earlier so there was no need for validating the hostname again. I could be wrong though
Also having the all
in dns key makes a lot of sense I will add that.
Good work! I think this would need some additional tests. |
Oh I am sorry I didn't get you earlier, I will make callbacks for all condition. |
@@ -212,8 +245,22 @@ function lookup(hostname, options, callback) { | |||
return {}; | |||
} | |||
|
|||
const cacheKey = `${hostname}_${family || 'default'}`; | |||
const cachedResult = dnsCache[cacheKey]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A read-through cache approach would be a bit simpler here. essentially something like
cache.get(cacheKey, callback, () => {
// If the cache lookup is a miss, this function is called to do the lookup and cache the result of the lookup.
});
This commit replaces the timer based approach for purging the expired dns cache with lazy cleanup approach. The DNS cache is now cleaned before adding a new DNS entry and before performing a lookup. This change simplifies the code and eliminates the need for a separate cleanup timer.
49c4df3
to
090a1a0
Compare
lib/dns.js
Outdated
const currentTime = DateNow(); | ||
for (const key in dnsCache) { | ||
if (currentTime - dnsCache[key].timestamp >= 1000) { | ||
delete dnsCache[key]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing dnsCache
to a Map
could be a better/faster structure to use in this case, delete
is usually slow.
Refs:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to keep the object rather than a Map
, just do a dnsCache[key] = undefined
.
Any chance of this landing before V21? We have had to build our own version of DNS caching to solve this. It heavily impacts the scaleability of our system. |
I am sorry for the inconvenience, I will try my best to close this issue within this week. |
No worries, if this can't land in Node v21.0.0 as semver-major, we can modify it to be under a flag and therefore include it in v21.x.0 as semver-minor. |
That would be great to be under a flag and shipped in V20 👍 @ShogunPanda Not sure if you got your versions miss written but V20.9 would be awesome to land this in 😉 |
test/parallel/test-dns-set-default-order, test-dns-default-verbatim-false, test-dns-default-verbatim-true is failing because The only way to pass the test is by changing the test Rest of the tests are passing. |
Cache DNS results very lightly in node. Strawman: Cache for 1 second, refresh in the background, and delete cache after 1 second.
Fixes: #49394