ProductPromotion
Logo

Go.Lang

made by https://0x3d.site

GitHub - mbrostami/consistenthash: A Go library that implements Consistent Hashing (+Block Partitioning)
A Go library that implements Consistent Hashing (+Block Partitioning) - mbrostami/consistenthash
Visit Site

GitHub - mbrostami/consistenthash: A Go library that implements Consistent Hashing (+Block Partitioning)

GitHub - mbrostami/consistenthash: A Go library that implements Consistent Hashing (+Block Partitioning)

Build Status Go Report Card

Consistent Hashing

A Go library that implements Consistent Hashing with zero dependency
This package is implemented based on golang/groupcache with some performance improvements

Improvements:

  • Remove function added - sort and remove a node (and replicas) from the hash ring
  • int hashes replaced with uint32
  • Number of replicas is now configurable while adding new node (useful when capacity is not the same for all nodes)

Technical Details:

A HashMap that maps the hash of the key to the original values, something like 0xFF => "node number one"

A BlockMap that has dynamic number of blocks and each block has sorted list of items, and each item has Key and Pointer to the HashMap. The block number is calculated as:
blockNumber = hash(key) / (MaxUint32 / number of blocks)
This will lead us to have a kind of sorted blocks.

A ReplicaMap that keeps the number of replicas for each key ONLY if the replicas for specific key is different than the default replicas. So if you have 10k keys with default replica set to 100 and you add a new key with 120 replicas, the ReplicaMap will have 1 record.

Re-Balancing:

To add a new record we need to know how many blocks we should have. Considering current number of keys and a control option D we will have number of keys divided by D as number of expected blocks.

As the result will change by adding D number of new keys we will need a re-balancing mechanism to add or remove blocks. To make it efficient we can start re-balancing if the expected blocks is twice more or less than current number of blocks.

As an example:
If we have D = 200 with 100k existing keys, there will be 1000 blocks each contains approximately 500 keys. Adding 200 new keys will require us to have 1001 blocks. So expected blocks is 1001 but current is 1000. As we add more keys the expected blocks becomes 2001 and current remains 1000. In this case re-balancing process starts and adds 1001 more blocks. As a result we will have 2001 blocks. Next re-balancing will happen when we need 4002 blocks and so on.

This process happens as follows:
Looping over blocks from the last one. Looping over items in each block starting from end, calculating the new block number for each key. Because items are sorted, as we reach to a key that doesn't belong to a different block, we shift items to the target block.
Here is an example:

max hash value = 1000
total keys = 100
D = 5
blockSize = 1000 / (100/5) = 50
blockNumber = hash / blockSize
Number of blocks: 1000 / blockSize = 20
10  / 50 => 0
20  / 50 => 0
50  / 50 => 1
...
1000 / 50 => 20

Block[0]  = [10,20,30,40]
Block[1]  = [50,60,70,80]
Block[4]  = [210,220,230,240]
...

Re-balancing:
newBlockSize = 1000/ (200/5) = 25
newBlockNumber = hash / newBlockSize
Expected blocks: 1000 / newBlockSize = 40
iter b20: // starting from last block
...
iter b4:
Block[0]  = [10,20,30,40]
Block[1]  = [50,60,70,80]
Block[8]  = [210,220]  // moved from block[4]
Block[9]  = [230,240]  // moved from block[4]
itr b1:
Block[0]  = [10,20,30,40]
Block[2]  = [50,60,70] // moved from block[1]
Block[3]  = [80]       // moved from block[1]
Block[8]  = [210,220]  // moved from block[4]
Block[9]  = [230,240]  // moved from block[4]
itr b0:
Block[0]  = [10,20]
Block[1]  = [30,40].   // moved from block[0]
Block[2]  = [50,60,70] // moved from block[1]
Block[3]  = [80]       // moved from block[1]
Block[8]  = [210,220]  // moved from block[4]
Block[9]  = [230,240]  // moved from block[4]

Time complexity of the above would be O(n) in worst case where n is the number of keys.
You can set D value by passing an option to constructor: WithBlockPartitioning(5)

Adding Item:

Time Complexity is between O(1) and O(log k) where k is the maximum number of keys in a block. (excluding shifting items)

To add a new item to a block, we need to calculate the block number and do a binary search to find the position where we want to insert the item, and update the list in that block. If the item is the original node, we need to add the key and value to the HashMap as well. All the items in the block (including replicas) will use the pointer to the HashMap.

Removing Item:

Time Complexity is between O(1) and O(log k) where k is the maximum number of keys in a block. (excluding shifting items)

To remove an item, we find the block number using hash of the key, doing a binary search in the block, finding removing the item in the block. The re-balancing might be necessary if we remove 1/2 of all the stored keys.

Lookup:

Time Complexity is between O(1) and O(log k) where k is the maximum number of keys in a block.

To find a key, we find the block number using hash of the key, doing a binary search to find the closest hash to the lookup key. You might go to the next non-empty block and get the first item.

Usage

go get github.com/mbrostami/consistenthash/v2

Simple use case

package main

import (
	"fmt"

	"github.com/mbrostami/consistenthash/v2"
)

func main() {

	ch := consistenthash.New(consistenthash.WithDefaultReplicas(10))
	ch.Add([]byte("templateA"), []byte("templateB"))

	assignedTemplate := ch.Get([]byte("userA")) // assigned template should always be the same for `userA`
	fmt.Printf("assigned: %s", assignedTemplate)
}

Weighted load

package main

import (
	"fmt"

	"github.com/mbrostami/consistenthash/v2"
)

func main() {
	ch := consistenthash.New(consistenthash.WithDefaultReplicas(10))
	ch.Add([]byte("127.0.0.1:1001"), []byte("127.0.0.1:1002"))
	ch.AddReplicas(40, []byte("127.0.0.1:1003")) // 4x more weight

	rKey := "something like request url or user id"
	node := ch.Get([]byte(rKey)) // find upper closest node
	fmt.Println(node) // this will print out one of the nodes
}

More about consistent hashing

You can find some explanation in this blog post: https://liuzhenglaichn.gitbook.io/system-design/advanced/consistent-hashing

The code example to achieve a hash ring similar to the following picture:

package main

import (
	"fmt"

	"github.com/mbrostami/consistenthash/v2"
)


func main() {
	ch := consistenthash.New(consistenthash.WithDefaultReplicas(3))
	ch.Add([]byte("A"), []byte("B"), []byte("C"))

	fmt.Println(ch.Get([]byte("Alica")))
	fmt.Println(ch.Get([]byte("Bob")))
	fmt.Println(ch.Get([]byte("Casey")))

}

Image

Articles
to learn more about the golang concepts.

Resources
which are currently available to browse on.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

FAQ's
to know more about the topic.

mail [email protected] to add your project or resources here ๐Ÿ”ฅ.

Queries
or most google FAQ's about GoLang.

mail [email protected] to add more queries here ๐Ÿ”.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory