-
Notifications
You must be signed in to change notification settings - Fork 60
Limit scope of queries to k closest peers #97
Conversation
There are four places we perform queries:
I think it makes sense to implement this behaviour for the first two, but I'm not sure about findProviders() and getMany(). @jhiesey @vasco-santos @jacobheun I'd like to hear your thoughts. |
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 totally agree on moving in this direction! If the other folks agree, I will have a deeper look to the PR codebase
I think the same logic applies for |
findProviders() and getMany() use disjoint paths whereas getClosestPeers() and findPeer() do not, so I wanted to consider what effect that might have. For example when running getMany(), we first work out the number of disjoint paths, which will be equal to alpha (ie 3). Results are divided among the paths, such that each path can return at most Limiting the scope of the query makes it run faster, because we examine less nodes, but it also makes it less likely that we will discover all possible paths to the values, meaning getMany() is more likely to fail. |
It sounds like this is where properly streaming responses would make it easier to achieve both. Until we add the streaming responses, we'll likely have to have the limits on those two be higher, because that seems likely to fail a lot. The math is not in IPNS's favor. |
Streaming responses should help. For now we could also decrease the required number of values for IPNS to be less than 16. There can only be one source crypto key for IPNS records, which in practice usually means only one source node, so IPNS records will almost always all have the same value for the same key (they would only differ when an IPNS publish hasn't reached all the nodes that a previous IPNS publish reached). I implemented a streaming version of the DHT in this PR: #82. It's waiting on async/await PRs for a few dependencies to be approved. |
c955bc5
to
c59a738
Compare
c59a738
to
57ce00a
Compare
I agree with @dirkmc and starting by targetting After that, once we introduce the stream we figure out what limits we can add to the remaining two. |
I think I've found a reason that the find peer test is often failing. I noticed that by default we limit the number of peers returned from the FIND_NODE RPC to 6, whereas the Kademlia spec (and go-libp2p-kad-dht) specify that it should be KValue (20 by default). This will cause a problem in networks where many nodes have accurate knowledge of the closest peers to a particular key (eg if that key is requested frequently). For example in the following scenario:
This will cause a problem for some DHT operations, for example when doing a PUT to the DHT, this will cause a problem because it needs to store the PUT value on at least KValue (20) nodes. Does anyone know why this limit of 6 was chosen? Here's what the Kademlia spec says:
|
I fixed a bug in the queueing logic, and changed the test so that the topology is more realistic (nodes know about peers close to them), so the tests now pass consistently |
No, and it looks like it's been there since day 1, #1. We should use what's in the spec unless we have clear, documented reasoning for deviating. It looks like the bundlesize is failing, with the added code this is understandable. We should bump https://github.com/libp2p/js-libp2p-kad-dht/blob/v0.14.12/.aegir.js#L2 to |
@dirkmc did you check if in go land, they also use |
While go is following the spec on this item, we really should avoid doing things here based on the go implementation. The go implementation has known issues and regularly references needing to follow the Kademlia spec properly. I think we should focus energy in making sure we're abiding by original Kademlia spec and pushing the libp2p spec for it, libp2p/specs#108, forward, rather than attempting to mimic the go implementation. As long as we're not breaking interop, and we document where and why we're deviating from go (and informing them if they're not aware), I think that's the approach we should be taking. |
I changed the number of closer peers to be returned to K (@vasco-santos the go DHT does use the k value also: https://github.com/libp2p/go-libp2p-kad-dht/blob/master/handlers.go#L23) |
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.
LGTM
@jacobheun do you think we should just enable this for getClosestPeers() and findPeer(), or for all four queries including findProviders() and getMany()? |
Perhaps we should start with It might be valuable to have the logic in One of the current unfortunate things about Maybe it's worth adding findProviders until we can properly support streaming? |
@jacobheun totally agree that we should follow the kademlia spec first and then try to iterate on improving it. In that time, we may check the go implementation looking for possible optimizations they did to the paper. We just need to make this visible for everyone being on the same page. Regarding the 4 functions that perform queries, I think we should do this by steps. I would go with these two now. However, I agree that it would be worth exploring this for |
Thinking about it a bit more, we may need to decide for each case in which we call any of those four functions. For example when doing a DHT PUT we call |
Yes I think that makes sense, I will put together a list |
The paths through the code that create a
|
So For the fetching functions For eventually getting the tolerance back up to a higher level (16), there's discussion about adopting sloppiness at libp2p/specs#163. While it's not the same concept of sloppiness, I was thinking about how being sloppy with the number of writes, combined with eventual accuracy, might be helpful in alleviating some of this. For example, we discussed concerns about spending enough time finding closest peers when performing a |
That's an interesting idea. I wonder in practice how often we won't find the actual closest 20 peers. Maybe it's worth merging this in and trying it out in the real network? |
Yes, I think getting this out so we can test with it and iterate is a good path forward. |
Thanks for the list @dirkmc I liked your proposal @jacobheun I will merge this as it looks good and we need to test it, but I believe we will want to iterate on this. |
Implements libp2p/go-libp2p-kad-dht#290
Stop querying once we have successfully queried >= K peers, and the only remaining peers waiting to be queried are further from the key than those K peers.
I also fixed a bug where we would return peers that we hadn't successfully connected to and refactored the Query class.