Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide pluggable hashing and lookup strategy for NodeLocator #154

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jasonk000
Copy link
Member

A significant part of the getBulk with large keylists is spent performing NodeLocator lookups (getPrimary) to identify which node to send traffic to. The current Ketama configuration is based on MD5 which is no longer best-in-class, and uses a Java TreeMap which is not the most efficient approach for large arrays.

This PR makes the components of the NodeLocator pluggable with different hash/ring functions and different strategies for storage of the hash-ring-to-node lookup function. It then provides a number of alternative implementations. It does NOT change any of the existing implementation / configuration, which would need to come in a follow-up.

Implementation configuration choices range from 30% faster to ~10x faster.

image

A HashRingAlgorithm defines the algorithm that will be used to split a
node into a ring. It assumes the ring will be Ketama-styled in that one
node can be responsible for multiple keyspace ranges. Hash-rings can
also be 'Simple' when they have a 1:1 mapping (one node receives one
keyspace).

A NodeLocatorLookup carries the data layout and associated search
functions to locate a node for a given hash in the hashring.

We also wire in the EVCacheNodeLocator to use the existing default
implementations.
This introduces a combination of options for hash-ring generation and
for the node lookup locator.

This does not change any of the default configuration, but paves the
way for future configuration to use the new code. In the right
configuration this will generate anywhere from a 30% to a 10x increase
in throughput while still allowing the choice of a backwards-compatible
configuration.

Also introduce some tests and benchmarks to demonstrate the impact.

Node lookup

- legacy uses the existing TreeMap implementation, this is the existing
  implementation.

- array uses a straightforward sorted array of all values and
  binary-search, this is backwards compatible.

- eytzinger uses a BFS-sorted array with a more efficient search tree
  (aka Eytzinger index), this is backwards compatible.

- direct uses an efficient direct-array index approximation of the
  ketama hash-space, this is not backwards compatible as the hash space
  is split at slightly different locations.

Hash ring

- the ketama-md5 ring is the existing Ketama implementation using MD5
  for a 128-bit hash

- the ketama-murmur3 ring is the Ketama implementation modified to use
  Murmur3 as a 128-bit hash

- the simple-fnv1a ring uses a simple (not-Ketama) ring, using FNV-1A
  hash

Benchmark           (hashRing)  (keyCount)  (keyTailLength)  (locator)  (nodeCount)   Mode  Cnt      Score      Error  Units
testGetPrimary      ketama-md5        2000                0     legacy           10  thrpt   15   2607.833 ±   52.342  ops/s  <--
testGetPrimary      ketama-md5        2000                0     legacy          120  thrpt   15   2137.626 ±   22.707  ops/s  <--
testGetPrimary      ketama-md5        2000               50     legacy           10  thrpt   15   1798.278 ±   27.627  ops/s  <--
testGetPrimary      ketama-md5        2000               50     legacy          120  thrpt   15   1539.314 ±   13.284  ops/s  <--
testGetPrimary  ketama-murmur3        2000                0     legacy           10  thrpt   15   5589.163 ±  125.725  ops/s
testGetPrimary  ketama-murmur3        2000                0     legacy          120  thrpt   15   3730.209 ±   46.291  ops/s
testGetPrimary  ketama-murmur3        2000               50     legacy           10  thrpt   15   4160.228 ±   55.954  ops/s
testGetPrimary  ketama-murmur3        2000               50     legacy          120  thrpt   15   2925.185 ±   66.501  ops/s

testGetPrimary      ketama-md5        2000                0      array           10  thrpt   15   2856.391 ±   29.325  ops/s
testGetPrimary      ketama-md5        2000                0      array          120  thrpt   15   2567.685 ±   58.148  ops/s
testGetPrimary      ketama-md5        2000               50      array           10  thrpt   15   1918.709 ±   11.799  ops/s
testGetPrimary      ketama-md5        2000               50      array          120  thrpt   15   1764.622 ±   10.229  ops/s
testGetPrimary  ketama-murmur3        2000                0      array           10  thrpt   15   8139.093 ±  391.241  ops/s
testGetPrimary  ketama-murmur3        2000                0      array          120  thrpt   15   5646.702 ±  192.760  ops/s
testGetPrimary  ketama-murmur3        2000               50      array           10  thrpt   15   4894.453 ±  143.582  ops/s
testGetPrimary  ketama-murmur3        2000               50      array          120  thrpt   15   3910.925 ±  189.508  ops/s

