UNPKG

ketama

Version:

A hash ring implementation using libketama-like hashing.

107 lines (73 loc) 4.06 kB
# ketama [![Actions Status](https://github.com/connor4312/ketama/workflows/Run%20Tests/badge.svg)](https://github.com/connor4312/ketama/actions) Ketama is a JavaScript/TypeScript implementation of the [libketama](https://www.metabrew.com/article/libketama-consistent-hashing-algo-memcached-clients) hash ring. The primary advantage of ketama-style hashing is that it reduces the amount of work which is shuffled to other servers when the hashring membership changes. npm install --save ketama Then go forth with confidence: ```js // alternatively: const { HashRing } = require('ketama'); import { HashRing } from 'ketama'; const ring = new HashRing(); ring.addNode('127.0.0.1'); // add with default weight ring.addNode('127.0.0.2', 2); // weight of 2 = twice as likely to choose this one export function onDoWork(input) { // hashes the input and choses a server based on it: const server = ring.getNode(input); doWorkOn(server); } export function doWorkOnMultipleServers(input) { // picks two "replica" servers from the ring to do work on for (const server of ring.getNodes(input, 2)) { doWorkOn(server); } } ``` ## Table of Contents - [HashRing(\[nodes\], \[hashFunction\])](#hashringnodes-hashfunction) - [hashRing.addNode(node\[, weight\])](#hashringaddnodenode-weight) - [hashRing.removeNode(node)](#hashringremovenodenode) - [hashRing.getNode(input)](#hashringgetnodeinput) - [hashRing.getNodes(input, replicas)](#hashringgetnodesinput-replicas) ## HashRing(\[nodes], \[hashFunction]) Creates a new `HashRing`, optionally with the initial set of nodes. The nodes can be _either_ a string, or an object with a string property "key" which will be used internally to hash against, for example: ```js new HashRing(['127.0.0.1', { key: '127.0.0.2', port: 1337 }]); ``` When giving the nodes in the constructor, you can specify a weight by providing an object with the `node` and its `weight`. Weights are proportional; a node with a weight of `2` is twice as likely to be chosen than one with the default weight of `1`. For example: ```js new HashRing([ { node: '127.0.0.1', weight: 2 }, { node: { key: '127.0.0.2', port: 1337 }, weight: 3 ]); ``` Finally, you can also specify the hashing function to use. This can be either the name of an algorithm the `require('crypto').createHash` implements, or a custom function that returns an int32 given a Buffer. Defaults to `sha1`. For example: ```js new HashRing([], 'md5'); // hash with md5 instead new HashRing([], buf => myCustomHash().readInt32BE()); // custom function ``` ## hashRing.addNode(node\[, weight]) Adds a new node to the existing hashring. The node can be _either_ a string, or an object with a string property "key" which will be used internally to hash against. ```js ring.addNode('127.0.0.1'); ring.addNode({ key: '127.0.0.2', port: 1337 }); ``` You can optionally specify a weight as the second argument. Weights are proportional; a node with a weight of `2` is twice as likely to be chosen than one with the default weight of `1`. If the node already exists, it is replaced; for example, you can call `addNode` multiple times to update a node's weight. ## hashRing.removeNode(node) Removes a node previously added to the hash ring. ```js ring.removeNode('127.0.0.1'); ``` No-op if the node is not in the ring. ## hashRing.getNode(input) Gets the node on which work should be done for the given input, which should be either a string or buffer. Returns the object or string originally given to `addNode` or `new HashRing()`, or returns `undefined` if the ring is empty. ```js const server = ring.getNode(inputData); doWorkOn(server); ``` ## hashRing.getNodes(input, replicas) Gets the "replicas" number of nodes that should handle the input, which should be either a string or buffer. The returned array length wiill equal the number of replicas, except if there are fewer nodes available than replicas requested, in which case all nodes are returned. ```js for (const server of ring.getNodes(input, 2)) { doWorkOn(server); } ```