ketama
v1.0.0
Published
A hash ring implementation using libketama-like hashing.
Downloads
295
Maintainers
Readme
ketama
Ketama is a JavaScript/TypeScript implementation of the libketama 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:
// 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])
- hashRing.addNode(node[, weight])
- hashRing.removeNode(node)
- hashRing.getNode(input)
- hashRing.getNodes(input, 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:
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:
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:
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.
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.
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.
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.
for (const server of ring.getNodes(input, 2)) {
doWorkOn(server);
}