Skip to content

Commit 428f6d3

Browse files
committed
Overall improvements and updates
1 parent 58e0b26 commit 428f6d3

File tree

12 files changed

+1212
-188
lines changed

12 files changed

+1212
-188
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ jobs:
1818
strategy:
1919
matrix:
2020
include:
21-
- elixir: 1.18.x
21+
- elixir: 1.19.x
2222
otp: 28.x
2323
os: 'ubuntu-latest'
2424
lint: true
2525
coverage: true
2626
dialyzer: true
27+
- elixir: 1.18.x
28+
otp: 28.x
29+
os: 'ubuntu-latest'
2730
- elixir: 1.17.x
2831
otp: 27.x
2932
os: 'ubuntu-latest'

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
elixir 1.18.3-otp-27
2-
erlang 27.3.3
1+
elixir 1.19.4-otp-28
2+
erlang 28.2

README.md

Lines changed: 63 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,19 @@
1111

1212
## 📖 About
1313

14-
This adapter uses [Redix][redix] - a Redis driver for Elixir.
14+
This adapter uses [Redix][redix], a Redis driver for Elixir, to provide a
15+
production-ready caching solution with support for multiple deployment modes.
16+
17+
**Key Features:**
18+
19+
- **Three deployment modes:**
20+
- `:standalone` - Single Redis instance with connection pooling.
21+
- `:redis_cluster` - Native Redis Cluster with automatic sharding and failover.
22+
- `:client_side_cluster` - Client-side sharding across multiple Redis instances.
23+
- **Automatic cluster topology discovery** for Redis Cluster mode.
24+
- **Connection pooling** for high concurrency.
25+
- **Custom serializers** for flexible data encoding.
26+
- **Telemetry integration** for monitoring and observability.
1527

1628
The adapter supports different configuration modes, which are explained in the
1729
following sections.
@@ -24,7 +36,7 @@ following sections.
2436
> not the latest released version on Hex. Please reference the
2537
> [official documentation][docs-lsr] for the latest stable release.
2638
27-
[docs-lsr]: http://hexdocs.pm/nebulex_redis_adapter/NebulexRedisAdapter.html
39+
[docs-lsr]: http://hexdocs.pm/nebulex_redis_adapter/Nebulex.Adapters.Redis.html
2840

2941
---
3042

