--- tags: [cachecloud, redis, infra, self-hosted] create time: 2026-07-04 12:00 --- # CacheCloud Redis 管理台 ## 概述 CacheCloud(搜狐开源)是一个 **Redis 私有云平台**,支持 Standalone、Sentinel、Cluster 三种架构的一站式高效管理。xinfra 中所有需要 Redis 服务的场景都通过 CacheCloud 进行**统一的实例申请和管理**——开发同学不再需要手动安装部署 Redis,只需在平台上提交工单即可获取可用实例。 核心目标:**降低大规模 Redis 运维成本,提升资源管控能力和利用率**。平台提供快速搭建/迁移、运维管理、弹性伸缩、统计监控、客户端整合接入等功能。 --- ## 系统架构 ### 整体拓扑 ```mermaid graph TB subgraph "用户层" Dev[开发同学 / 运维人员] end subgraph "接入层 (Nginx 双机房)" NG1[Nginx 机房 A] NG2[Nginx 机房 B] VIP[Virtual IP → 双向漂移] VIP --> NG1 VIP --> NG2 end subgraph "应用层 (Spring Boot)" CC[CacheCloud Web Server] DB[(MySQL 元数据)] AGT_Mgr[Agent 管理器] ALERT[报警组件
邮件 / 微信 / HTTP] CUSTOM[自定义扩展模块] end subgraph "执行层 (Agent 代理)" AGT1[Agent 宿主机 A
Redis Standalone / Sentinel] AGT2[Agent 宿主机 B
Redis Cluster Shard 1] AGT3[Agent 宿主机 C
Redis Cluster Shard 2] end Dev -->|cc.company.com| VIP VIP --> NG1 & NG2 NG1 & NG2 --> CC CC <--> DB CC --> AGT_Mgr CC --> ALERT CC --> CUSTOM AGT_Mgr -->|SSH + 心跳| AGT1 & AGT2 & AGT3 ``` > **关键设计决策**:CacheCloud 采用 **Agent 模式**而非直接 SSH 连接 Redis 实例。每个宿主机部署一个 Agent 进程,负责该机器上所有 Redis 实例的生命周期管理(启停、升级、备份恢复)。这样做的好处是 Agent 可复用 SSH 连接、缓存本地状态,大幅减少管理平台到 Redis 主机的网络开销。 ### 核心组件 | 组件 | 职责 | |------|------| | **Web UI / REST API** | 自助申请实例、配置修改、工单审批、监控大屏 | | **Agent 代理** | 部署在每个宿主机上,负责 Redis 进程生命周期管理、状态上报、远程命令执行 | | **元数据库 (MySQL)** | 存储实例拓扑、配置模板、账号权限、工单流转记录 | | **报警模块** | 内置邮件和微信报警,同时暴露 HTTP 接口供任意语言集成 | | **扩展模块** | 登录组件 (`LoginComponent`)、报警组件 (`EmailComponent`/`WeChatComponent`) 均可自行实现 | --- ## 实例类型与选型指南 ### 三种架构对比 | 维度 | Standalone | Sentinel (Master-Slave) | Cluster | |------|-----------|------------------------|---------| | **高可用** | ❌ 单机,无 Failover | ✅ 主从 + Sentinel 自动故障转移 | ✅ 多分片,自动槽迁移 | | **横向扩展** | ❌ 受单机容量限制 | ❌ 受单机容量限制 | ✅ 新增节点即扩容 | | **复杂度** | 简单 | 中等 | 较高 | | **推荐场景** | 测试环境、低频读写缓存 | 生产环境常规业务、内存需求 ≤ 6GB | 大数据量、高并发、内存需求 > 6GB | > **建议**:并不是 Cluster 越好。如果当前或未来所需内存不超过 6GB 且要求高可用,选择 Sentinel 就足够了。 ### 选型决策树 ```mermaid flowchart TD Start{是否需要高可用?} Start -->|否: 测试/灰度| Standalone[Standalone] Start -->|是| NeedScale{是否需要横向扩展?} NeedScale -->|否≤6GB| Sentinel[Sentinel 主从] NeedScale -->|是>6GB| Cluster[Redis Cluster] ``` --- ## 客户端接入方式 CacheCloud 提供了多种客户端 SDK 及 REST API,覆盖 Java、Python 等主流语言。 ### REST API(最通用) 通过简单 HTTP 请求即可获取实例连接信息,适用于任何语言: ``` GET http://{domain}/cache/client/redis/{appType}/{appId}.json?clientVersion={version} ``` **参数说明**: | 参数 | 含义 | 枚举值 | |------|------|--------| | `appType` | 实例类型 | `cluster` / `sentinel` / `standalone` | | `appId` | 应用 ID | 平台分配的数字 ID | **响应示例**: ```json { "message": "client is up to date, Cheers!", "shardNum": 10, "appId": 10192, "status": 1, "shardInfo": "10.10.xx.xx:6390,10.10.xx.xx:6382 10.10.xx.xx:6387,10.10.xx.xx:6379 ..." } ``` > `shardInfo` 字段以空格分隔每个分片,逗号分隔同一个分片的主从地址。解析后即可直连。 ### Java — cachecloud-client-redis(Jedis 封装) ```java @Configuration public class RedisConfiguration { @Bean(destroyMethod = "close") public PipelineCluster pipelineCluster(@Value("${cachecloud.demo.appId}") long appId) { return ClientBuilder.redisCluster(appId).build(); } @Bean(destroyMethod = "destroy") public JedisSentinelPool jedisSentinelPool(@Value("${cachecloud.demo.appId}") long appId) { return ClientBuilder.redisSentinel(appId).build(); } @Bean(destroyMethod = "destroy") public JedisPool jedisPool(@Value("${cachecloud.demo.appId}") long appId) { return ClientBuilder.redisStandalone(appId).build(); } } ``` **使用方式**: ```java @Autowired private PipelineCluster pipelineCluster; public String get(String key) { return pipelineCluster.get(key); } ``` > 所有 `...Pool.getResource()` 使用后必须调用 `jedis.close()` —— 它并非真正关闭连接,而是将连接归还给连接池(内部判断连接是否损坏后决定 `returnResource` 还是 `returnBrokenResource`)。 ### Java — cachecloud-client-lettuce(Lettuce 封装) 适合需要异步/响应式场景的应用: ```java @Bean(destroyMethod = "shutdown") public RedisClusterClient redisClusterClient(long appId, String password) { return LettuceClientBuilder.redisCluster(appId, password).build(); } @Bean(destroyMethod = "close") public StatefulRedisClusterConnection clusterConnection(RedisClusterClient client) { StatefulRedisClusterConnection conn = client.connect(); conn.setReadFrom(ReadFrom.REPLICA_PREFERRED); // 读操作优先走从节点 return conn; } ``` ### Python 接入(REST API 动态拉取连接信息) ```python import requests from rediscluster import RedisCluster app_id = 10192 url = f'http://cc.company.com/cache/client/redis/cluster/{app_id}.json' resp = requests.get(url).json() startup_nodes = [ dict(zip(['host', 'port'], addr.split(':'))) for shard in resp['shardInfo'].split(' ') for addr in shard.split(',') ] rc = RedisCluster(startup_nodes=startup_nodes, password='your-pass') ``` ### 跨机房部署(Cross-Room) 对于容灾要求高的业务,CacheCloud 支持**跨机房双活**:同一业务在两个机房分别部署应用实例,客户端 SDK 自动做双写双读和机房切换。原理是两个 `PipelineCluster` 实例被包装进一个 `RedisCrossRoomClient`。 --- ## 系统功能全景 ### 用户端功能 | 功能 | 说明 | |------|------| | **应用管理** | 查看统计信息、实例列表、应用拓扑、连接信息 | | **监控面板** | 命令曲线、延迟监控、日报统计 | | **命令执行** | 在线执行 Redis 命令用于排查 | | **键值分析** | 分析 bigkey、hotkey 分布 | ### 运维端功能 | 功能分类 | 具体能力 | |----------|---------| | **数据统计** | 全局统计、client 统计、server 统计 | | **工单审批** | 实例申请、配置修改、数据清理等操作需管理员审批 | | **应用运维** | 应用维度的启停、配置下发、日志查看 | | **实例运维** | 实例维度的启停、配置查询、数据清理 | | **数据迁移** | 跨实例数据迁移工具 | | **诊断工具** | 慢查询分析、连接数诊断等 | | **模板管理** | 按规格预设 Redis 配置模板(maxmemory、持久化策略等) | | **任务流** | 编排运维操作流程(如批量升级) | ### 报警配置 CacheCloud 内置的报警覆盖了 Redis 机器级别和实例级别的重要指标,支持的报警渠道: - **邮件报警** — 默认实现,也可替换为 HTTP 回调 - **微信报警** — 企业微信/钉钉 webhook 风格 报警可通过 HTTP 接口自定义,格式如下: ``` POST www.xxx.com/emailAlert?title=xx&content=xx&receiver=x&cc=x POST www.xxx.com/weChatAlert?title=xx&message=xx&weChatList=xx ``` --- ## 基础运维实践 ### maxmemory-policy 策略选择 | 策略 | 行为 | 适用场景 | |------|------|---------| | `volatile-lru` | 删除有过期时间的 key,LRU 淘汰 | 默认策略,有 TTL 的缓存 | | `allkeys-lru` | 对所有 key 做 LRU 淘汰 | 纯缓存场景,不设 TTL | | `volatile-ttl` | 删除即将过期的 key | 希望按过期时间优先淘汰 | | `noeviction` | 不淘汰,写操作返回错误 | 需要绝对保证数据完整性 | > **注意**:修改的配置会对应用的所有节点生效,因为所有节点的配置是统一的。 ### Jedis 连接池调优参考 ```java GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxTotal(DEFAULT_MAX_TOTAL * 5); // 根据实际 QPS 调整 poolConfig.setMaxIdle(DEFAULT_MAX_IDLE * 3); poolConfig.setMinIdle(DEFAULT_MIN_IDLE * 2); poolConfig.setMaxWaitMillis(3000); // 连接耗尽时最多等待 3s poolConfig.setJmxEnabled(true); // 开启 JMX 便于观察 poolConfig.setTestWhileIdle(true); // 空闲时定期检查连接有效性 poolConfig.setTimeBetweenEvictionRunsMillis(60000); // 每分钟检查一次 ``` 关键字段解读: | 配置项 | 默认值 | 调优建议 | |--------|--------|---------| | `maxTotal` | 8 | 根据峰值连接数估算,通常 × 3~5 | | `testOnBorrow` | false | 不建议设为 true,会显著增加延迟 | | `testOnReturn` | false | 一般保持 false,由 `testWhileIdle` 兜底 | | `whenExhaustedAction` | 1 (阻塞) | 配合 `maxWaitMillis` 使用,避免无限等待 | --- ## 常见陷阱与最佳实践 ### 1. Bigkey 的寻找与优化 **什么是 bigkey**:value 所占内存空间较大的 key。字符串类型超过 100KB 即视为 bigkey;非字符串类型(Hash/List/Set/ZSet)则以元素数量过多为准。 **危害**: - 内存不均匀:Cluster 中造成部分节点内存暴增 - 超时阻塞:Redis 单线程特性下,大 key 操作耗时 > 客户端超时 - 网络拥塞:单次大流量冲击网卡,影响同机其他实例 - 过期删除阻塞:未启用 lazyfree 时阻塞主线程 - 碎片整理冲突:Redis 4.0+ activeDefrag 对超大 key 可能导致周期性延迟 **发现手段**: | 方法 | 命令 | 特点 | |------|------|------| | redis-cli | `redis-cli --bigkeys` | 全量扫描,建议在从节点执行 | | DEBUG OBJECT | `DEBUG OBJECT key` | 获知序列化长度 `serializedlength` | | MEMORY USAGE | `MEMORY USAGE key` | 仅 Redis 4.0+,返回精确内存占用 | | 监控输出缓冲区 | `info clients` 关注 `client_biggest_input_buf` / `client_recent_max_output_buffer` | 间接判断是否存在大 key 读取 | **优雅删除方案**: - **String**:直接使用 `DEL`,通常不会阻塞 - **Hash/List/Set/ZSet**:使用 `HSCAN/SSCAN/ZSCAN` 分批获取元素 + `HDEL/SREM/ZREM` 逐个删除,或使用 Redis 4.0+ 的 `UNLINK`(异步删除) ```python def del_big_hash(r, key): cursor = 0 while True: cursor, members = r.hscan(key, cursor, count=100) if not members: break r.hdel(key, *members) # pipeline 批量更高效 if cursor == 0: break ``` ### 2. Hotkey 的处理方向 当某个 key 的访问量远超平均水平时: - **本地缓存**:在应用侧加一层 Guava/Caffeine 缓存 - **key 拆分**:将一个大 key 拆成多个子 key(如 `user:1001:friends` → `user:1001:friends:1`, `user:1001:friends:2`) - **读写分离**:读操作通过 Sentinel 路由到从节点 ### 3. 实例规格匹配 不要盲目选大规格。建议先通过 Prometheus/Grafana 观察历史 QPS、内存使用和连接数,再确定实例规格。过度配置会在资源看板上体现为浪费。 ### 4. 临时 vs 长期实例 - **临时实例**(测试/灰度用)应设置自动回收策略——超出保留期后系统自动销毁 - **长期实例**则需要完善监控、定期巡检配置变更 ### 5. 机房就近原则 Redis 对网络延迟非常敏感。跨机房访问比同机房慢数倍,因此应用申请时应填写服务所在机房,确保实例分配到最近的机器。 --- ## Redis 版本演进速览 CacheCloud 管理的 Redis 实例可能运行在不同版本,了解各版本的关键特性有助于理解平台行为差异: | 版本 | 核心新特性 | CacheCloud 相关 | |------|-----------|----------------| | **3.x** | 原生 Cluster | 最早支持的 Cluster 形态 | | **4.0** | Lazyfree 异步删除、AOF/RDB 混合持久化、内存碎片整理 | 支持 UNLINK 删除 bigkey | | **5.0** | Stream 数据类型、RESP3 协议、Dynamic HZ | 客户端兼容性更好 | | **6.0** | 多线程 IO、ACL、SSL 加密、协助客户端缓存 | 多线程 IO 提升非 Pipeline 场景 2 倍性能 | > **启发问题**:为什么 Redis 6.0 的多线程只处理网络 IO 而不涉及命令执行?这背后有什么权衡? --- ## 与 xinfra 的对接方向 进阶目标中提到要「基于 CacheCloud API 实现页面直接创建 Redis Cluster」,这意味着: 1. **阅读 Open API 文档**:梳理可用的创建/配置/查询接口 2. **封装创建流程**:选择规格 → 调用 API → 等待就绪 → 返回连接信息 3. **集成到 xinfra 统一服务管理页面**:让开发者在 xinfra 内即可完成 Redis 实例的全生命周期操作 4. **可选增强**:对接 xinfra 的审批流、用量统计、成本分摊等模块 --- ## 关联笔记 - [[technical/xinfra-preview/cloud-dm-overview]] — SQL 审核与 Redis 访问同属数据层基础设施 - [[technical/xinfra-preview/k8s-rke2-fundamentals]] — CacheCloud 的宿主机未来可能迁移至 K8s 部署 - https://github.com/sohutv/cachecloud — CacheCloud GitHub 仓库(含完整 Wiki 和代码) - https://github.com/antirez/redis — Redis 官方仓库