Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 6 additions & 5 deletions content/develop/clients/go/autopipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,23 +141,24 @@ The configuration options are:
| Field | Description |
| :---- | :---------- |
| `MaxBatchSize` | Target number of commands the engine coalesces into a single pipeline before flushing. This is a soft threshold rather than a hard cap, so a busy queue can flush a larger batch. Defaults to 200. |
| `MaxBatchBytes` | Soft limit on the total size of arguments (in bytes) for a batch, so that large values flush as several bounded writes instead of one very large one. Defaults to 0, meaning no byte limit. |
| `MaxBatchBytes` | Soft limit on the total size of arguments (in bytes) for a batch, so that large values flush as several bounded writes instead of one very large one. Defaults to 128 KiB in v9.23.0 or later. In v9.22.0, the default is 0, meaning no byte limit. |
| `MaxFlushDelay` | Maximum time the engine waits to accumulate more commands before flushing a batch. Larger values build deeper pipelines at the cost of latency. Defaults to 0, which adds no accumulation wait. |
| `AdaptiveDelay` | Scales `MaxFlushDelay` down as the queue fills, so a busy queue flushes sooner. Requires `MaxFlushDelay` to be greater than 0. Defaults to `false`. |
| `MaxConcurrentBatches` | Number of batches that may execute at once. Defaults to 1, which gives a single ordered stream. Values greater than 1 require `Unordered` set to `true` because concurrent batches do not preserve a single ordered stream. |
| `Unordered` | Allows commands to execute without preserving a single ordered stream, which enables higher concurrency. |
| `NumShards` | Number of independent command queues, or shards, that the engine flushes separately. Defaults to 0, meaning a single shard, which funnels every caller into one queue so batches stay deep. Cluster clients default to several slot-routed shards instead. With `AsyncAutoPipeline()`, values greater than 1 require `Unordered` to be set to `true`. |
| `MaxQueuedCommands` | Maximum number of commands the autopipeliner has accepted but not yet completed. A command submitted at the limit fails immediately with `ErrAutoPipelineQueueFull` instead of being queued, which bounds client memory when the server is slower than your goroutines. Because each command is rejected separately, a later command can succeed after an earlier one failed, so check the error of any command that a later one depends on. Defaults to 0, meaning no limit. Requires v9.23.0 or later. |

`MaxBatchSize` is the one default that differs between the two methods. If you
set no options at all, `AutoPipeline()` uses a built-in preset that targets 300
commands instead of 200. As soon as you supply `AutoPipelineOptions`, either on
the client or to `AutoPipelineWithOptions()`, that preset no longer applies, and
a `MaxBatchSize` you leave unset means 200.

