Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions content/develop/connect/clients/dotnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dotnet add package NRedisStack

Connect to localhost on port 6379.

```
```csharp
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;
Expand Down Expand Up @@ -70,7 +70,7 @@ Console.WriteLine(String.Join("; ", hashFields));
// name: John; surname: Smith; company: Redis; age: 29
```

To access Redis Stack capabilities, you should use appropriate interface like this:
To access Redis Stack capabilities, use the appropriate interface like this:

```
IBloomCommands bf = db.BF();
Expand All @@ -84,7 +84,7 @@ IJsonCommands json = db.JSON();
ITimeSeriesCommands ts = db.TS();
```

### Connect to a Redis cluster
## Connect to a Redis cluster

To connect to a Redis cluster, you just need to specify one or all cluster endpoints in the client configuration:

Expand All @@ -106,7 +106,7 @@ db.StringSet("foo", "bar");
Console.WriteLine(db.StringGet("foo")); // prints bar
```

### Connect to your production Redis with TLS
## Connect to your production Redis with TLS

When you deploy your application, use TLS and follow the [Redis security]({{< relref "/operate/oss_and_stack/management/security/" >}}) guidelines.

Expand Down Expand Up @@ -169,6 +169,23 @@ conn.StringSet("foo", "bar");
Console.WriteLine(conn.StringGet("foo"));
```

## Multiplexing

Although example code typically works with a single connection,
real-world code often uses multiple connections at the same time.
Opening and closing connections repeatedly is inefficient, so it is best
to manage open connections carefully to avoid this.

Several other
Redis client libraries use *connection pools* to reuse a set of open
connections efficiently. NRedisStack uses a different approach called
*multiplexing*, which sends all client commands and responses over a
single connection. NRedisStack manages multiplexing for you automatically.
This gives high performance without requiring any extra coding.
See
[Connection pools and multiplexing]({{< relref "/develop/connect/clients/pools-and-muxing" >}})
for more information.

## Example: Indexing and querying JSON documents

This example shows how to convert Redis search results to JSON format using `NRedisStack`.
Expand Down
103 changes: 72 additions & 31 deletions content/develop/connect/clients/java/jedis.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,46 +56,36 @@ To include `Jedis` as a dependency in your application, edit the dependency file

## Connect

For many applications, it's best to use a connection pool. You can instantiate and use a `Jedis` connection pool like so:
The following code opens a basic connection to a local Redis server:

```java
package org.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.UnifiedJedis;

public class Main {
public static void main(String[] args) {
JedisPool pool = new JedisPool("localhost", 6379);
UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");

try (Jedis jedis = pool.getResource()) {
// Store & Retrieve a simple string
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints bar

// Store & Retrieve a HashMap
Map<String, String> hash = new HashMap<>();;
hash.put("name", "John");
hash.put("surname", "Smith");
hash.put("company", "Redis");
hash.put("age", "29");
jedis.hset("user-session:123", hash);
System.out.println(jedis.hgetAll("user-session:123"));
// Prints: {name=John, surname=Smith, company=Redis, age=29}
}
// Code that interacts with Redis...

jedis.close();
}
}
```

Because adding a `try-with-resources` block for each command can be cumbersome, consider using `JedisPooled` as an easier way to pool connections.
When you have connected, you can check the connection by storing and
retrieving a simple string value:

```java
import redis.clients.jedis.JedisPooled;
...

//...
String res1 = jedis.set("bike:1", "Deimos");
System.out.println(res1); // OK

JedisPooled jedis = new JedisPooled("localhost", 6379);
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints "bar"
String res2 = jedis.get("bike:1");
System.out.println(res2); // Deimos

...
```

### Connect to a Redis cluster
Expand Down Expand Up @@ -313,15 +303,61 @@ The client will also flush the cache automatically
if any connection (including one from a connection pool)
is disconnected.

## Production usage
## Connect with a connection pool

The following sections explain how to handle situations that may occur
in your production environment.
For production usage, you should use a connection pool to manage
connections rather than opening and closing connections individually.
A connection pool maintains several open connections and reuses them
efficiently. When you open a connection from a pool, the pool allocates you
one of its open connections. When you subsequently close the same connection,
it is not actually closed but simply returned to the pool for reuse.
This avoids the overhead of repeated connecting and disconnecting.
See
[Connection pools and multiplexing]({{< relref "/develop/connect/clients/pools-and-muxing" >}})
for more information.

Use the following code to connect with a connection pool:

```java
package org.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class Main {
public static void main(String[] args) {
JedisPool pool = new JedisPool("localhost", 6379);

try (Jedis jedis = pool.getResource()) {
// Store & Retrieve a simple string
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints bar

// Store & Retrieve a HashMap
Map<String, String> hash = new HashMap<>();;
hash.put("name", "John");
hash.put("surname", "Smith");
hash.put("company", "Redis");
hash.put("age", "29");
jedis.hset("user-session:123", hash);
System.out.println(jedis.hgetAll("user-session:123"));
// Prints: {name=John, surname=Smith, company=Redis, age=29}
}
}
}
```

Because adding a `try-with-resources` block for each command can be cumbersome, consider using `JedisPooled` as an easier way to pool connections. `JedisPooled`, added in Jedis version 4.0.0, provides capabilities similar to `JedisPool` but with a more straightforward API.

```java
import redis.clients.jedis.JedisPooled;

//...

### Configuring a connection pool
JedisPooled jedis = new JedisPooled("localhost", 6379);
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints "bar"
```

As mentioned in the previous section, use `JedisPool` or `JedisPooled` to create a connection pool.
`JedisPooled`, added in Jedis version 4.0.0, provides capabilities similar to `JedisPool` but with a more straightforward API.
A connection pool holds a specified number of connections, creates more connections when necessary, and terminates them when they are no longer needed.

Here is a simplified connection lifecycle in a pool:
Expand Down Expand Up @@ -367,6 +403,11 @@ poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
JedisPooled jedis = new JedisPooled(poolConfig, "localhost", 6379);
```

## Production usage

The following sections explain how to handle situations that may occur
in your production environment.

### Timeouts

To set a timeout for a connection, use the `JedisPooled` or `JedisPool` constructor with the `timeout` parameter, or use `JedisClientConfig` with the `socketTimeout` and `connectionTimeout` parameters:
Expand Down
3 changes: 3 additions & 0 deletions content/develop/connect/clients/java/lettuce.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ try (RedisClient client = RedisClient.create(redisURI)) {

A typical approach with Lettuce is to create a single `RedisClient` instance and reuse it to establish connections to your Redis server(s).
These connections are multiplexed; that is, multiple commands can be run concurrently over a single or a small set of connections, making explicit pooling less practical.
See
[Connection pools and multiplexing]({{< relref "/develop/connect/clients/pools-and-muxing" >}})
for more information.

Lettuce provides pool config to be used with Lettuce asynchronous connection methods.

Expand Down
80 changes: 80 additions & 0 deletions content/develop/connect/clients/pools-and-muxing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
categories:
- docs
- develop
- stack
- oss
- rs
- rc
- oss
- kubernetes
- clients
description: Manage Redis connections efficiently
linkTitle: Pooling/multiplexing
title: Connection pools and multiplexing
weight: 10
---

Redis example code generally opens a connection, demonstrates
a command or feature and then closes. Real-world code typically
has short bursts of communication with the server and periods of
inactivity in between. Opening and closing connections
involves some overhead and leads to inefficiency if you do
it frequently. This means that you can improve the performance of production
code by making as few separate connections as possible.

Managing connections in your own code can be tricky, so the Redis
client libraries give you some help. The two basic approaches to
connection management are called *connection pooling* and *multiplexing*.
The [`redis-py`]({{< relref "/develop/connect/clients/python/redis-py" >}}),
[`jedis`]({{< relref "/develop/connect/clients/java/jedis" >}}), and
[`go-redis`]({{< relref "/develop/connect/clients/go" >}}) clients support
connection pooling, while
[`NRedisStack`]({{< relref "/develop/connect/clients/dotnet" >}})
supports multiplexing.
[`Lettuce`]({{< relref "/develop/connect/clients/java/lettuce" >}})
supports both approaches.

## Connection pooling

When you initialize a connection pool, the client opens a small number
of connections and adds them to the pool.

{{< image filename="/images/dev/connect/pool-and-mux/ConnPoolInit.drawio.svg" >}}

Each time you "open" a connection
from the pool, the client actually justs returns one of these existing
connections and notes the fact that it is in use.

{{< image filename="/images/dev/connect/pool-and-mux/ConnPoolInUse.drawio.svg" >}}

When you later "close"
the connection, the client puts it back into the pool of available
connections without actually closing it.

{{< image filename="/images/dev/connect/pool-and-mux/ConnPoolDiscon.drawio.svg" >}}

If all connections in the pool are in use but the app needs more then
the client can simply open new ones as necessary. In this way, the client
eventually finds the right number of connections to satisfy your
app's demands.

## Multiplexing

Instead of pooling several connections, a multiplexer keeps a
single connection open and uses it for all traffic between the
client and the server. The "connections" returned to your code are
simply to identify where to send the response data from your commands.

{{< image filename="/images/dev/connect/pool-and-mux/ConnMux.drawio.svg" >}}

Note that it is not a problem if the multiplexer receives several commands close
together in time. When this happens, the multiplexer can often combine the commands into a
[pipeline]({{< relref "/develop/use/pipelining" >}}), which
improves efficiency even more.

Multiplexing offers high efficiency but works transparently without requiring
any special code to enable it in your app. The main disadvantage of multiplexing compared to
connection pooling is that it can't support the blocking "pop" commands (such as
[`BLPOP`]({{< relref "/commands/blpop" >}})) since these would stall the
connection for all callers.
34 changes: 34 additions & 0 deletions content/develop/connect/clients/python/redis-py.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,40 @@ The client will also flush the cache automatically
if any connection (including one from a connection pool)
is disconnected.

## Connect with a connection pool

For production usage, you should use a connection pool to manage
connections rather than opening and closing connections individually.
A connection pool maintains several open connections and reuses them
efficiently. When you open a connection from a pool, the pool allocates you
one of its open connections. When you subsequently close the same connection,
it is not actually closed but simply returned to the pool for reuse.
This avoids the overhead of repeated connecting and disconnecting.
See
[Connection pools and multiplexing]({{< relref "/develop/connect/clients/pools-and-muxing" >}})
for more information.

Use the following code to connect with a connection pool:

```python
import redis

pool = redis.ConnectionPool().from_url("redis://localhost")
r1 = redis.Redis().from_pool(pool)
r2 = redis.Redis().from_pool(pool)
r3 = redis.Redis().from_pool(pool)

r1.set("wind:1", "Hurricane")
r2.set("wind:2", "Tornado")
r3.set("wind:3", "Mistral")

r1.close()
r2.close()
r3.close()

pool.close()
```

## Example: Indexing and querying JSON documents

Make sure that you have Redis Stack and `redis-py` installed. Import dependencies:
Expand Down
Loading
Loading