fireproofsocks
I’ve been kicking the tires of the libring package to help distribute work/data across multiple nodes in a deterministic way.
Given a ring like so:
iex> ring = HashRing.new()
|> HashRing.add_node(:a@localhost)
|> HashRing.add_node(:b@localhost)
#<Ring[:b@localhost, :a@localhost]>
You can ask it which n nodes a given key should map to, e.g.
iex> HashRing.key_to_nodes(ring, 13, 2)
[:a@localhost, :b@localhost]
But what’s strange is that certain numbers seem to cause problems. For example, the lucky number 14 comes out with only ONE node assigned to it instead of the 2 that were asked for:
iex> HashRing.key_to_nodes(ring, 14, 2)
[:a@localhost]
But more curious is that the problematic keys seem to be related to the names of the hosts, e.g. using hostnames :a and :b works as expected:
iex> ring2 = HashRing.new() |> HashRing.add_node(:a) |> HashRing.add_node(:b)
#<Ring[:a, :b]>
iex> HashRing.key_to_nodes(ring2, 14, 2)
[:b, :a]
The docs say that “Will return either count results or the number of nodes, depending on which is smaller.”, but this seems to not be the case with the lucky number 14.
Can someone explain this? This is easy enough to avoid by wrapping calls to HashRing.key_to_nodes/3 to return all nodes when the count is equal to the number of available nodes, but it sure caught me by surprise!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
ruslandoga
libringseems to be using gb_trees and iterates over it. Maybe it didn’t implement wrapping around?Here: libring/lib/ring.ex at c64f12ded165eef37a987595dd1815e5846e8e6d · bitwalker/libring · GitHub
Maybe it needs to restart iteration from some appropriate point (e.g.
:gb_trees.smallest(r)or some0equivalent) ifnextreturnes:noneandcount > 0Off-topic: Erlang people have some sort of unusual affinity towards hash rings (probably because of Riak) but I like Rendezvous hashing - Wikipedia better
Here’s a basic but simple (no deps) implementation: GitHub · Where software is built – modifying it to
k > 1to pick top-K nodes is a matter of switching fromEnum.max_bytoEnum.sortandEnum.take.al2o3cr
Not particularly familiar with this algorithm, but re: @ruslandoga’s point about wrapping around - 14’s
phashvalue is definitely largegarrison
Of course, Riak was a Dynamo clone and the Dynamo paper was very influential. They in turn got it from Akamai, and I have seen it speculated that the popularity of consistent hashing was essentially a cargo cult on top of Akamai, which was a big deal during the boom. There was even an old Apple keynote from the time where Steve Jobs talked up Akamai’s CDN and announced they had invested.
The funny part is that Rendezvous hashing is not only better but, on top of that, way easier to understand.
Side note: if you are using this method to store data, make sure you read the Copysets paper!
fireproofsocks
Thanks for the insights! I’m new to all the algorithms here. I see GitHub - timdeputter/Rendezvous: Implementation of the Rendezvous or Highest Random Weight (HRW) hashing algorithm in the Elixir Programming Language · GitHub but it doesn’t seem to be on hex? (No docs, anyway… it’s 10 years old). I have some other headier problems with distributed nodes that are probably more in need of my brainpower, but I’d be happy to kick tires on this… anyone know if there is a more current implementation of rendezvous hashing in Elixir?
ruslandoga
It might be the curse of this approach. In Elixir it can be expressed with a single
Enum.max_byThe linked implementation seems to be using very heavy hashing functions and attempts to make them configurable, there is no need for this.
:erlang.phash2is good and fast enough.fireproofsocks
Which linked implementation are you referring to? Are you saying that
libring’s implementation is too complex? Or that therendezvousrepo is trying to be configurable and it’s too complex.How to adjust
:erlang.phash2so it returns a sorted list?garrison
What he’s saying is that the rendezvous hash algorithm is so simple that a library isn’t really necessary.
The algorithm is literally just: hash the key with each node and sort the hashes, then take the top
Nresults and those are your nodes. Themax_byexample he gave would beN=1, but you could instead doEnum.sort_by(...) |> Enum.take(n).fireproofsocks
ah, gotcha. Makes sense. Yep. Thanks for the clarification!