Skip to content

Commit

Permalink
make dial ranker configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
sukunrt committed Jun 7, 2023
1 parent 3f5d299 commit 1716e2e
Show file tree
Hide file tree
Showing 9 changed files with 26 additions and 51 deletions.
9 changes: 4 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
## 🔦 Highlights <!-- omit in toc -->

### Smart Dialing <!-- omit in toc -->
* When connecting to a peer we now do dial prioritisation to prefer QUIC addresses over TCP addresses. We dial the QUIC addresses first and wait 250ms to dial the TCP addresses of the peer.
* In our experiments, we've seen little impact on latencies up to 95th percentile. Two new metrics have been added, dial ranking delay and dials per connection to gauge the impact.
* To avoid adversely impacting users in UDP black holed environments, this feature is disabled by default.
* To enable use `libp2p.EnableSmartDialing` option.
* When connecting to a peer we now do [happy eyeballs](https://www.rfc-editor.org/rfc/rfc8305) like dial prioritisation to prefer QUIC addresses over TCP addresses. We dial the QUIC address first and wait 250ms to dial the TCP address of the peer.
* In our experiments we've seen little impact on latencies up to 80th percentile. 90th and 95th percentile latencies are impacted. For details see discussion on the [PR](https://github.com/libp2p/go-libp2p/pull/2260#issuecomment-1528848170).
* For details of the address ranking logic see godoc for `swarm.DefaultDialRanker`.

* To disable smart dialing and keep the old behaviour use the
`libp2p.NoDelayNetworkDialRanker` option.

# [v0.27.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.27.0)

Expand Down
9 changes: 5 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ type Config struct {
DisableMetrics bool
PrometheusRegisterer prometheus.Registerer

SmartDialing bool
SmartDialingCustom bool
DialRanker network.DialRanker
DialRankerCustom bool
}

func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) {
Expand Down Expand Up @@ -176,9 +176,10 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa
if cfg.MultiaddrResolver != nil {
opts = append(opts, swarm.WithMultiaddrResolver(cfg.MultiaddrResolver))
}
if !cfg.SmartDialing {
opts = append(opts, swarm.WithNoDialDelay())
if cfg.DialRanker == nil {
cfg.DialRanker = swarm.NoDelayRanker
}
opts = append(opts, swarm.WithDialRanker(cfg.DialRanker))
if enableMetrics {
opts = append(opts,
swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer))))
Expand Down
10 changes: 5 additions & 5 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ var DefaultPrometheusRegisterer = func(cfg *Config) error {
return cfg.Apply(PrometheusRegisterer(prometheus.DefaultRegisterer))
}

// DefaultSmartDialing configures libp2p to disable smart dialing by default
var DefaultSmartDialing = func(cfg *Config) error {
return cfg.Apply(DisableSmartDialing())
// DefaultDialRanker configures libp2p to disable smart dialing by default
var DefaultDialRanker = func(cfg *Config) error {
return cfg.Apply(DialRanker(nil))
}

// Complete list of default options and when to fallback on them.
Expand Down Expand Up @@ -197,8 +197,8 @@ var defaults = []struct {
opt: DefaultPrometheusRegisterer,
},
{
fallback: func(cfg *Config) bool { return !cfg.SmartDialingCustom },
opt: DefaultSmartDialing,
fallback: func(cfg *Config) bool { return !cfg.DialRankerCustom },
opt: DefaultDialRanker,
},
}

Expand Down
30 changes: 7 additions & 23 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,31 +575,15 @@ func PrometheusRegisterer(reg prometheus.Registerer) Option {
}
}

// EnableSmartDialing configures libp2p to prioritise dials to certain
// addresses for outgoing connection attempts to a peer. This reduces the number
// of dial attempts with little impact to latency. see `swarm.DefaultDialRanker`
// for details of the ranking logic.
// (default: disabled)
func EnableSmartDialing() Option {
return func(cfg *Config) error {
if cfg.SmartDialingCustom {
return errors.New("smart dialing already configured")
}
cfg.SmartDialingCustom = true
cfg.SmartDialing = true
return nil
}
}

// DisableSmartDialing configures libp2p to dial all addresses in parallel
// for outgoing connection attempts to a peer.
func DisableSmartDialing() Option {
// DialRanker configures libp2p to use d as the dial ranker. To enable smart
// dialing use `swarm.DefaultDialRanker`. nil disables smart dialing.
func DialRanker(d network.DialRanker) Option {
return func(cfg *Config) error {
if cfg.SmartDialingCustom {
return errors.New("smart dialing already configured")
if cfg.DialRankerCustom {
return errors.New("dial ranker already configured")
}
cfg.SmartDialingCustom = true
cfg.SmartDialing = false
cfg.DialRanker = d
cfg.DialRankerCustom = true
return nil
}
}
4 changes: 2 additions & 2 deletions p2p/net/swarm/dial_ranker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const (
RelayDelay = 250 * time.Millisecond
)

// noDelayRanker ranks addresses with no delay. This is useful for simultaneous connect requests.
func noDelayRanker(addrs []ma.Multiaddr) []network.AddrDelay {
// NoDelayRanker ranks addresses with no delay. This is useful for simultaneous connect requests.
func NoDelayRanker(addrs []ma.Multiaddr) []network.AddrDelay {
return getAddrDelay(addrs, 0, 0, 0)
}

Expand Down
2 changes: 1 addition & 1 deletion p2p/net/swarm/dial_ranker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestNoDelayRanker(t *testing.T) {
}
for _, tc := range testCase {
t.Run(tc.name, func(t *testing.T) {
res := noDelayRanker(tc.addrs)
res := NoDelayRanker(tc.addrs)
if len(res) != len(tc.output) {
log.Errorf("expected %s got %s", tc.output, res)
t.Errorf("expected elems: %d got: %d", len(tc.output), len(res))
Expand Down
2 changes: 1 addition & 1 deletion p2p/net/swarm/dial_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func (w *dialWorker) dispatchError(ad *addrDial, err error) {
// dial all addresses immediately without any delay
func (w *dialWorker) rankAddrs(addrs []ma.Multiaddr, isSimConnect bool) []network.AddrDelay {
if isSimConnect {
return noDelayRanker(addrs)
return NoDelayRanker(addrs)
}
return w.s.dialRanker(addrs)
}
Expand Down
2 changes: 1 addition & 1 deletion p2p/net/swarm/dial_worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ func TestCheckDialWorkerLoopScheduling(t *testing.T) {
s4 := makeSwarmWithNoListenAddrs(t)
defer s4.Close()
// invalid ranking logic to trigger an error
s3.dialRanker = noDelayRanker
s3.dialRanker = NoDelayRanker
err = checkDialWorkerLoopScheduling(t, s3, s4, tc)
require.Error(t, err)
}
Expand Down
9 changes: 0 additions & 9 deletions p2p/net/swarm/swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,6 @@ func WithResourceManager(m network.ResourceManager) Option {
}
}

// WithNoDialDelay configures swarm to dial all addresses for a peer without
// any delay
func WithNoDialDelay() Option {
return func(s *Swarm) error {
s.dialRanker = noDelayRanker
return nil
}
}

// WithDialRanker configures swarm to use d as the DialRanker
func WithDialRanker(d network.DialRanker) Option {
return func(s *Swarm) error {
Expand Down

0 comments on commit 1716e2e

Please sign in to comment.