File: README.md

package info (click to toggle)
ruby-redis 5.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,160 kB
  • sloc: ruby: 11,445; makefile: 117; sh: 24
file content (101 lines) | stat: -rw-r--r-- 3,893 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# Redis::Cluster

## Getting started

Install with:

```
$ gem install redis-clustering
```

You can connect to Redis by instantiating the `Redis::Cluster` class:

```ruby
require "redis-clustering"

redis = Redis::Cluster.new(nodes: (7000..7005).map { |port| "redis://127.0.0.1:#{port}" })
```

NB: Both `redis_cluster` and `redis-cluster` are unrelated and abandoned gems.

```ruby
# Nodes can be passed to the client as an array of connection URLs.
nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
redis = Redis::Cluster.new(nodes: nodes)

# You can also specify the options as a Hash. The options are the same as for a single server connection.
(7000..7005).map { |port| { host: '127.0.0.1', port: port } }
```

You can also specify only a subset of the nodes, and the client will discover the missing ones using the [CLUSTER NODES](https://redis.io/commands/cluster-nodes) command.

```ruby
Redis::Cluster.new(nodes: %w[redis://127.0.0.1:7000])
```

If you want [the connection to be able to read from any replica](https://redis.io/commands/readonly), you must pass the `replica: true`. Note that this connection won't be usable to write keys.

```ruby
Redis::Cluster.new(nodes: nodes, replica: true)
```

Also, you can specify the `:replica_affinity` option if you want to prevent accessing cross availability zones.

```ruby
Redis::Cluster.new(nodes: nodes, replica: true, replica_affinity: :latency)
```

The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).

```ruby
redis = Redis::Cluster.new(nodes: %w[redis://127.0.0.1:7000])

redis.mget('key1', 'key2')
#=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)

redis.mget('{key}1', '{key}2')
#=> [nil, nil]
```

* The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
* The client support permanent node failures, and will reroute requests to promoted slaves.
* The client supports `MOVED` and `ASK` redirections transparently.

## Cluster mode with SSL/TLS
Since Redis can return FQDN of nodes in reply to client since `7.*` with CLUSTER commands, we can use cluster feature with SSL/TLS connection like this:

```ruby
Redis::Cluster.new(nodes: %w[rediss://foo.example.com:6379])
```

On the other hand, in Redis versions prior to `6.*`, you can specify options like the following if cluster mode is enabled and client has to connect to nodes via single endpoint with SSL/TLS.

```ruby
Redis::Cluster.new(nodes: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
```

In case of the above architecture, if you don't pass the `fixed_hostname` option to the client and servers return IP addresses of nodes, the client may fail to verify certificates.

## Transaction with an optimistic locking
Since Redis cluster is a distributed system, several behaviors are different from a standalone server.
Client libraries can make them compatible up to a point, but a part of features needs some restrictions.
Especially, some cautions are needed to use the transaction feature with an optimistic locking.

```ruby
# The client is an instance of the internal adapter for the optimistic locking
redis.watch("{my}key") do |client|
  if client.get("{my}key") == "some value"
    # The tx is an instance of the internal adapter for the transaction
    client.multi do |tx|
      tx.set("{my}key", "other value")
      tx.incr("{my}counter")
    end
  else
    client.unwatch
  end
end
```

In a cluster mode client, you need to pass a block if you call the watch method and you need to specify an argument to the block.
Also, you should use the block argument as a receiver to call commands in the block.
Although the above restrictions are needed, this implementations is compatible with a standalone client.