@@ -37,7 +49,7 @@ defp deps do
3749
[
3850
{:nebulex_redis_adapter, "~> 3.0.0-rc.1"},
3951
{:crc, "~> 0.10"}, #=> Needed when using `:redis_cluster` mode
40-
{:ex_hash_ring, "~> 6.0"} #=> Needed when using `:client_side_cluster` mode
52+
{:ex_hash_ring, "~> 7.0"} #=> Needed when using `:client_side_cluster` mode
4153
]
4254
end
4355
```
@@ -94,107 +106,80 @@ There are different ways to support distributed caching when using
94106

95107
### 🏗️ Redis Cluster
96108

97-
[Redis Cluster][redis_cluster] is a built-in feature in Redis since version 3,
98-
and it may be the most convenient and recommended way to set up Redis in a
99-
cluster and have distributed cache storage out-of-the-box. This adapter provides
100-
the `:redis_cluster` mode to set up **Redis Cluster** from the client-side
101-
automatically and use it transparently.
102-
103-
First, ensure you have **Redis Cluster** configured and running.
109+
[Redis Cluster][redis_cluster] is the recommended approach for production
110+
distributed caching. The adapter automatically discovers the cluster topology
111+
and routes commands to the correct shards.
104112

105-
Then you can define your cache which will use **Redis Cluster**:
113+
**Quick setup:**
106114

107115
```elixir
116+
# 1. Define your cache
108117
defmodule MyApp.RedisClusterCache do
109118
use Nebulex.Cache,
110119
otp_app: :my_app,
111120
adapter: Nebulex.Adapters.Redis
112121
end
113-
```
114-
115-
The configuration:
116122

117-
```elixir
123+
# 2. Configure in config/config.exs
118124
config :my_app, MyApp.RedisClusterCache,
119-
# Enable redis_cluster mode
120125
mode: :redis_cluster,
121-
122-
# For :redis_cluster mode this option must be provided
123126
redis_cluster: [
124-
# Configuration endpoints
125-
# This is where the client will connect and send the "CLUSTER SHARDS"
126-
# (Redis >= 7) or "CLUSTER SLOTS" (Redis < 7) command to get the cluster
127-
# information and set it up on the client side.
128127
configuration_endpoints: [
129128
endpoint1_conn_opts: [
130129
host: "127.0.0.1",
131130
port: 6379,
132-
# Add the password if 'requirepass' is enabled
133131
password: "password"
134132
]
135133
]
136134
]
137135
```
138136

139-
The pool of connections to the different master nodes is automatically
140-
configured by the adapter once it gets the cluster slots information.
137+
The adapter automatically:
138+
- Connects to configuration endpoints.
139+
- Fetches cluster topology via `CLUSTER SHARDS` (Redis 7+) or `CLUSTER SLOTS`.
140+
- Creates connection pools for each shard.
141+
- Handles `MOVED` errors with automatic retry.
142+
143+
See the [Redis Cluster documentation][redis_cluster_docs] for advanced
144+
configuration options.
141145

142-
> This could be the easiest and recommended way for distributed caching
143-
using Redis and **Nebulex.Adapters.Redis**.
146+
[redis_cluster_docs]: http://hexdocs.pm/nebulex_redis_adapter/Nebulex.Adapters.Redis.html#module-redis-cluster
144147

145148
### 🔗 Client-side Cluster
146149

147-
**Nebulex.Adapters.Redis** also provides a simple client-side cluster
148-
implementation based on a sharding distribution model.
150+
For distributing data across multiple independent Redis instances without Redis
151+
Cluster, use client-side sharding with consistent hashing.
149152

150-
Define your cache normally:
153+
**Quick setup:**
151154

152155
```elixir
156+
# 1. Define your cache
153157
defmodule MyApp.ClusteredCache do
154158
use Nebulex.Cache,
155159
otp_app: :my_app,
156160
adapter: Nebulex.Adapters.Redis
157161
end
158-
```
159162

160-
The configuration:
161-
162-
```elixir
163+
# 2. Configure in config/config.exs
163164
config :my_app, MyApp.ClusteredCache,
164-
# Enable client-side cluster mode
165165
mode: :client_side_cluster,
166-
167-
# For :client_side_cluster mode this option must be provided
168166
client_side_cluster: [
169-
# Nodes config (each node has its own options)
170167
nodes: [
171-
node1: [
172-
# Node pool size
173-
pool_size: 10,
174-
175-
# Redix options to establish the pool of connections against this node
176-
conn_opts: [
177-
host: "127.0.0.1",
178-
port: 9001
179-
]
180-
],
181-
node2: [
182-
pool_size: 4,
183-
conn_opts: [
184-
url: "redis://127.0.0.1:9002"
185-
]
186-
],
187-
node3: [
188-
conn_opts: [
189-
host: "127.0.0.1",
190-
port: 9003
191-
]
192-
]
193-
# Maybe more nodes...
168+
node1: [pool_size: 10, conn_opts: [host: "127.0.0.1", port: 9001]],
169+
node2: [pool_size: 4, conn_opts: [host: "127.0.0.1", port: 9002]],
170+
node3: [conn_opts: [host: "127.0.0.1", port: 9003]]
194171
]
195172
]
196173
```
197174

175+
The adapter uses consistent hashing to distribute keys across nodes. Each node
176+
maintains its own connection pool.
177+
178+
See the [Client-side Cluster documentation][client_cluster_docs] for more
179+
configuration options.
180+
181+
[client_cluster_docs]: http://hexdocs.pm/nebulex_redis_adapter/Nebulex.Adapters.Redis.html#module-client-side-cluster
182+
198183
### 🌉 Using a Redis Proxy
199184

200185
Another option is to use a proxy, such as [Envoy proxy][envoy] or
@@ -209,34 +194,35 @@ you set up the pool with the host and port pointing to the proxy.
209194

210195
## 🔧 Using the Adapter as a Redis Client
211196

212-
Since the Redis adapter works on top of `Redix` and provides features like
213-
connection pools, "Redis Cluster", etc., it can also work as a Redis client.
214-
The Redis API is quite extensive, and there are many useful commands you may
215-
want to run, leveraging the Redis adapter features. Therefore, the adapter
216-
provides additional functions to do so.
197+
The adapter provides `fetch_conn/1` and `fetch_conn!/1` to execute custom Redis
198+
commands using `Redix`, while leveraging the adapter's connection pooling and
199+
cluster routing.
217200

218201
```elixir
202+
# Get a connection and execute Redis commands
219203
iex> conn = MyCache.fetch_conn!()
220-
iex> Redix.command!(conn, ["LPUSH", "mylist", "world"])
221-
1
222204
iex> Redix.command!(conn, ["LPUSH", "mylist", "hello"])
223-
2
205+
1
224206
iex> Redix.command!(conn, ["LRANGE", "mylist", "0", "-1"])
225-
["hello", "world"]
207+
["hello"]
208+
```
209+
210+
For cluster modes, provide a `:key` to ensure commands route to the correct
211+
shard/node:
226212

213+
```elixir
227214
iex> conn = MyCache.fetch_conn!(key: "mylist")
228215
iex> Redix.pipeline!(conn, [
229216
...> ["LPUSH", "mylist", "world"],
230-
...> ["LPUSH", "mylist", "hello"],
231217
...> ["LRANGE", "mylist", "0", "-1"]
232218
...> ])
233-
[1, 2, ["hello", "world"]]
219+
[1, ["world"]]
234220
```
235221

236-
> [!NOTE]
237-
>
238-
> The `:name` may be needed when using dynamic caches, and the `:key` is
239-
> required when using the `:redis_cluster` or `:client_side_cluster` mode.
222+
See the [Using as Redis Client documentation][redis_client_docs] for encoding/
223+
decoding helpers and advanced usage.
224+
225+
[redis_client_docs]: http://hexdocs.pm/nebulex_redis_adapter/Nebulex.Adapters.Redis.html#module-using-the-adapter-as-a-redis-client
240226

241227
## 🧪 Testing
242228

@@ -326,4 +312,4 @@ all checks run successfully.
326312

327313
Copyright (c) 2018, Carlos Bolaños.
328314

329-
Nebulex.Adapters.Redis source code is licensed under the [MIT License](LICENSE).
315+
Nebulex.Adapters.Redis source code is licensed under the [MIT License](LICENSE.md).

benchmarks/benchmark.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ benchmarks = %{
5757
cache.incr!(:counter, 1)
5858
end,
5959
"update!" => fn {cache, random} ->
60-
cache.update!(random, 1, &Kernel.+(&1, 1))
60+
cache.update!(random, 1, &(&1 + 1))
6161
end,
6262
"get_and_update!" => fn {cache, random} ->
6363
cache.get_and_update!(random, fn

0 commit comments

Comments
 (0)