View Source NebulexRedisAdapter (NebulexRedisAdapter v2.4.2)
Nebulex adapter for Redis. This adapter is implemented using Redix
,
a Redis driver for Elixir.
NebulexRedisAdapter provides three setup alternatives:
Standalone - The adapter establishes a pool of connections with a single Redis node. The
:standalone
is the default mode.Redis Cluster - Redis Cluster is a built-in feature in Redis since version 3, and it may be the most convenient and recommendable way to set up Redis in a cluster and have a distributed cache storage out-of-box. This adapter provides the
:redis_cluster
mode to set up Redis Cluster from the client-side automatically and be able to use it transparently.Built-in client-side cluster based on sharding - This adapter provides a simple client-side cluster implementation based on Sharding distribution model via
:client_side_cluster
mode.
Standalone
We can define a cache to use Redis as follows:
defmodule MyApp.RedisCache do
use Nebulex.Cache,
otp_app: :nebulex,
adapter: NebulexRedisAdapter
end
The configuration for the cache must be in your application environment,
usually defined in your config/config.exs
:
config :my_app, MyApp.RedisCache,
conn_opts: [
host: "127.0.0.1",
port: 6379
]
Redis Cluster
We can define a cache to use Redis Cluster as follows:
defmodule MyApp.RedisClusterCache do
use Nebulex.Cache,
otp_app: :nebulex,
adapter: NebulexRedisAdapter
end
The config:
config :my_app, MyApp.RedisClusterCache,
mode: :redis_cluster,
redis_cluster: [
configuration_endpoints: [
endpoint1_conn_opts: [
host: "127.0.0.1",
port: 6379,
# Add the password if 'requirepass' is on
password: "password"
],
...
]
]
Client-side Cluster
We can define a cache with "client-side cluster mode" as follows:
defmodule MyApp.ClusteredCache do
use Nebulex.Cache,
otp_app: :nebulex,
adapter: NebulexRedisAdapter
end
The config:
config :my_app, MyApp.ClusteredCache,
mode: :client_side_cluster,
client_side_cluster: [
nodes: [
node1: [
pool_size: 10,
conn_opts: [
host: "127.0.0.1",
port: 9001
]
],
node2: [
pool_size: 4,
conn_opts: [
url: "redis://127.0.0.1:9002"
]
],
node3: [
conn_opts: [
host: "127.0.0.1",
port: 9003
]
],
...
]
]
Configuration options
In addition to Nebulex.Cache
config options, the adapter supports the
following options:
:mode
- Redis configuration mode.:standalone
- A single Redis instance. See the "Standalone" section in the module documentation for more options.:redis_cluster
- Redis Cluster setup. See the "Redis Cluster" section in the module documentation for more options.:client_side_cluster
- See the "Client-side Cluster" section in the module documentation for more options.
The default value is
:standalone
.:pool_size
(pos_integer/0
) - The number of connections that will be started by the adapter (based on the:mode
). The default value isSystem.schedulers_online()
.:serializer
- Custom serializer module implementing theNebulexRedisAdapter.Serializer
behaviour.:serializer_opts
(keyword/0
) - Custom serializer options. The default value is[]
.:encode_key
(keyword/0
) - Options for encoding the key. The default value is[]
.:encode_value
(keyword/0
) - Options for encoding the value. The default value is[]
.:decode_key
(keyword/0
) - Options for decoding the key. The default value is[]
.:decode_value
(keyword/0
) - Options for decoding the value. The default value is[]
.
:conn_opts
(keyword/0
) - Redis client options. SeeRedix
docs for more information about the options. The default value is[host: "127.0.0.1", port: 6379]
.:redis_cluster
- Required only when:mode
is set to:redis_cluster
. A keyword list of options.See "Redis Cluster options" section below.
:client_side_cluster
- Required only when:mode
is set to:client_side_cluster
. A keyword list of options.See "Client-side Cluster options" section below.
Redis Cluster options
The available options are:
:configuration_endpoints
- Required. A keyword list of named endpoints where the key is an atom as an identifier and the value is another keyword list of options (same as:conn_opts
).See "Redis Cluster" for more information.
:override_master_host
(boolean/0
) - Defines whether the given master host should be overridden with the configuration endpoint or not. Defaults tofalse
.The adapter uses the host returned by the "CLUSTER SHARDS" (Redis >= 7) or "CLUSTER SLOTS" (Redis < 7) command. One may consider set it to
true
for tests when using Docker for example, or when Redis nodes are behind a load balancer that Redis doesn't know the endpoint of. See Redis docs for more information.The default value is
false
.:keyslot
- The module implementing theNebulex.Adapter.Keyslot
behaviour, which is used to compute the node where the command will be applied to. The default value isNebulexRedisAdapter.RedisCluster.Keyslot
.
Client-side Cluster options
The available options are:
:nodes
- Required. A keyword list of named nodes where the key is an atom as an identifier and the value is another keyword list of options (same as:conn_opts
).See "Client-side Cluster" for more information.
:keyslot
- The module implementing theNebulex.Adapter.Keyslot
behaviour, which is used to compute the node where the command will be applied to. The default value isNebulexRedisAdapter.ClientCluster.Keyslot
.
Shared runtime options
Since the adapter runs on top of Redix
, all commands accept their options
(e.g.: :timeout
, and :telemetry_metadata
). See Redix
docs for more
information.
Redis Cluster runtime options
The following options apply to all commands:
:lock_retries
- This option is specific to the:redis_cluster
mode. When the config manager is running and setting up the hash slot map, all Redis commands get blocked until the cluster is properly configured and the hash slot map is ready to use. This option defines the max retry attempts to acquire the lock and execute the command in case the configuration manager is running and all commands are locked. Defaults to:infinity
.
Custom Keyslot
As it is mentioned in the configuration options above, the :redis_cluster
and :client_side_cluster
modes have a default value for the :keyslot
option. However, you can also provide your own implementation by implementing
the Nebulex.Adapter.Keyslot
and configuring the :keyslot
option.
For example:
defmodule MyApp.ClusteredCache.Keyslot do
use Nebulex.Adapter.Keyslot
@impl true
def hash_slot(key, range) do
# your implementation goes here
end
end
And the config:
config :my_app, MyApp.ClusteredCache,
mode: :client_side_cluster,
client_side_cluster: [
keyslot: MyApp.ClusteredCache.Keyslot,
nodes: [
...
]
]
NOTE: For
:redis_cluster
mode, the:keyslot
implementation must follow the Redis cluster specification.
TTL or Expiration Time
As is explained in Nebulex.Cache
, most of the write-like functions support
the :ttl
option to define the expiration time, and it is defined in
milliseconds. Despite Redis work with seconds, the conversion logic
is handled by the adapter transparently, so when using a cache even with the
Redis adapter, be sure you pass the :ttl
option in milliseconds.
Data Types
Currently. the adapter only works with strings, which means a given Elixir
term is encoded to a binary/string before executing a command. Similarly,
a returned binary from Redis after executing a command is decoded into an
Elixir term. The encoding/decoding process is performed by the adapter
under-the-hood. However, it is possible to provide a custom serializer via the
option :serializer
. The value must be module implementing the
NebulexRedisAdapter.Serializer
behaviour.
NOTE: Support for other Redis Data Types is in the roadmap.
Queryable API
Since the queryable API is implemented by using KEYS
command,
keep in mind the following caveats:
- Only keys can be queried.
- Only strings and predefined queries are allowed as query values.
Predefined queries
nil
- All keys are returned.{:in, [term]}
- Only the keys in the given key list ([term]
) are returned. This predefined query is only supported forNebulex.Cache.delete_all/2
. This is the recommended way of doing bulk delete of keys.
Examples
iex> MyApp.RedisCache.put_all(%{
...> "firstname" => "Albert",
...> "lastname" => "Einstein",
...> "age" => 76
...> })
:ok
iex> MyApp.RedisCache.all("**name**")
["firstname", "lastname"]
iex> MyApp.RedisCache.all("a??")
["age"]
iex> MyApp.RedisCache.all()
["age", "firstname", "lastname"]
iex> stream = MyApp.RedisCache.stream("**name**")
iex> stream |> Enum.to_list()
["firstname", "lastname"]
# get the values for the returned queried keys
iex> "**name**" |> MyApp.RedisCache.all() |> MyApp.RedisCache.get_all()
%{"firstname" => "Albert", "lastname" => "Einstein"}
Deleting multiple keys at once (bulk delete)
iex> MyApp.RedisCache.delete_all({:in, ["foo", "bar"]})
2
Transactions
This adapter doesn't provide support for transactions. However, in the future,
it is planned support Redis Transactions by using the
commands MULTI
, EXEC
, DISCARD
and WATCH
.
Running Redis commands and/or pipelines
Since NebulexRedisAdapter
works on top of Redix
and provides features like
connection pools and "Redis Cluster" support, it may be seen also as a sort of
Redis client, but it is meant to be used mainly with the Nebulex cache API.
However, Redis API is quite extensive and there are a lot of useful commands
we may want to run taking advantage of the NebulexRedisAdapter
features.
Therefore, the adapter provides two additional/extended functions to the
defined cache: command!/2
and pipeline!/2
.
command!(command, opts \\ [])
iex> MyCache.command!(["LPUSH", "mylist", "world"], key: "mylist")
1
iex> MyCache.command!(["LPUSH", "mylist", "hello"], key: "mylist")
2
iex> MyCache.command!(["LRANGE", "mylist", "0", "-1"], key: "mylist")
["hello", "world"]
pipeline!(commands, opts \\ [])
iex> [
...> ["LPUSH", "mylist", "world"],
...> ["LPUSH", "mylist", "hello"],
...> ["LRANGE", "mylist", "0", "-1"]
...> ]
...> |> cache.pipeline!(key: "mylist")
[1, 2, ["hello", "world"]]
Options for command!/2
and pipeline!/2
:
:key
- It is required when used the adapter in mode:redis_cluster
or:client_side_cluster
so that the node where the commands will take place can be selected properly. For:standalone
mode is not required (optional).:name
- The name of the cache in case you are using dynamic caches, otherwise it is not required.
Since these functions run on top of Redix
, they also accept their options
(e.g.: :timeout
, and :telemetry_metadata
). See Redix
docs for more
information.
Telemetry
This adapter emits the recommended Telemetry events.
See the "Telemetry events" section in Nebulex.Cache
for more information.
Adapter-specific telemetry events for the :redis_cluster
mode
Aside from the recommended Telemetry events by Nebulex.Cache
, this adapter
exposes the following Telemetry events for the :redis_cluster
mode:
telemetry_prefix ++ [:config_manager, :setup, :start]
- This event is specific to the:redis_cluster
mode. Before the configuration manager calls Redis to set up the cluster shards, this event should be invoked.The
:measurements
map will include the following::system_time
- The current system time in native units from calling:System.system_time()
.
A Telemetry
:metadata
map including the following fields::adapter_meta
- The adapter metadata.:pid
- The configuration manager PID.
telemetry_prefix ++ [:config_manager, :setup, :stop]
- This event is specific to the:redis_cluster
mode. After the configuration manager set up the cluster shards, this event should be invoked.The
:measurements
map will include the following::duration
- The time spent configuring the cluster. The measurement is given in the:native
time unit. You can read more about it in the docs forSystem.convert_time_unit/3
.
A Telemetry
:metadata
map including the following fields::adapter_meta
- The adapter metadata.:pid
- The configuration manager PID.:status
- The cluster setup status. If the cluster was configured successfully, the status will be set to:ok
, otherwise, will be set to:error
.:error
- The status reason. When the status is:ok
, the reason is:succeeded
, otherwise, it is the error reason.
telemetry_prefix ++ [:config_manager, :setup, :exception]
- This event is specific to the:redis_cluster
mode. When an exception is raised while configuring the cluster, this event should be invoked.The
:measurements
map will include the following::duration
- The time spent configuring the cluster. The measurement is given in the:native
time unit. You can read more about it in the docs forSystem.convert_time_unit/3
.
A Telemetry
:metadata
map including the following fields::adapter_meta
- The adapter metadata.:pid
- The configuration manager PID.:kind
- The type of the error::error
,:exit
, or:throw
.:reason
- The reason of the error.:stacktrace
- The stacktrace.