Skip to content

feat: support redis multi mode#1788

Merged
looplj merged 7 commits into
looplj:unstablefrom
wangYX657211334:feature/redis_multi_mode
Jun 7, 2026
Merged

feat: support redis multi mode#1788
looplj merged 7 commits into
looplj:unstablefrom
wangYX657211334:feature/redis_multi_mode

Conversation

@wangYX657211334

Copy link
Copy Markdown
Contributor

需求背景
当前 AxonHub 仅支持单机模式的 Redis 连接,该架构存在明显的单点故障风险。

主要修改

  • 统一客户端接口:内部改用 UniversalClient 创建 Redis 客户端,该接口统一支持单机模式(Client)、集群模式(ClusterClient)、哨兵模式(FailoverClient/FailoverClusterClient),实现多模式无缝切换。
  • 增强配置灵活性:扩展 URL 连接串的参数解析能力,支持通过 DSN 配置更丰富的连接参数(如连接池大小、超时时间、集群地址等)。
  • 保证向后兼容:完全兼容旧版本的单机配置方式,用户无需修改现有配置文件即可平滑升级。

业务价值

  • 核心收益 - 高可用保障:通过支持哨兵模式(Sentinel)和集群模式(Cluster),实现 Redis 节点的自动故障检测与转移,从根本上消除了单点故障风险,确保缓存服务在生产环境中的持续可用。
  • 可扩展性提升:集群模式支持数据分片,打破了单机 Redis 的内存和性能瓶颈,使 AxonHub 能够平滑支撑未来更大规模的业务流量。

@wangYX657211334 wangYX657211334 changed the title support redis multi mode feat: support redis multi mode Jun 5, 2026
@greptile-apps

greptile-apps Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the single-node Redis client (*redis.Client) with redis.UniversalClient throughout the codebase, enabling standalone, Sentinel, and Cluster modes through a unified interface. It also introduces a custom URL query-param parser (ParseUniversalURL) that maps a rich set of connection parameters (pool size, timeouts, routing flags, etc.) directly from the DSN, and adds new config fields (addrs, master_name, sentinel_username/password, route_by_latency, route_randomly, is_cluster_mode) with full backward compatibility for the deprecated addr field.

  • Client layer (xredis/client.go): newUniversalOptions applies a clear precedence — URL body → URL query params → addr config → addrs config — before handing off to redis.NewUniversalClient, which auto-selects the right client type based on MasterName and IsClusterMode / address count.
  • API surface (xcache, watcher): All public functions widened to redis.UniversalClient; NewRedisWithOptions updated to accept *redis.UniversalOptions.
  • Documentation: New mode-specific examples and a full URL parameter reference table are added to both English and Chinese docs, but the Docker Compose deployment example block combines all three modes under a single YAML mapping, producing duplicate keys that most parsers will silently collapse to the last value.

Confidence Score: 3/5

The core client logic and backward compatibility are solid, but two pre-existing regressions from earlier review rounds remain unresolved in client.go, and the new documentation deployment example actively misleads users by placing all three mode configs under the same YAML block with conflicting duplicate keys.

The duplicate-key documentation bug is not merely cosmetic — a user following the deployment guide and copying the combined block would silently connect to cluster mode regardless of intent. The two client.go issues flagged in prior rounds (TLSInsecureSkipVerify regression for rediss:// + config flag, and undetected unknown URL params) also remain open. The implementation itself is architecturally sound and well-tested.

docs/en/deployment/configuration.md and docs/zh/deployment/configuration.md (duplicate-key deployment example); internal/pkg/xredis/client.go (open regressions from prior review rounds)

Important Files Changed

Filename Overview
internal/pkg/xredis/client.go Core change: replaces redis.Options with UniversalOptions and adds ParseUniversalURL with rich query-param parsing. Two confirmed bugs: (1) cfg.TLSInsecureSkipVerify is silently ignored when using a rediss:// URL without cfg.TLS=true; (2) unknown URL query parameters are swallowed without error (both flagged in prior review rounds).
internal/pkg/xredis/config.go Adds new config fields for multi-mode support (Addrs, MasterName, SentinelUsername/Password, RouteByLatency, RouteRandomly, IsClusterMode). Uses *bool pointers to distinguish 'not set' from false, which is correct.
internal/pkg/xredis/client_test.go Comprehensive test coverage added for sentinel, cluster, and standalone modes including config-overrides-URL scenarios. All existing tests migrated to UniversalOptions.
internal/pkg/xcache/cache.go API updated to use redis.UniversalClient throughout; NewFromConfig condition correctly extended to check Addrs in addition to Addr and URL.
internal/pkg/watcher/watcher_redis.go Straightforward type widening from *redis.Client to redis.UniversalClient; no logic changed.
docs/en/deployment/configuration.md New multi-mode configuration docs added. The Docker-Compose example block shows all three modes (standalone/sentinel/cluster) within a single yaml mapping, producing duplicate addrs and password keys — only the last values survive parsing.
docs/zh/deployment/configuration.md Chinese translation of the same docs; shares the same duplicate-key issue in the deployment example block.
conf/conf.go Adds deprecation warning for addr, new defaults for addrs, master_name, sentinel_username, and sentinel_password. Straightforward and correct.
config.example.yml Example config updated with new fields and deprecation note on addr. Clear and accurate.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[NewClient cfg] --> B[newUniversalOptions cfg]
    B --> C[ParseUniversalURL cfg.URL]
    C --> D{URL empty?}
    D -- yes --> E[return empty UniversalOptions]
    D -- no --> F[Parse scheme / host / path / query]
    F --> G{scheme rediss?}
    G -- yes --> H[Set TLSConfig MinTLS1.2]
    G -- no --> I[No TLS from URL]
    F --> J[Parse query params client_name db addrs sentinel_* pool_* timeouts...]
    H --> K[opts returned to newUniversalOptions]
    I --> K
    J --> K
    E --> K
    K --> L{cfg.Addr set?}
    L -- yes --> M[opts.Addrs = addr]
    L -- no --> N{cfg.Addrs set?}
    N -- yes --> O[opts.Addrs = addrs]
    N -- no --> P{opts.Addrs empty?}
    P -- yes --> Q[ERROR: addr required]
    P -- no --> R[Continue]
    M --> N
    O --> R
    R --> S[Override Username Password MasterName SentinelUsername/Password RouteByLatency RouteRandomly IsClusterMode DB]
    S --> T{cfg.TLS?}
    T -- yes --> U[Create/update TLSConfig Apply InsecureSkipVerify]
    T -- no --> V{cfg.TLSInsecureSkipVerify without TLSConfig?}
    U --> W[return opts]
    V -- yes --> X[ERROR: TLS required]
    V -- no --> W
    W --> Y[redis.NewUniversalClient opts]
    Y --> Z{opts.MasterName set?}
    Z -- yes --> ZA{opts.IsClusterMode?}
    ZA -- yes --> ZB[FailoverClusterClient]
    ZA -- no --> ZC[FailoverClient Sentinel]
    Z -- no --> ZD{IsClusterMode or len Addrs gt 1?}
    ZD -- yes --> ZE[ClusterClient]
    ZD -- no --> ZF[standalone Client]
Loading

Reviews (3): Last reviewed commit: "fix: remove deletion of query parameters..." | Re-trigger Greptile

Comment thread docs/zh/deployment/configuration.md
Comment on lines +221 to +228
func (o *queryOptions) string(name string) string {
vs := o.q[name]
if len(vs) == 0 {
return ""
}
delete(o.q, name) // enable detection of unknown parameters
return vs[len(vs)-1]
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unknown URL query parameters silently swallowed

The string() method calls delete(o.q, name) with the comment "enable detection of unknown parameters", implying that after all known parameters are consumed any remaining keys in o.q should surface as errors. However, there is no code that checks len(o.q) > 0 after parsing completes. A user who types pool_sise=50 (typo) or any unrecognised key will get no warning, and their configuration will be silently ignored.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

避免存在歧义,已把delete删除

@looplj looplj merged commit 4a6ade5 into looplj:unstable Jun 7, 2026
4 checks passed
junjiangao pushed a commit to junjiangao/axonhub that referenced this pull request Jun 9, 2026
* feat: update Redis configuration to support multiple mode(use UniversalClient)

* fix: update parameter names in ParseUniversalURL for consistency

* feat: enhance Redis configuration to support standalone, sentinel, and cluster modes

* fix: improve error wrapping for invalid number in queryOptions

* fix: correct parameter name from 'addr' to 'addrs' in Redis configuration

* feat: add support for configuring Redis parameters via URL for standalone, sentinel, and cluster modes

* fix: remove deletion of query parameters in string and strings methods for better parameter handling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants