gogossip

package module
v0.0.0-...-131e97a Latest Latest
Warning

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

Go to latest
Published: Apr 3, 2023 License: BSD-3-Clause Imports: 14 Imported by: 0

README

go-gossip

This is Go implementation of the Gossip protocol.

Gossip is a communication protocol that delivers messages in a distributed system.
The point is that each node transmits data while periodically exchanging metadata based on TCP/UDP without a broadcast master.
In general, each node periodically performs health checks of other nodes and communicates with them, but this library relies on an externally imported discovery layer.
The gossip protocol is divided into two main categories: Push and Pull. If implemented as a push, it becomes inefficient if a large number of peers are already infected. If implemented as Pull, it will propagate efficiently, but there is a point to be concerned about because the message that needs to be propagated to the peer needs to be managed.
This project implements the Pull-based Gossip protocol. That's why we need to implement a way to send a new message when another node requests it. In this library, it consists of two parts, 'filter' that checks whether a message is received and 'cache' that stores the message for propagation.

Take a look at the list of supported features below.

  • Message propagation
  • Secure transport

It's forcus on gossip through relying on discovery layer from outside.

Layer

image

Registry layer

Registry layer serves as the managed peer table. That could be static peer table, also could dynamic peer table(like DHT).
The required(MUST) method is Gossipiers. Gossipiers is used to select random peers to send gossip messages to.

type Registry interface {
	Gossipiers() []string
}

(It means DHT or importers covers registration to Gossip protocol)
Gossipiers returns array of raw addresses. The raw addresses will validate when gossip layer. Even if rely on validation of externally imported methods, We need to double-check internally here(trust will make unexpected panic).
A consideration is whether Gossipiers return value actually needs a peer ID.
In generally, there is need each peer's meta datas(about memberlist), the unique id is required. However, since this library does not support health checks, the peer id is not required from a metadata required point of view.
In addition, if you receive and use a unique ID from outside, the dependency relationship becomes severe, so I think it is correct not to have an peer id.
When making a request, such as checking gossip node stat or something, we decide to use the raw address.

Gossip layer

Gossip layer serves core features that propagating gossip messages and relay data to application when needed.
For serve that, it's detect packet and handles them correctly to the packet types.
There is three tasks what this layer have to do.

  1. The node should be able to be a source of gossip. Provide surface interface for application programs to push gossip messages.
  2. Handles them correctly to the packet types.
  3. Detects is the gossip message already exist in memory and relay the gossip messages to the application if necessary.

Take a look the packet specification below.

Packet

┏---------------------┓
| Label | Actual data |
┗---------------------┛

Label

┏--------------------------------┓
| Packet type| Encrypt algorithm | 
┗--------------------------------┛

Packet type (1 byte)

1: PullRequest
2: PullResponse

Packet handle

PullRequest - It replies a packet to the requester. However, packets that have already been taken by the requester are excluded.
PullResponse - Stores the received message in memory. Messages that have already been received will be ignored.

Filter and Propagator

Filter is used to distinguish between 'already received messages' and 'newly received messages'.
To determine this 'accurately' in an asynchronous network environment, all history must be stored. Therefore, if you are sensitive to receiving duplicate data, store the history permanently (currently implemented as LevelDB). If it's not very sensitive, store it in a large enough memory cache.
Propagator classifies newly received messages using filters and manages a cache to propagate them to other nodes. Actually, even if all messages are propagated, nodes use filters to store only those messages that have not been received. However, we exclude and propagate messages that are determined to have propagated 'enough' to reduce network congestion.

Transport/Security layer

Transport layer supports peer-to-peer UDP communication. Security layer resolve the secure between peer to peer trnasmission. From the point of view of packet fragmentation, to use UDP, packets must be divided and transmitted at the application level or TCP must be used, but this library does not care about packet fragmentation. The maximum packet size is set by subtracting the size of the IP header (20 bytes) and UDP header (8 bytes) from the 2^18 bytes written to the UDP header. So, max packet size is 65507 byte.

It should be possible to add multiple encryption algorithms. I'm just considering a method of encrypting and decrypting using a passphrase(It is also okay to encrypt in the application and then propagate it. In this case, you should set NO-SECURE in config).

Encrypt alogrithm (1 byte)

0: NO-SECURE
1: AES-256-CBC

Documentation

Index

Constants

View Source
const (
	NON_SECURE_TYPE = 0x00
	AES256_CBC_TYPE = 0x01
)

Variables

View Source
var (
	// If call 'Push' and it returns this error, you are making
	// too many requests. cache is emptied after a certain amount
	// of time, so if you try again, it will be processed normally.
	ErrNoSpaceCache = errors.New("too many requests")
)

Functions

This section is empty.

Types

type Cipher

type Cipher struct {
	CipherMethod
	// contains filtered or unexported fields
}

func (*Cipher) Is

func (s *Cipher) Is(kind EncryptType) bool

type CipherMethod

type CipherMethod interface {
	Encrypt(string, []byte) ([]byte, error)
	Decrypt(string, []byte) ([]byte, error)
}

type Config

type Config struct {
	// FilterWithStorage is the filter option variable. If the
	// value is nil, it means a memory filter. Set the path to
	// save the data if to use the storage filter.
	FilterWithStorage string

	// GossipNumber means the number of peers to make pull
	// requests per pullInterval. This number must be greater
	// than 2, and if set to greater than the total number of
	// existing peers, it means broadcasting.
	GossipNumber int

	EncType    EncryptType
	Passphrase string
}

func DefaultConfig

func DefaultConfig() *Config

type EncryptType

type EncryptType byte

func (EncryptType) String

func (e EncryptType) String() string

type Gossiper

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

func New

func New(reg Registry, transport Transport, cfg *Config) (*Gossiper, error)

func (*Gossiper) MessagePipe

func (g *Gossiper) MessagePipe() chan []byte

MessagePipe is a method for surface to application for send newly messages.

func (*Gossiper) Pending

func (g *Gossiper) Pending() int

func (*Gossiper) Push

func (g *Gossiper) Push(buf []byte) error

Push is a method for surface to application for starts gossip. It's limits requests to prevent abnormal propagation when more requests than cacheSize are received.

func (*Gossiper) Start

func (g *Gossiper) Start()

type Registry

type Registry interface {
	// The imported Registry object must have method Gossipiers implement thread
	// safety. It returns all of the peer that target of gossip protocol by
	// array of raw addresses. The raw address validate when before send gossip.
	//
	// It'll used 'SelectRandomPeers' in Gossiper.
	Gossipiers() []string
}

type Transport

type Transport interface {
	ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
	WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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