testGetPrimary      ketama-md5        2000                0  eytzinger           10  thrpt   15   2939.745 ±   21.005  ops/s <--
testGetPrimary      ketama-md5        2000                0  eytzinger          120  thrpt   15   2661.046 ±   25.636  ops/s <--
testGetPrimary      ketama-md5        2000               50  eytzinger           10  thrpt   15   1939.034 ±   12.243  ops/s <--
testGetPrimary      ketama-md5        2000               50  eytzinger          120  thrpt   15   1822.782 ±   10.516  ops/s <--
testGetPrimary  ketama-murmur3        2000                0  eytzinger           10  thrpt   15   7761.497 ±   47.165  ops/s
testGetPrimary  ketama-murmur3        2000                0  eytzinger          120  thrpt   15   6125.655 ±  100.586  ops/s
testGetPrimary  ketama-murmur3        2000               50  eytzinger           10  thrpt   15   4920.855 ±   42.134  ops/s
testGetPrimary  ketama-murmur3        2000               50  eytzinger          120  thrpt   15   4084.432 ±   26.123  ops/s

testGetPrimary      ketama-md5        2000                0     direct           10  thrpt   15   3982.198 ±   42.075  ops/s <--
testGetPrimary      ketama-md5        2000                0     direct          120  thrpt   15   3908.419 ±   41.634  ops/s <--
testGetPrimary      ketama-md5        2000               50     direct           10  thrpt   15   2359.383 ±   14.831  ops/s <--
testGetPrimary      ketama-md5        2000               50     direct          120  thrpt   15   2332.527 ±   12.630  ops/s <--
testGetPrimary  ketama-murmur3        2000                0     direct           10  thrpt   15  25727.606 ±  236.122  ops/s <--
testGetPrimary  ketama-murmur3        2000                0     direct          120  thrpt   15  24404.013 ±  223.451  ops/s <--
testGetPrimary  ketama-murmur3        2000               50     direct           10  thrpt   15   8182.122 ±   43.455  ops/s <--
testGetPrimary  ketama-murmur3        2000               50     direct          120  thrpt   15   7798.550 ±   90.895  ops/s <--

testGetPrimary    simple-fnv1a        2000                0     legacy           10  thrpt   15  16497.086 ±  237.651  ops/s
testGetPrimary    simple-fnv1a        2000                0     legacy          120  thrpt   15  15026.541 ±   64.791  ops/s
testGetPrimary    simple-fnv1a        2000               50     legacy           10  thrpt   15   5256.310 ±   88.628  ops/s
testGetPrimary    simple-fnv1a        2000               50     legacy          120  thrpt   15   3969.989 ±   15.371  ops/s
testGetPrimary    simple-fnv1a        2000                0      array           10  thrpt   15  33851.510 ±  320.860  ops/s
testGetPrimary    simple-fnv1a        2000                0      array          120  thrpt   15  25844.239 ±  106.294  ops/s
testGetPrimary    simple-fnv1a        2000               50      array           10  thrpt   15   5650.150 ±  181.146  ops/s
testGetPrimary    simple-fnv1a        2000               50      array          120  thrpt   15   4232.681 ±  212.107  ops/s
testGetPrimary    simple-fnv1a        2000                0  eytzinger           10  thrpt   15  34050.744 ±   83.166  ops/s
testGetPrimary    simple-fnv1a        2000                0  eytzinger          120  thrpt   15  29417.993 ±  484.761  ops/s
testGetPrimary    simple-fnv1a        2000               50  eytzinger           10  thrpt   15   5699.404 ±   17.079  ops/s
testGetPrimary    simple-fnv1a        2000               50  eytzinger          120  thrpt   15   4516.383 ±  144.211  ops/s
testGetPrimary    simple-fnv1a        2000                0     direct           10  thrpt   15  44406.089 ±  290.314  ops/s
testGetPrimary    simple-fnv1a        2000                0     direct          120  thrpt   15  43076.871 ± 1227.180  ops/s
testGetPrimary    simple-fnv1a        2000               50     direct           10  thrpt   15   7761.636 ±  252.395  ops/s
testGetPrimary    simple-fnv1a        2000               50     direct          120  thrpt   15   7564.380 ±  218.651  ops/s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant