-
Notifications
You must be signed in to change notification settings - Fork 2
Tune redis proxy connection capacity #1147
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
Changes from 5 commits
30004df
e4ce5d0
41be10a
fa52ca7
1f3b80d
b6f5ebf
2607b32
6c805f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -414,7 +414,7 @@ groups: | |
| | Parameter | Value | Description | | ||
| |-----------|-------|-------------| | ||
| | Redis connection pool size | 128 | Default go-redis pool size for Redis | | ||
| | ElasticKV connection pool size | 4 | Default per-leader pool; keep within the server per-peer connection limit | | ||
| | ElasticKV connection pool size | 4 | Default per-leader pool; keep within the server per-peer connection limit and leave room for dedicated sockets | | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 実装のデフォルト値とドキュメントをPRの目的に揃えてください。 この表はElasticKVのデフォルトpool sizeを4と記載していますが、PR目的は4から16へのデフォルト増加です。現在の 🤖 Prompt for AI Agents |
||
| | Dial timeout | 5s | Backend connection timeout | | ||
| | Read timeout | 3s | Backend read timeout | | ||
| | Write timeout | 3s | Backend write timeout | | ||
|
|
@@ -439,7 +439,8 @@ Recommended shutdown order: `redis-proxy -> application -> Redis / ElasticKV`. | |
| ### Secondary writes are falling behind | ||
| - Check `proxy_async_queue_depth`, `proxy_async_queue_delay_seconds`, and `proxy_async_drops_by_queue_total` before increasing concurrency. | ||
| - Check `proxy_backend_pool_pending_requests` and the `waits`/`timeouts` pool events. Pool waits mean concurrency is too high for the configured pool. | ||
| - Increase the ElasticKV pool only together with `ELASTICKV_REDIS_PER_PEER_CONNECTIONS`; keep `-secondary-write-concurrency` at or below the pool size. | ||
| - Increase the ElasticKV pool only together with `ELASTICKV_REDIS_PER_PEER_CONNECTIONS` when the proxy pool can exceed the server's per-peer cap; keep `-secondary-write-concurrency` at or below the pool size. | ||
| - For the production proxy shape that needs more backend connections, first deploy ElasticKV nodes with `ELASTICKV_REDIS_PER_PEER_CONNECTIONS=64`, then raise the proxy with `REDIS_PROXY_ELASTICKV_POOL_SIZE=16` or an explicit `-elastickv-pool-size=16`, keeping `-secondary-write-concurrency` below the pool size, for example `8`. Do not roll a larger proxy pool before the server-side cap is active on every node. | ||
| - A sustained `expired` rate means secondary throughput is below ingress. Increasing queue size only delays the loss; profile ElasticKV before raising concurrency. | ||
|
|
||
| ### High divergence count | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,8 +75,8 @@ type LeaderAwareRedisBackend struct { | |
| } | ||
|
|
||
| // NewLeaderAwareRedisBackend creates a LeaderAwareRedisBackend with the given | ||
| // seed addresses. The first seed is used as the initial target until the | ||
| // first refresh completes. At least one seed is required. | ||
| // seed addresses. The first command waits for leader discovery instead of | ||
| // sending traffic to a seed that may be down. At least one seed is required. | ||
| func NewLeaderAwareRedisBackend(seeds []string, name string, opts BackendOptions, logger *slog.Logger) *LeaderAwareRedisBackend { | ||
| return NewLeaderAwareRedisBackendWithInterval(seeds, name, opts, defaultLeaderRefreshInterval, defaultLeaderRefreshTimeout, logger) | ||
| } | ||
|
|
@@ -106,7 +106,7 @@ func NewLeaderAwareRedisBackendWithInterval(seeds []string, name string, opts Ba | |
| clients: make(map[string]*redis.Client, len(normalized)), | ||
| clientOrder: make([]string, 0, len(normalized)), | ||
| seedProtect: seedProtect, | ||
| leader: normalized[0], | ||
| leader: "", | ||
| stopCh: make(chan struct{}), | ||
| done: make(chan struct{}), | ||
| refreshCh: make(chan struct{}, 1), | ||
|
|
@@ -389,6 +389,15 @@ func (b *LeaderAwareRedisBackend) currentClient() *redis.Client { | |
| return b.clients[b.leader] | ||
| } | ||
|
|
||
| func (b *LeaderAwareRedisBackend) currentClientOrRefresh(ctx context.Context) *redis.Client { | ||
| cli := b.currentClient() | ||
| if cli != nil { | ||
| return cli | ||
| } | ||
| b.RefreshLeaderNow(ctx) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| return b.currentClient() | ||
| } | ||
|
|
||
| // Do forwards a single command to the current leader. NOTLEADER refreshes the | ||
| // cached leader for the next command, but the current command is not replayed: | ||
| // leadership-loss errors can be returned after an operation has already applied. | ||
|
|
@@ -404,7 +413,7 @@ func (b *LeaderAwareRedisBackend) Do(ctx context.Context, args ...any) *redis.Cm | |
| } | ||
|
|
||
| func (b *LeaderAwareRedisBackend) doOnce(ctx context.Context, args ...any) *redis.Cmd { | ||
| cli := b.currentClient() | ||
| cli := b.currentClientOrRefresh(ctx) | ||
| if cli == nil { | ||
| cmd := redis.NewCmd(ctx, args...) | ||
| cmd.SetErr(ErrNoLeaderBackend) | ||
|
|
@@ -426,7 +435,7 @@ func (b *LeaderAwareRedisBackend) DoWithTimeout(ctx context.Context, timeout tim | |
| } | ||
|
|
||
| func (b *LeaderAwareRedisBackend) doWithTimeoutOnce(ctx context.Context, timeout time.Duration, args ...any) *redis.Cmd { | ||
| cli := b.currentClient() | ||
| cli := b.currentClientOrRefresh(ctx) | ||
| if cli == nil { | ||
| cmd := redis.NewCmd(ctx, args...) | ||
| cmd.SetErr(ErrNoLeaderBackend) | ||
|
|
@@ -437,7 +446,7 @@ func (b *LeaderAwareRedisBackend) doWithTimeoutOnce(ctx context.Context, timeout | |
|
|
||
| // Pipeline forwards a batch to the current leader. | ||
| func (b *LeaderAwareRedisBackend) Pipeline(ctx context.Context, cmds [][]any) ([]*redis.Cmd, error) { | ||
| cli := b.currentClient() | ||
| cli := b.currentClientOrRefresh(ctx) | ||
| if cli == nil { | ||
| return nil, ErrNoLeaderBackend | ||
| } | ||
|
|
@@ -517,7 +526,7 @@ func isLeaderRefreshTransportError(err error) bool { | |
|
|
||
| // NewPubSub opens a subscribe connection on the current leader. | ||
| func (b *LeaderAwareRedisBackend) NewPubSub(ctx context.Context) *redis.PubSub { | ||
| cli := b.currentClient() | ||
| cli := b.currentClientOrRefresh(ctx) | ||
|
bootjp marked this conversation as resolved.
|
||
| if cli == nil { | ||
| return nil | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
「legacy cap」の期待値を上限8に合わせてください。
limit: 8のケースでデフォルトのプールサイズを期待しているため、プール合計が8を超える構成では Line 113 の上限検証に必ず失敗します。旧上限の回帰ケースは通常4・ブロッキング4(または上限から算出した値)を期待し、現在のデフォルト値の検証は別ケースに分離してください。修正例
📝 Committable suggestion
🤖 Prompt for AI Agents