Documentation ¶
Overview ¶
Package hashring implements consistent hashing hashring data structure.
In general, consistent hashing is all about mapping of object from a very big set of values (e.g. request id) to object from a quite small set (e.g. server address). The word "consistent" means that it can produce consistent mapping on different machines or processes without additional state exchange and communication.
For more theory about the subject please see this great document: https://theory.stanford.edu/~tim/s16/l/l1.pdf
There are two goals for this hashring implementation: 1) To be efficient in highly concurrent applications by blocking read operations for the least possible time. 2) To correctly handle very rare but yet possible hash collisions, which may break all your eventually consistent application.
To reach the first goal hashring uses immutable AVL tree internally, making read operations (getting item for object) blocked only for a tiny amount of time needed to swap the ring's tree root after some write operation (insertion or deletion).
The second goal is reached by using ring of size 2^64-1 points, which dramatically reduces the probability of hash collisions (the greater the number of items on the ring, the higher the probability of collisions) and implementation that covers collisions.
Index ¶
Examples ¶
Constants ¶
const DefaultMagicFactor = 1020
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Ring ¶
type Ring struct { // Hash is an optional function used to build up a new 64-bit hash function // for further hash values calculation. Hash func() hash.Hash64 // MagicFactor is an optional number of "virtual" points on the ring per // item. The higher this number, the more equal distribution of objects // this ring produces and the more time is needed to update the ring. // // MagicFactor is the maximum number of points which can be placed on ring // for a single item. That is, item having max weight will have this amount // of points. // // If MagicFactor is zero, then the DefaultMagicFactor is used. For most // applications the default value is fine enough. MagicFactor int // contains filtered or unexported fields }
Ring is a consistent hashing hashring. It is goroutine safe. Ring instances must not be copied. The zero value for Ring is an empty ring ready to use.
Example ¶
var ring Ring // Insert four servers on the ring with equal weight. ring.Insert(StringItem("server01"), 1) ring.Insert(StringItem("server02"), 1) ring.Insert(StringItem("server03"), 1) ring.Insert(StringItem("server04"), 1) // Calculate distribution of 1M requests across four servers. distribution := make(map[string]int) for i := 0; i < 1000000; i++ { x := ring.Get(StringItem(strconv.Itoa(i))) s := string(x.(StringItem)) distribution[s]++ } fmt.Println(distribution["server01"]) fmt.Println(distribution["server02"]) fmt.Println(distribution["server03"]) fmt.Println(distribution["server04"])
Output: 254240 253479 246126 246155
func (*Ring) Delete ¶
Delete removes item x from the ring. It returns non-nil error when x doesn't exist on the ring.
func (*Ring) Get ¶
Get returns mapping of v to previously inserted item. Returned item is nil only when ring is empty.