Connection and buffer tuning is not part of `AutoPipelineOptions`. Batches use
the client's pipeline connections, which you size with the
`PipelineReadBufferSize`, `PipelineWriteBufferSize`, and `PipelinePoolSize`
fields of the client's options.
Connection and buffer tuning is not part of `AutoPipelineOptions`. Batches run
on the client's separate pipeline connection pool, which you size with the
fields described in
[Connection pooling](/content/develop/clients/go/produsage.md#connection-pooling).

Each client holds at most two autopipeliners: one for the blocking method and
one for the asynchronous method. Each of them is a
Expand Down
64 changes: 63 additions & 1 deletion content/develop/clients/go/produsage.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ progress in implementing the recommendations.
- [ ] [Monitor performance and errors](#monitor-performance-and-errors)
- [ ] [Retries](#retries)
- [ ] [Timeouts](#timeouts)
- [ ] [Smart client handoffs](#seamless-client-experience)
- [ ] [Connection pooling](#connection-pooling)
- [ ] [Smart client handoffs](#smart-client-handoffs)
```

## Recommendations
Expand Down Expand Up @@ -127,6 +128,67 @@ might retry commands that would have succeeded if given more time. However,
if they are too long, your app might hang unnecessarily while waiting for a
response that will never arrive.

### Connection pooling

`go-redis` manages connections for you with a
[connection pool](/content/develop/clients/pools-and-muxing.md), so your
app doesn't have to cache and reuse open connections itself. The `PoolSize`
field of `Options` sets the number of
connections the main pool keeps (with a default of ten times the value of `GOMAXPROCS`). `MinIdleConns` sets how many
connections to open before your app asks for them, `MaxActiveConns` caps the
total number of connections, and `PoolTimeout` sets how long a command waits
for a free connection. By default, no connections are opened in advance, the
total is uncapped, and a command waits one second longer than `ReadTimeout`.

By default, pipelines don't use the main pool. In go-redis v9.23.0 or later,
every client also creates a separate *pipeline pool* that
[pipelines and transactions](/content/develop/clients/go/transpipe.md) and
[automatic pipelining](/content/develop/clients/go/autopipeline.md) use
for each batch they run. This prevents a burst of batches from competing with your
ordinary commands for the same connections.

Use the following fields of `Options` to size the pipeline pool:

| Field | Description |
| :---- | :---------- |
| `PipelinePoolSize` | Number of connections the pipeline pool keeps. Defaults to 10. Set it to `0` to use the default number of connections, or to `-1` to disable the separate pipeline pool (which means connections are allocated to pipelines from the main pool). |
| `PipelineReadBufferSize` | Size of the read buffer for each pipeline connection. Defaults to the larger of `ReadBufferSize` and 128 KiB, because a batch of commands can return many replies in a single round trip. If the value is set smaller than the minimum required by the [RESP3](/content/develop/reference/protocol-spec.md#resp-versions) protocol for push messages then that minimum is used instead. |
| `PipelineWriteBufferSize` | Size of the write buffer for each pipeline connection. Defaults to the larger of `WriteBufferSize` and 128 KiB. |

The pipeline pool costs you nothing while you are not using pipelining. It never opens
connections in advance regardless of the value of `MinIdleConns`, so an idle pipeline
pool holds no connections at all. Also, it doesn't use
`MaxActiveConns` as its upper limit (which would double the number of connections your client can
open). The limit is instead the value of `MaxActiveConns` plus `PipelinePoolSize`.
`ClusterClient` and `Ring` create a pipeline pool for each node, so this limit
applies for each node rather than for each client.

If every pipeline connection is busy, a batch runs on the main pool straight away
rather than waiting for a pipeline connection. A burst of batches wider than
`PipelinePoolSize` therefore opens extra connections in the main pool, which
still applies the `MaxActiveConns` limit. A `Limiter` counts such a batch once
rather than twice.

You can find out the current size of the pipeline pool using the `PipelineStats`
field from the client's pool statistics:

```go
stats := client.PoolStats()
fmt.Printf("Main pool connections: %d, hits: %d, misses: %d\n",
stats.TotalConns, stats.Hits, stats.Misses)
if ps := stats.PipelineStats; ps != nil {
fmt.Printf("Pipeline pool connections: %d, hits: %d, misses: %d\n",
ps.TotalConns, ps.Hits, ps.Misses)
}
```

No field counts the batches that run on the main pool, and they don't appear
as timeouts. If `PipelineStats.TotalConns` stays at `PipelinePoolSize` while the
main pool's `TotalConns` grows during bursts of batches, increase
`PipelinePoolSize`. Note that `PipelineStats` is `nil` when you disable the
pipeline pool (by setting `PipelinePoolSize` to `-1`). It also combines
the figures from every node for `ClusterClient` and `Ring` into the same count.

### Smart client handoffs

*Smart client handoffs (SCH)* is a feature of Redis Cloud and
Expand Down
6 changes: 6 additions & 0 deletions content/develop/clients/go/transpipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ If you want the client to batch concurrent commands into pipelines for you
without writing any pipeline code, see
[Automatic pipelining](/content/develop/clients/go/autopipeline.md).

Both types of batch run on a separate pool of connections that the client keeps
for them, so a burst of batches doesn't compete with your ordinary commands for
the same connections. See
[Connection pooling](/content/develop/clients/go/produsage.md#connection-pooling)
for how to size that pool.

## Execute a pipeline

To execute commands in a pipeline, you first create a pipeline object
Expand Down
Loading