pex

package
v0.0.0-...-055f8da Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2023 License: Apache-2.0, MIT Imports: 30 Imported by: 3

README

Peer Exchange (PeX)

Gossip-based sampling service for robust connectivity.

Overview

Once a host has successfully joined a cluster, it ceases to rely on the bootstrap service for peer-discovery, and instead relies on the cluster itself to discover new peers. This process of "ambient peer discovery" is provided as an unstructured service called PeX (short for peer exchange). In contrast to DHT and PubSub-based methods, PeX can be used to repair cluster partitions, or to rejoin a cluster after having been disconnected.

See PEX.md for more details.

Quickstart

package main

import (
    "fmt"
    "context"

    "github.com/libp2p/go-libp2p"
    "github.com/wetware/casm/pkg/pex"
)

const ns = "example_namespace"

var ctx = context.Background()

func main() {
    h, _ := libp2p.New(ctx)    // start libp2p host
    px, _ := pex.New(ctx, ns)  // create peer exchange

    // Join an existing cluster and start gossiping.  The 'info' parameter
    // is a 'peer.AddrInfo' instance that points to a bootstrap peer. This
    // is usually obtained through a discovery service (not shown).
    _ = px.Join(ctx, info)

    // Print the local view.  The records can be used to repair partitions
    // or to reconnect to a cluster after becoming isolated.
    for _, rec := range px.View() {
        fmt.Println(rec.PeerID)
    }
}

Documentation

Index

Constants

View Source
const (
	DefaultMaxView    = 32
	DefaultSwap       = 10
	DefaultProtect    = 5
	DefaultDecay      = 0.005
	DefaultTick       = time.Minute * 5
	DefaultTimeout    = time.Second * 30
	DefaultMaxMsgSize = 2048
)

Variables

View Source
var (
	// ErrClosed is returned from an operation performed against a
	// closed PeerExchange or namespace.
	ErrClosed = errors.New("closed")

	// ErrNotFound is returned from an operation performed against
	// a non-existent namespace.
	ErrNotFound = errors.New("not found")

	// ErrNoListenAddrs is returned from 'New' if the supplied host
	// is not accepting peer connections.
	ErrNoListenAddrs = errors.New("host not accepting connections")

	// ErrInvalidRange is returned as a cause in a ValidationError when
	// a field's value falls outside the expected range.
	ErrInvalidRange = errors.New("invalid range")
)
View Source
var DefaultGossipConfig = GossipConfig{
	MaxView:    DefaultMaxView,
	Swap:       DefaultSwap,
	Protect:    DefaultProtect,
	Decay:      DefaultDecay,
	Tick:       DefaultTick,
	Timeout:    DefaultTimeout,
	MaxMsgSize: DefaultMaxMsgSize,
}

Functions

This section is empty.

Types

type EvtPeersUpdated

type EvtPeersUpdated []*peer.PeerRecord

type GossipConfig

type GossipConfig struct {
	MaxView int     // maximum View size (default: 30)
	Swap    int     // swapping amount (default: 10)
	Protect int     // protection amount (default: 5)
	Decay   float64 // decay probability (default .005)

	// Tick defines the maximum interval separating two gossip
	// rounds.  If Tick == 0, a default value of 5min is used.
	//
	// Intervals are jittered in order to smooth out network load.
	// The actual tick duration is derived by uniformly sampling
	// the interval (Tick/2, Tick), resulting in a mean interval
	// of .75 * Tick.
	//
	// To avoid redundant gossip rounds, Tick SHOULD be at least
	// twice the value of Timeout.
	Tick time.Duration

	// Timeout specifies the maximum duration of a gossip round.
	// If Timeout == 0, a default value of of 30s is used.
	//
	// To avoid redundant gossip rounds, Timeout SHOULD be less
	// than half of Tick.
	Timeout time.Duration

	// MaxMsgSize specifies the maximum size of a single record over
	// the wire.  This is used to prevent amplification attacks.  If
	// MaxMsgSize == 0, a default value of 2048 is used.  This value
	// is quite generous, but moderate increases are reasonably safe.
	MaxMsgSize uint64
}

GossipConfig contains parameters for the PeX gossip algorithm. Users SHOULD use the default settings. The zero value is ready to use.

type GossipRecord

type GossipRecord struct {
	peer.PeerRecord
	// contains filtered or unexported fields
}

func NewGossipRecord

func NewGossipRecord(env *record.Envelope) (*GossipRecord, error)

func (*GossipRecord) Distance

func (g *GossipRecord) Distance(id peer.ID) uint64

Distance returns the XOR of the last byte from 'id' and the record's ID.

func (*GossipRecord) Hop

func (g *GossipRecord) Hop() uint64

func (*GossipRecord) IncrHop

func (g *GossipRecord) IncrHop()

func (*GossipRecord) Key

func (g *GossipRecord) Key() ds.Key

func (*GossipRecord) Loggable

func (g *GossipRecord) Loggable() map[string]interface{}

