From 83aaa160a25fac09bd16c793da16fa4359a6ffce Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 8 Oct 2026 15:05:06 +0100 Subject: [PATCH] DOC-7167 Add Redis Sentinel connection examples to client connect pages Adds a "Connect to Redis Sentinel" section after the cluster section on the nine connect.md pages (H3 on Jedis to match its neighbors). hiredis gets a short "not supported" section: v1.4.1 has no Sentinel code. Every snippet ran against a local topology (primary, replica, three Sentinels, mymaster, quorum 2) in two variants: no auth, and separate data-node and Sentinel passwords. Test copies differed from the page snippets only in ports, passwords, and key names. Versions run: redis-py 8.1.0 (GitHub tag source), go-redis v9.23.0, node-redis 6.3.0, ioredis 6.0.0, Jedis 8.0.2, Lettuce 7.8.0, StackExchange.Redis 3.0.0 (NuGet was blocked; latest is 3.3.1), Predis 3.6.1. The failover caveats are measured, not inferred. Under a forced SENTINEL FAILOVER, redis-py, ioredis (default options), a Lettuce RedisClient connection, Predis, and SE.Redis 3.0.0 kept writing to the demoted primary for about 10 s, until Sentinel reconfigured it, and the old primary discarded those acknowledged writes on resync (22 of about 60 in the measured runs). go-redis, node-redis, and Jedis subscribe to +switch-master and moved within 1-2 s; ioredis with failoverDetector cut loss to the inherent sub-second window. The .NET page deliberately has no caveat: 3.3.1 adds an IsStalePrimaryView path that may close the window, and 3.3.1 couldn't be run here (needs the .NET 10 SDK). Surprises worth knowing before editing these sections: Jedis RedisSentinelClient has no replica reads at all; Predis replica routing is sticky until the first write and the parameters username leaks to the Sentinels (hence username in each Sentinel URI); go-redis ReplicaOnly sends writes to the replica too; redis-py sentinel_kwargs stops socket_* inheritance. Learned: five of eight clients silently lose ~10 s of writes after a graceful Sentinel failover Constraint: every snippet here is run-verified (some trimmed to fragments of the tested program); re-run any edit against a real Sentinel topology Rejected: SE.Redis SentinelUser/SentinelPassword options | 3.1.13+, source-read only, never run; page uses SentinelConnect + GetSentinelMasterConnection, which ran on 3.0.0 Rejected: Jedis .serverDefaultProtocol() to silence the 8.x RESP3 WARN | method doesn't exist in 7.x Directive: add the SE.Redis failover caveat only after testing 3.3.1 or later under a forced failover Directive: link Sentinel URL forms to connection-urls.md once DOC-7165 merges; it isn't on main yet Gaps: no TLS to Sentinels tested on any client; no crash failover, only graceful SENTINEL FAILOVER; SE.Redis 3.3.1 never run Recheck: SE.Redis credentials example when the .NET 10 SDK is available to run 3.3.1 Ticket: DOC-7167 Co-Authored-By: Claude Opus 5.5 --- content/develop/clients/dotnet/connect.md | 58 ++++++++++++++++ content/develop/clients/go/connect.md | 39 +++++++++++ content/develop/clients/hiredis/connect.md | 6 ++ content/develop/clients/ioredis/connect.md | 62 +++++++++++++++++ content/develop/clients/jedis/connect.md | 62 +++++++++++++++++ content/develop/clients/lettuce/connect.md | 76 +++++++++++++++++++++ content/develop/clients/nodejs/connect.md | 71 +++++++++++++++++++ content/develop/clients/php/connect.md | 75 ++++++++++++++++++++ content/develop/clients/redis-py/connect.md | 55 +++++++++++++++ 9 files changed, 504 insertions(+) diff --git a/content/develop/clients/dotnet/connect.md b/content/develop/clients/dotnet/connect.md index 2a2e842cf1..5f9320532b 100644 --- a/content/develop/clients/dotnet/connect.md +++ b/content/develop/clients/dotnet/connect.md @@ -67,6 +67,64 @@ db.StringSet("foo", "bar"); Console.WriteLine(db.StringGet("foo")); // prints bar ``` +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +list the Sentinels in `EndPoints` and set `ServiceName` to the name of the primary that +the Sentinels monitor. The client asks the Sentinels for the current primary. + +```csharp +using StackExchange.Redis; + +ConfigurationOptions conf = new ConfigurationOptions { + EndPoints = { "localhost:26379", "localhost:26380", "localhost:26381" }, + ServiceName = "mymaster" +}; + +ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(conf); +IDatabase db = redis.GetDatabase(); + +db.StringSet("foo", "bar"); +Console.WriteLine(db.StringGet("foo")); // prints bar +``` + +You can also use a configuration string, such as +`"localhost:26379,localhost:26380,localhost:26381,serviceName=mymaster"`. + +If the Sentinels and the data nodes have different credentials, connect to the Sentinels +first with `SentinelConnect()`, using the Sentinel credentials. Then call +`GetSentinelMasterConnection()` with the credentials for the primary and replicas: + +```csharp +using StackExchange.Redis; + +// Connect to the Sentinels with the Sentinel credentials. +ConfigurationOptions sentinelConf = new ConfigurationOptions { + EndPoints = { "localhost:26379", "localhost:26380", "localhost:26381" }, + User = "yourSentinelUsername", + Password = "yourSentinelPassword" +}; +ConnectionMultiplexer sentinel = ConnectionMultiplexer.SentinelConnect(sentinelConf); + +// Connect to the primary with the Redis credentials. +ConfigurationOptions conf = new ConfigurationOptions { + ServiceName = "mymaster", + User = "yourUsername", + Password = "yourPassword" +}; +ConnectionMultiplexer redis = sentinel.GetSentinelMasterConnection(conf); +IDatabase db = redis.GetDatabase(); +``` + +The connection also includes the replicas that the Sentinels report. To read from a +replica, pass `CommandFlags.PreferReplica` (or `CommandFlags.DemandReplica`) to a read-only +command. Replication is asynchronous, so a replica can return stale data. + +```csharp +// Read from a replica if one is available, otherwise from the primary. +Console.WriteLine(db.StringGet("foo", CommandFlags.PreferReplica)); // prints bar +``` + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the [Redis security](/content/operate/oss_and_stack/management/security/_index.md) guidelines. diff --git a/content/develop/clients/go/connect.md b/content/develop/clients/go/connect.md index 49d465cc73..060d835e2e 100644 --- a/content/develop/clients/go/connect.md +++ b/content/develop/clients/go/connect.md @@ -80,6 +80,45 @@ client := redis.NewClusterClient(&redis.ClusterOptions{ }) ``` +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +use `NewFailoverClient()`. Set `MasterName` to the name of the primary that the Sentinels +monitor, and list one or more Sentinels in `SentinelAddrs`. The client asks the Sentinels +for the current primary and switches to the new one after a failover. + +```go +client := redis.NewFailoverClient(&redis.FailoverOptions{ + MasterName: "mymaster", + SentinelAddrs: []string{"localhost:26379", "localhost:26380", "localhost:26381"}, +}) +``` + +The Sentinels and the data nodes have separate credentials. Set `SentinelPassword` for the +Sentinels, and `Username` and `Password` for the primary and replicas: + +```go +client := redis.NewFailoverClient(&redis.FailoverOptions{ + MasterName: "mymaster", + SentinelAddrs: []string{"localhost:26379", "localhost:26380", "localhost:26381"}, + SentinelPassword: "sentinel-secret", // use your Sentinel password + Username: "default", // use your Redis user + Password: "secret", // use your Redis password +}) +``` + +To send commands to a replica, set `ReplicaOnly`. The client sends every command to a +random replica, including writes, which fail, so use this option only for a client that +reads: + +```go +replica := redis.NewFailoverClient(&redis.FailoverOptions{ + MasterName: "mymaster", + SentinelAddrs: []string{"localhost:26379", "localhost:26380", "localhost:26381"}, + ReplicaOnly: true, +}) +``` + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the diff --git a/content/develop/clients/hiredis/connect.md b/content/develop/clients/hiredis/connect.md index 475f0d9069..f88836976e 100644 --- a/content/develop/clients/hiredis/connect.md +++ b/content/develop/clients/hiredis/connect.md @@ -145,3 +145,9 @@ pending commands execute and activate their callbacks. Use `redisAsyncFree()` to disconnect immediately. If you do this then any pending callbacks from commands that have already executed will be called with a `NULL` reply pointer. + +## Redis Sentinel + +`hiredis` doesn't support [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md). +It has no API to find the current primary from a set of Sentinels or to reconnect after a +failover. diff --git a/content/develop/clients/ioredis/connect.md b/content/develop/clients/ioredis/connect.md index 70935592d8..d38fedbdd3 100644 --- a/content/develop/clients/ioredis/connect.md +++ b/content/develop/clients/ioredis/connect.md @@ -66,6 +66,68 @@ const redis = new Redis.Cluster([ ]); ``` +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +pass a list of Sentinels in the `sentinels` option and the name of the primary that the +Sentinels monitor in `name`. The client asks the Sentinels for the current primary. + +```js +const redis = new Redis({ + sentinels: [ + { host: "localhost", port: 26379 }, + { host: "localhost", port: 26380 }, + { host: "localhost", port: 26381 }, + ], + name: "mymaster", +}); + +await redis.set('foo', 'bar'); +const value = await redis.get('foo'); +console.log(value); // >>> bar +``` + +The Sentinels and the data nodes have separate credentials. Set `sentinelPassword` (and +`sentinelUsername`, if needed) for the Sentinels, and `username` and `password` for the +primary and replicas: + +```js +const redis = new Redis({ + sentinels: [ + { host: "localhost", port: 26379 }, + { host: "localhost", port: 26380 }, + { host: "localhost", port: 26381 }, + ], + name: "mymaster", + // Credentials for the Sentinel instances. + sentinelPassword: "my-sentinel-password", + // Credentials for the primary and replica data nodes. + username: "default", + password: "my-password", +}); +``` + +If the Sentinel password is wrong or missing, the error says that all Sentinels are +unreachable. + +By default, ioredis doesn't listen for failover announcements from the Sentinels. After a +failover, the client keeps using the old primary until Sentinel reconfigures it as a +replica and closes the connection. Any writes that the old primary accepts during that time +are lost. Set `failoverDetector: true` to switch to the new primary as soon as the Sentinels +announce it. + +To connect to a replica instead of the primary, set `role: "slave"`. The client connects to +one replica, chosen at random. Replication is asynchronous, so a replica can return stale +data. + +```js +const replica = new Redis({ + sentinels: [{ host: "localhost", port: 26379 }], + name: "mymaster", + role: "slave", +}); +``` + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the [Redis security](/content/operate/oss_and_stack/management/security/_index.md) guidelines. diff --git a/content/develop/clients/jedis/connect.md b/content/develop/clients/jedis/connect.md index e5284a0d97..b10d1d313a 100644 --- a/content/develop/clients/jedis/connect.md +++ b/content/develop/clients/jedis/connect.md @@ -76,6 +76,68 @@ jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380)); RedisClusterClient jedis = RedisClusterClient.create(jedisClusterNodes); ``` +### Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +use `RedisSentinelClient`. Pass the name of the primary that the Sentinels monitor to +`masterName()`, and the Sentinel addresses to `sentinels()`. The client asks the Sentinels +for the current primary and switches to the new one after a failover. + +```java +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.RedisSentinelClient; + +import java.util.HashSet; +import java.util.Set; + +//... + +Set sentinels = new HashSet<>(); +sentinels.add(new HostAndPort("localhost", 26379)); +sentinels.add(new HostAndPort("localhost", 26380)); +sentinels.add(new HostAndPort("localhost", 26381)); + +RedisSentinelClient jedis = RedisSentinelClient.builder() + .masterName("mymaster") + .sentinels(sentinels) + .build(); + +jedis.set("foo", "bar"); +System.out.println(jedis.get("foo")); // bar + +jedis.close(); +``` + +The Sentinels and the data nodes have separate credentials. Pass a client configuration for +the primary to `clientConfig()`, and one for the Sentinels to `sentinelClientConfig()`: + +```java +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.JedisClientConfig; + +//... + +// Credentials for the primary and replica nodes. +JedisClientConfig masterConfig = DefaultJedisClientConfig.builder() + .password("secret!") // use your Redis password + .build(); + +// Credentials for the Sentinel nodes. +JedisClientConfig sentinelConfig = DefaultJedisClientConfig.builder() + .password("sentinelSecret!") // use your Sentinel password + .build(); + +RedisSentinelClient jedis = RedisSentinelClient.builder() + .masterName("mymaster") + .sentinels(sentinels) + .clientConfig(masterConfig) + .sentinelClientConfig(sentinelConfig) + .build(); +``` + +`RedisSentinelClient` always sends commands to the primary. It doesn't support reading +from replicas. + ### Connect to your production Redis with TLS When you deploy your application, use TLS and follow the [Redis security](/content/operate/oss_and_stack/management/security/_index.md) guidelines. diff --git a/content/develop/clients/lettuce/connect.md b/content/develop/clients/lettuce/connect.md index ae8c50f807..e6889c5d70 100644 --- a/content/develop/clients/lettuce/connect.md +++ b/content/develop/clients/lettuce/connect.md @@ -66,6 +66,82 @@ try (RedisClusterClient clusterClient = RedisClusterClient.create(redisURI)) { Learn more about Cluster connections and how to configure them in [the reference guide](https://redis.github.io/lettuce/ha-sharding/#redis-cluster). +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +build a `RedisURI` with `RedisURI.Builder.sentinel()`, passing the address of one Sentinel +and the name of the primary that the Sentinels monitor. Add the other Sentinels with +`withSentinel()`. The client asks the Sentinels for the current primary. + +```java +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.sync.RedisCommands; + +//... + +RedisURI redisUri = RedisURI.Builder + .sentinel("localhost", 26379, "mymaster") + .withSentinel("localhost", 26380) + .withSentinel("localhost", 26381) + .build(); + +try (RedisClient client = RedisClient.create(redisUri)) { + StatefulRedisConnection connection = client.connect(); + RedisCommands commands = connection.sync(); + + commands.set("foo", "bar"); + System.out.println(commands.get("foo")); // >>> bar + + connection.close(); +} +``` + +The Sentinels and the data nodes have separate credentials. Pass the Sentinel password with +each Sentinel address, and set the credentials for the primary and replicas with +`withAuthentication()`: + +```java +RedisURI redisUri = RedisURI.Builder + // The password argument authenticates to each Sentinel. + .sentinel("localhost", 26379, "mymaster", "yourSentinelPassword") + .withSentinel("localhost", 26380, "yourSentinelPassword") + .withSentinel("localhost", 26381, "yourSentinelPassword") + // withAuthentication() authenticates to the primary and replicas. + .withAuthentication("default", "yourPassword") + .build(); +``` + +A `RedisClient` connection doesn't listen for failover announcements from the Sentinels. +After a failover, it keeps using the old primary until Sentinel reconfigures it as a +replica and closes the connection. Any writes that the old primary accepts during that time +are lost. + +To read from replicas, open a connection with `MasterReplica.connect()` and set a +`ReadFrom` policy. This connection also listens for failover announcements from the +Sentinels, so it switches to a new primary sooner. Replication is asynchronous, so a +replica can return stale data. + +```java +import io.lettuce.core.ReadFrom; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.masterreplica.MasterReplica; +import io.lettuce.core.masterreplica.StatefulRedisMasterReplicaConnection; + +//... + +try (RedisClient client = RedisClient.create()) { + StatefulRedisMasterReplicaConnection connection = + MasterReplica.connect(client, StringCodec.UTF8, redisUri); + connection.setReadFrom(ReadFrom.REPLICA); + + System.out.println(connection.sync().get("foo")); // >>> bar + + connection.close(); +} +``` + ## Asynchronous connection ```java diff --git a/content/develop/clients/nodejs/connect.md b/content/develop/clients/nodejs/connect.md index eef6f44f27..a2171e9fcb 100644 --- a/content/develop/clients/nodejs/connect.md +++ b/content/develop/clients/nodejs/connect.md @@ -97,6 +97,77 @@ console.log(value); // returns 'bar' await cluster.close(); ``` +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +use `createSentinel()`. Set `name` to the name of the primary that the Sentinels monitor, +and list one or more Sentinels in `sentinelRootNodes`. The client asks the Sentinels for +the current primary and switches to the new one after a failover. + +```js +import { createSentinel } from 'redis'; + +const sentinel = createSentinel({ + name: 'mymaster', + sentinelRootNodes: [ + { host: 'localhost', port: 26379 }, + { host: 'localhost', port: 26380 }, + { host: 'localhost', port: 26381 } + ] +}); + +sentinel.on('error', (err) => console.log('Redis Sentinel Error', err)); + +await sentinel.connect(); + +await sentinel.set('foo', 'bar'); +const value = await sentinel.get('foo'); +console.log(value); // returns 'bar' + +await sentinel.close(); +``` + +The Sentinels and the data nodes have separate credentials. Set the Sentinel credentials in +`sentinelClientOptions`, and the credentials for the primary and replicas in +`nodeClientOptions`: + +```js +const sentinel = createSentinel({ + name: 'mymaster', + sentinelRootNodes: [ + { host: 'localhost', port: 26379 }, + { host: 'localhost', port: 26380 }, + { host: 'localhost', port: 26381 } + ], + // Credentials for the Sentinel instances. + sentinelClientOptions: { + password: 'sentinel-secret' + }, + // Credentials for the primary and replica data nodes. + nodeClientOptions: { + username: 'default', + password: 'secret' + } +}); +``` + +Neither option accepts a `url`, so you can't use a connection string with +`createSentinel()`. + +By default, the client sends all commands to the primary. To send read-only commands such +as `GET` to the replicas, set `replicaPoolSize` to the number of connections to open to each +replica. Replication is asynchronous, so a read that follows a write can return stale data. + +```js +const sentinel = createSentinel({ + name: 'mymaster', + sentinelRootNodes: [ + { host: 'localhost', port: 26379 } + ], + replicaPoolSize: 1 +}); +``` + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the [Redis security](/content/operate/oss_and_stack/management/security/_index.md) guidelines. diff --git a/content/develop/clients/php/connect.md b/content/develop/clients/php/connect.md index 9e6d7d3b91..3ee729370b 100644 --- a/content/develop/clients/php/connect.md +++ b/content/develop/clients/php/connect.md @@ -99,6 +99,81 @@ echo $rc->get('foo'), PHP_EOL; // >>> bar ``` +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +pass a list of Sentinels as the first parameter. In `options`, set +`'replication' => 'sentinel'` and set `service` to the name of the primary that the +Sentinels monitor: + +```php +$sentinels = [ + 'tcp://localhost:26379', + 'tcp://localhost:26380', + 'tcp://localhost:26381', +]; +$options = [ + 'replication' => 'sentinel', + 'service' => 'mymaster', +]; + +$r = new PredisClient($sentinels, $options); + +echo $r->set('foo', 'bar'), PHP_EOL; +// >>> OK + +echo $r->get('foo'), PHP_EOL; +// >>> bar +``` + +The default timeout for connecting to a Sentinel is 100 milliseconds. If your Sentinels +are on remote hosts, add a longer timeout to each Sentinel address, such as +`tcp://:26379?timeout=0.5`. + +The Sentinels and the data nodes have separate credentials. Add the Sentinel credentials +to each Sentinel address, and set the credentials for the primary and replicas in the +`parameters` option. Include the Sentinel `username` even if it's `default`, because +otherwise Predis uses the `username` from `parameters` for the Sentinels too: + +```php +// Credentials for the Sentinels. +$sentinels = [ + 'tcp://localhost:26379?username=yourSentinelUsername&password=yourSentinelPassword', + 'tcp://localhost:26380?username=yourSentinelUsername&password=yourSentinelPassword', + 'tcp://localhost:26381?username=yourSentinelUsername&password=yourSentinelPassword', +]; +$options = [ + 'replication' => 'sentinel', + 'service' => 'mymaster', + // Credentials for the primary and replicas. + 'parameters' => [ + 'username' => 'yourUsername', + 'password' => 'yourPassword', + ], +]; + +$r = new PredisClient($sentinels, $options); +``` + +Predis sends read-only commands to a replica until the first write command. After that, it +sends all commands to the primary. Call `switchToSlave()` to send reads to a replica again. +Replication is asynchronous, so a replica can return stale data. + +```php +// A write command switches the client to the primary. +echo $r->set('foo', 'baz'), PHP_EOL; +// >>> OK + +// Switch back to a replica for later reads. +$r->getConnection()->switchToSlave(); +echo $r->get('foo'), PHP_EOL; +// >>> baz +``` + +Predis doesn't listen for failover announcements from the Sentinels. After a failover, the +client keeps using the old primary until Sentinel reconfigures it as a replica and closes +the connection. Any writes that the old primary accepts during that time are lost. + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the diff --git a/content/develop/clients/redis-py/connect.md b/content/develop/clients/redis-py/connect.md index 8b2837aeeb..3b68f759ca 100644 --- a/content/develop/clients/redis-py/connect.md +++ b/content/develop/clients/redis-py/connect.md @@ -67,6 +67,61 @@ rc.get('foo') ``` For more information, see [redis-py Clustering](https://redis.readthedocs.io/en/stable/clustering.html). +## Connect to Redis Sentinel + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +create a `Sentinel` object with a list of Sentinel addresses. Then call `master_for()` with +the name of the primary that the Sentinels monitor. The client asks the Sentinels for the +current address of the primary. + +```python +from redis.sentinel import Sentinel + +sentinel = Sentinel([('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]) +r = sentinel.master_for('mymaster', decode_responses=True) + +r.set('foo', 'bar') +# True + +r.get('foo') +# bar +``` + +The Sentinels and the data nodes have separate credentials. Pass the Sentinel credentials +in `sentinel_kwargs`, and the credentials for the primary and replicas to `master_for()`: + +```python +from redis.sentinel import Sentinel + +sentinel = Sentinel( + [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)], + sentinel_kwargs={'password': 'sentinel-secret'}, # use your Sentinel password +) +r = sentinel.master_for( + 'mymaster', + username='default', # use your Redis user + password='secret', # use your Redis password + decode_responses=True, +) +``` + +If you set `sentinel_kwargs`, the Sentinel connections don't inherit `socket_timeout` or the +other `socket_*` options, so add any that you need to `sentinel_kwargs`. + +To send read-only commands to a replica, use `slave_for()`. Replication is asynchronous, so +a replica can return stale data. + +```python +replica = sentinel.slave_for('mymaster', decode_responses=True) + +replica.get('foo') +# bar +``` + +redis-py doesn't listen for failover announcements from the Sentinels. After a failover, +the client keeps using the old primary until Sentinel reconfigures it as a replica and it +starts rejecting writes. Any writes that the old primary accepts during that time are lost. + ## Connect to your production Redis with TLS When you deploy your application, use TLS and follow the [Redis security](/content/operate/oss_and_stack/management/security/_index.md) guidelines.