Current section
Files
Jump to
Current section
Files
guides/configuration.md
# Configuration
## Overview
The hash ring behaviour is controlled through options passed to `make/2` and `make_from_keys/2`. All options are optional.
```elixir
# All defaults
ring = ExRingRing.make(nodes)
# Custom configuration
ring = ExRingRing.make(nodes,
virtual_node_count: 512,
max_hash_byte_size: 8,
hash_algorithm: :sha256,
implementation: :dynamic
)
```
## Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `:virtual_node_count` | `pos_integer` | `256` | Virtual nodes per physical node |
| `:max_hash_byte_size` | `pos_integer` | `4` | Significant bytes of hash value |
| `:hash_algorithm` | `atom` | `:md5` | Hash function to use |
| `:implementation` | `:static \| :dynamic` | `:static` | Ring data structure |
## Hash Algorithms
| Algorithm | Byte Size | Performance | Use Case |
|-----------|-----------|-------------|----------|
| `:md5` | 16 | Fast | General purpose (default) |
| `:sha` | 20 | Moderate | When larger hash space needed |
| `:sha256` | 32 | Slowest | Maximum hash quality |
| `:crc32` | 4 | Fastest | High throughput, small hash ok |
| `:phash2` | 4 | Fastest | Erlang native, no binary conversion |
The `max_hash_byte_size` option controls how many bytes of the hash are used. For example, with `:md5` (16 bytes) and `max_hash_byte_size: 4`, only the first 4 bytes are used. This is clamped to the algorithm's maximum.
```elixir
# Uses all 32 bytes of SHA256
ring = ExRingRing.make(nodes, hash_algorithm: :sha256, max_hash_byte_size: 32)
# Fast CRC32 with minimal hash space
ring = ExRingRing.make(nodes, hash_algorithm: :crc32)
```
## Virtual Nodes
Each physical node is represented by multiple virtual nodes spread around the ring. More virtual nodes = better distribution at the cost of memory.
```elixir
# 128 virtual nodes per physical node (less memory, slightly less balanced)
ring = ExRingRing.make(nodes, virtual_node_count: 128)
# 1024 virtual nodes (more balanced, more memory)
ring = ExRingRing.make(nodes, virtual_node_count: 1024)
```
## Node Weights
Node weights scale the number of virtual nodes assigned to a node, giving it proportionally more hash space.
```elixir
# 3-argument form: key, data, weight
node = ExRingRing.Domain.Entities.Node.make(:big, "10x capacity", 10)
# With keyword options: key, data, [weight: n]
node = ExRingRing.Domain.Entities.Node.make(:small, "1x capacity", weight: 1)
# Using list_to_nodes
nodes = ExRingRing.list_to_nodes([
{:server_a, "10gb_ram", [weight: 2]},
{:server_b, "10gb_ram", [weight: 2]},
{:server_c, "4gb_ram", [weight: 1]}
])
```
### Phantom Nodes (Weight 0)
A node with weight 0 exists in the ring but is invisible to `find_node/2` and `collect_nodes/3`. Useful for standby/failover members.
```elixir
nodes = [
ExRingRing.Domain.Entities.Node.make(:active, "primary", weight: 1),
ExRingRing.Domain.Entities.Node.make(:standby, "failover", weight: 0)
]
ring = ExRingRing.make(nodes)
ExRingRing.get_nodes(ring) # => [%Node{key: :active}, %Node{key: :standby}]
ExRingRing.get_node_count(ring) # => 2
ExRingRing.find_node(ring, "key") # => {:ok, %Node{key: :active}} (never :standby)
```
To promote a phantom to an active node, simply add it with a positive weight:
```elixir
ring = ExRingRing.add_node(ring, ExRingRing.Domain.Entities.Node.make(:standby, "now_active", weight: 1))
```