func (*GossipRecord) Message

func (g *GossipRecord) Message() *capnp.Message

func (*GossipRecord) ReadMessage

func (g *GossipRecord) ReadMessage(m *capnp.Message) error

type Option

type Option func(px *PeerExchange)

func WithBootstrapPeers

func WithBootstrapPeers(peers ...peer.AddrInfo) Option

WithBootstrapPeers sets the bootstrap discovery service for the PeX instance to bootstrap with specific peers. It is a user-friendly way to set up the discovery service, and is exactly equivalent to:

WithDiscovery(boot.StaticAddrs{...})

Namespaces will be bootstrapped using the supplied peers whenever the PeerExchange is unable to connect to peers in its cache.

func WithDatastore

func WithDatastore(store ds.Batching) Option

WithDatastore sets the storage backend for gossip records. If newStore == nil, a volatile storage backend is used.

Note that store MUST be thread-safe.

func WithDiscovery

func WithDiscovery(d discovery.Discovery, opt ...discovery.Option) Option

WithDiscovery sets the bootstrap discovery service for the PeX instance. The supplied instance will be called with 'opt' whenever the PeeerExchange is unable to connect to peers in its cache.

func WithGossip

func WithGossip(newGossip func(ns string) GossipConfig) Option

WithGossip sets the parameters for gossiping. See github.com/wetware/casm/specs/pex.md for details on the MaxView, Swap, Protect and Decay parameters.

If newGossip == nil, the following default values are used for each namespace:

GossipConfig{
    MaxView:    32,
    Swap:       10,
    Protect:    5,
    Decay:      0.005,

    Tick:       time.Minute * 5,
    Timeout:    time.Second * 30,
    MaxMsgSize: 2048,
}

Users should exercise care when modifying the gossip params and ensure they fully understand the implications of their changes. Generally speaking, it is safe to increase MaxView. It is also reasonably safe to increase Decay by moderate amounts, in order to more aggressively expunge stale entries from cache.

Users SHOULD ensure all nodes in a given namespace have identical GossipParam values.

func WithLogger

func WithLogger(l log.Logger) Option

WithLogger sets the logger for the peer exchange. If l == nil, a default logger is used.

type PeerExchange

type PeerExchange struct {
	// contains filtered or unexported fields
}

PeerExchange is a collection of passive views of various p2p clusters.

For each namespace that is joined, PeerExchange maintains a bounded set of random peer addresses via its gossip protocol. Peers are not directly monitored for liveness, so the addresses returned from FindPeers may be stale. However, the PeX gossip-protocol guarantees that stale addresses are eventually expunged.

Note that this is behavior reflects a fundamental trade-off in the design of the PeX protocol. PeX strives to maintain a passive view of clusters that can be used to repair partitions and reconnect orphaned peers. As a result, it must not immediately expunge unreachable peers from its records, else this would cause partitions to rapidly "forget" about each other.

For the above reasons, we encourage users NOT to tune PeX parameters, as these have been carefully selected to work in a broad range of applications and micro-optimizations are likely to be counterproductive.

func New

func New(h host.Host, opt ...Option) (*PeerExchange, error)

New PeerExchange. Host MUST be lisening on at least one address.

func (*PeerExchange) Advertise

func (px *PeerExchange) Advertise(ctx context.Context, ns string, _ ...discovery.Option) (time.Duration, error)

Advertise triggers a gossip round for the specified namespace. The returned TTL is derived from the GossipParam instance associated with 'ns'. Any options passed to Advertise are ignored.

The caller is responsible for calling Advertise with the same ns parameter as soon as the returned TTL has elapsed. Failure to do so will cause the PeerExchange to eventually drop ns and to cease its participation in the namespace's gossip. A brief grace period is in effect, but SHOULD NOT be relied upon, and is therefore not documented.

func (*PeerExchange) Bootstrap

func (px *PeerExchange) Bootstrap(ctx context.Context, ns string, peers ...peer.AddrInfo) error

func (*PeerExchange) Close

func (px *PeerExchange) Close() error

func (*PeerExchange) FindPeers

func (px *PeerExchange) FindPeers(ctx context.Context, ns string, opt ...discovery.Option) (<-chan peer.AddrInfo, error)

type ValidationError

type ValidationError struct {
	Cause   error
	Message string
}

func (ValidationError) Error

func (err ValidationError) Error() string

func (ValidationError) Is

func (err ValidationError) Is(target error) bool

func (ValidationError) Unwrap

func (err ValidationError) Unwrap() error

type View

type View []*GossipRecord

func (View) Bind

func (v View) Bind(f func(View) View) View

func (View) Len

func (v View) Len() int

func (View) Less

func (v View) Less(i, j int) bool

func (View) PeerRecords

func (v View) PeerRecords() []*peer.PeerRecord

func (View) Swap

func (v View) Swap(i, j int)

func (View) Validate

func (v View) Validate() error

Validate a View that was received during a gossip round.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL