Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert wiki to markdown docs #2944

Merged
merged 12 commits into from
Aug 21, 2024
2,686 changes: 2,686 additions & 0 deletions docs/Advanced-usage.md

Large diffs are not rendered by default.

2,139 changes: 2,139 additions & 0 deletions docs/Connecting-Redis.md

Large diffs are not rendered by default.

171 changes: 171 additions & 0 deletions docs/Frequently-Asked-Questions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Frequently Asked Questions

## I’m seeing `RedisCommandTimeoutException`

**Symptoms:**

`RedisCommandTimeoutException` with a stack trace like:

io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51)
at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:114)
at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:69)
at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
at com.sun.proxy.$Proxy94.set(Unknown Source)

**Diagnosis:**

1. Check the debug log (log level `DEBUG` or `TRACE` for the logger
`io.lettuce.core.protocol`)

2. Take a Thread dump to investigate Thread activity

3. Investigate Lettuce usage, specifically for
`setAutoFlushCommands(false)` calls

4. Do you use a custom `RedisCodec`?

**Cause:**

Command timeouts are caused by the fact that a command was not completed
within the configured timeout. Timeouts may be caused for various
reasons:

1. Redis server has crashed/network partition happened and your Redis
service didn’t recover within the configured timeout

2. Command was not finished in time. This can happen if your Redis
server is overloaded or if the connection is blocked by a command
(e.g. `BLPOP 0`, long-running Lua script). See also
[gives](#blpopdurationzero--gives-rediscommandtimeoutexception).

3. Configured timeout does not match Redis’s performance.

4. If you block the `EventLoop` (e.g. calling blocking methods in a
`RedisFuture` callback or in a Reactive pipeline). That can easily
happen when calling Redis commands in a Pub/Sub listener or a
`RedisConnectionStateListener`.

5. If you manually control the flushing behavior of commands
(`setAutoFlushCommands(true/false)`), you should have a good reason
to do so. In multi-threaded environments, race conditions may easily
happen, and commands are not flushed. Updating a missing or
misplaced `flushCommands()` call might solve the problem.

6. If you’re using a custom `RedisCodec` that can fail during encoding,
this will desynchronize the protocol state.

**Action:**

Check for the causes above. If the configured timeout does not match
your Redis latency characteristics, consider increasing the timeout.
Never block the `EventLoop` from your code. Make sure that your
`RedisCodec` doesn’t fail on encode.

## `blpop(Duration.ZERO, …)` gives `RedisCommandTimeoutException`

**Symptoms:**

Calling `blpop`, `brpop` or any other blocking command followed by
`RedisCommandTimeoutException` with a stack trace like:

io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51)
at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:114)
at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:69)
at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
at com.sun.proxy.$Proxy94.set(Unknown Source)

**Cause:**

The configured command timeout applies without considering
command-specific timeouts.

**Action:**

There are various options:

1. Configure a higher default timeout.

2. Consider a timeout that meets the default timeout when calling
blocking commands.

3. Configure `TimeoutOptions` with a custom `TimeoutSource`

``` java
TimeoutOptions timeoutOptions = TimeoutOptions.builder().timeoutSource(new TimeoutSource() {
@Override
public long getTimeout(RedisCommand<?, ?, ?> command) {

if (command.getType() == CommandType.BLPOP) {
return TimeUnit.MILLISECONDS.toNanos(CommandArgsAccessor.getFirstInteger(command.getArgs()));
}

// -1 indicates fallback to the default timeout
return -1;
}
}).build();
```

Note that commands that timed out may block the connection until either
the timeout exceeds or Redis sends a response.

## Excessive Memory Usage or `RedisException` while disconnected

**Symptoms:**

`RedisException` with one of the following messages:

io.lettuce.core.RedisException: Request queue size exceeded: n. Commands are not accepted until the queue size drops.

io.lettuce.core.RedisException: Internal stack size exceeded: n. Commands are not accepted until the stack size drops.

Or excessive memory allocation.

**Diagnosis:**

1. Check Redis connectivity

2. Inspect memory usage

**Cause:**

Lettuce auto-reconnects by default to Redis to minimize service
disruption. Commands issued while there’s no Redis connection are
buffered and replayed once the server connection is reestablished. By
default, the queue is unbounded which can lead to memory exhaustion.

**Action:**

You can configure disconnected behavior and the request queue size
through `ClientOptions` for your workload profile. See [Client
Options](Advanced-usage.md#client-options) for further reference.

## Performance Degradation using the Reactive API with a single connection

**Symptoms:**

Performance degradation when using the Reactive API with a single
connection (i.e. non-pooled connection arrangement).

**Diagnosis:**

1. Inspect Thread affinity of reactive signals

**Cause:**

Netty’s threading model assigns a single Thread to each connection which
makes I/O for a single `Channel` effectively single-threaded. With a
significant computation load and without further thread switching, the
system leverages a single thread and therefore leads to contention.

**Action:**

You can configure signal multiplexing for the reactive API through
`ClientOptions` by enabling `publishOnScheduler(true)`. See [Client
Options](Advanced-usage.md#client-options) for further reference. Alternatively, you can
configure `Scheduler` on each result stream through
`publishOn(Scheduler)`. Note that the asynchronous API features the same
behavior and you might want to use `then…Async(…)`, `run…Async(…)`,
`apply…Async(…)`, or `handleAsync(…)` methods along with an `Executor`
object.
94 changes: 94 additions & 0 deletions docs/Getting-Started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Getting Started

You can get started with Lettuce in various ways.

## 1. Get it

### For Maven users

Add these lines to file pom.xml:

``` xml
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.2.RELEASE</version>
uglide marked this conversation as resolved.
Show resolved Hide resolved
</dependency>
```

### For Ivy users

Add these lines to file ivy.xml:

``` xml
<ivy-module>
<dependencies>
<dependency org="io.lettuce" name="lettuce-core" rev="6.3.2.RELEASE"/>
uglide marked this conversation as resolved.
Show resolved Hide resolved
</dependencies>
</ivy-module>
```

### For Gradle users

Add these lines to file build.gradle:

``` groovy
dependencies {
implementation 'io.lettuce:lettuce-core:6.3.2.RELEASE'
uglide marked this conversation as resolved.
Show resolved Hide resolved
}
```

### Plain Java

Download the latest binary package from
<https://github.com/redis/lettuce/releases> and extract the
archive.

## 2. Start coding

So easy! No more boring routines, we can start.

Import required classes:

``` java
import io.lettuce.core.*;
```

and now, write your code:

``` java
RedisClient redisClient = RedisClient.create("redis://password@localhost:6379/0");
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> syncCommands = connection.sync();

syncCommands.set("key", "Hello, Redis!");

connection.close();
redisClient.shutdown();
```

Done!

Do you want to see working examples?

- [Standalone
Redis](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToRedis.java)

- [Standalone Redis with
SSL](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToRedisSSL.java)

- [Redis
Sentinel](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToRedisUsingRedisSentinel.java)

- [Redis
Cluster](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToRedisCluster.java)

- [Connecting to a ElastiCache
Master](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToElastiCacheMaster.java)

- [Connecting to ElastiCache with
Master/Replica](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java)

- [Connecting to Azure Redis
Cluster](https://github.com/redis/lettuce/blob/6.3.2.RELEASE/src/test/java/io/lettuce/examples/ConnectToRedisClusterSSL.java)

Loading
Loading