{% extends "_layout.html" %} {% block title %}How Peer Selection Works{% endblock %} {% block content %}
Peer selection within I2P is simply the process of choosing which routers on the network we want our messages to go through (which peers will we ask to join our tunnels). To accomplish this, we keep track of how each peer performs (the peer's "profile") and use that data to estimate how fast they are, how often they will be able to accept our requests, and whether they seem to be overloaded or otherwise unable to perform what they agree to reliably.
Each peer has a set of data points collected about them, including statistics about how long it takes for them to reply to a network database query, how often their tunnels fail, and how many new peers they are able to introduce us to, as well as simple data points such as when we last heard from them or when the last communication error occurred. The specific data points gathered can be found in the code
Currently, there is no 'ejection' strategy to get rid of the profiles for peers that are no longer active (or when the network consists of thousands of peers, to get rid of peers that are performing poorly). However, the size of each profile is fairly small, and is unrelated to how much data is collected about the peer, so that a router can keep a few thousand active peer profiles before the overhead becomes a serious concern. Once it becomes necessary, we can simply compact the poorly performing profiles (keeping only the most basic data) and maintain hundreds of thousands of profiles in memory. Beyond that size, we can simply eject the peers (e.g. keeping the best 100,000).
The actual in-memory size of a peer profile should be analyzed, and unused portions should be removed. This is a good topic for further research and optimization.
While the profiles themselves can be considered a summary of a peer's performance, to allow for effective peer selection we break each summary down into four simple values, representing the peer's speed, its capacity, how well integrated into the network it is, and whether it is failing.
The speed calculation (as implemented here) simply goes through the profile and estimates how many round trip messages we can send through the peer in a minute. For this estimate it just looks at past performance, weighing more recent data more heavily, and extrapolates it for the future.
The capacity calculation (as implemented here) simply goes through the profile and estimates how many tunnels we think the peer would agree to participate in over the next hour. For this estimate it looks at how many the peer has agreed to lately, how many the peer rejected, and how many of the agreed to tunnels failed, and extrapolates the data. In addition, it includes a 'growth factor' (when the peer isn't failing or rejecting requests) so that we will keep trying to push their limits.
The integration calculation (as implemented here) is important only for the network database (and in turn, only when trying to focus the 'exploration' of the network to detect and heal splits). At the moment it is not used for anything though, as the detection code is not necessary for generally well connected networks. In any case, the calculation itself simply tracks how many times the peer is able to tell us about a peer we didn't know (or updated data for a peer we did know).
In upcoming releases, the integration calculation will be used, combined with other measurements of a peer's connectivity and reliability, to determine suitablility for use as a floodfill router in the network database. By determining whether a peer is actually a useful floodfill router (rather than just claiming to be), intelligent decisions can be made about whether to send database queries and stores to that peer. Also, high-capacity non-floodfill routers can analyze the number of floodfill peers in the network and join the floodfill router pool if insufficient floodfill peers are present, thus eliminating a major weakness in today's floodfill scheme.
The failing calculation (as implemented here) keeps track of a few data points and determines whether the peer is overloaded or is unable to honor its agreements. When a peer is marked as failing, it will be avoided whenever possible.
As mentioned above, we drill through each peer's profile to come up with a few key calculations, and based upon those, we organize each peer into five groups - fast, capable, well integrated, not failing, and failing. When the router wants to build a tunnel, it looks for fast peers, while when it wants to test peers it simply choses capable ones. Within each of these groups however, the peer selected is random so that we balance the load (and risk) across peers as well as to prevent some simple attacks.
The groupings are not mutually exclusive, nor are they unrelated: