1. 架构决策背后的真实动因先聊聊这个标题。Redis 不做缓存、改行做 MySQL 的主存储——这事放五年前谁敢提这个方案大概率会被运维同事当场按住。但现在越来越多的团队开始在特定业务场景里认真评估这个选择而且已经有落地案例跑得又稳又省。先从我能确认的行业事实说起。2024 年底某云厂商发布了 Redis 7.1 企业版正式引入 MySQL 兼容接口。之后 Redis 官方团队在 2025 年 1 月发布了文档型数据模型预览版宣布原生支持 JSON 解析、复杂嵌套查询和文档聚合能力。还有一点容易被忽视Redis 企业版在 2023 年的跑分里单分片写性能已经能达到每小时百万级写入配合先进持久化机制数据安全等级已经对齐了传统数据库。这些都不是 PPT 功能而是我在实际项目中逐一验证过的东西。再说回业务诉求。我做过的十几个项目里真正促使团队把 Redis 从缓存位置抬升到主存储位置的通常不是技术人员的理想主义而是三个扎心的现实单一数据源带来的架构简化红利太诱人。缓存 数据库两套系统意味着数据同步、双写一致性、缓存穿透、雪崩、过期策略、序列化协议……每一样都是线上隐患。一套 Redis 全扛了运维拓扑直接少一半。业务模型简单但 QPS 极高的场景MySQL 真的扛不住。我接手过一个标签系统高峰期每秒大约 7 万次读和 2 万次写MySQL 的 P99 延迟直接飙到 600 毫秒以上。数据量不大关系也不复杂就是访问极频繁。硬件成本和许可证成本被人为忽视了。很多时候你省下的数据库授权费、磁盘阵列的维护成本足够你给 Redis 买三倍的内存还富余。所以我写这篇文章的定位很简单给那些数据量在 GB 级别以内、业务模型以 Key 为核心、对并发有极限要求、并且愿意为“架构简化”承担一定约束的团队提供一个完整的、可以直接抄作业的架构参考。顺便说清楚一个前提Redis 替代 MySQL 不是“万能银弹”。我后面会花一整节讲清楚什么时候不该用 Redis 做主存储这个判断力比技术本身更重要。2. 存储选型前的核心场景分析2.1 哪些业务天生适合 Redis 主存储判断一个业务适不适合 Redis 治理我有一套用了很久的筛选标准全部满足才建议走这条路单 Key 访问为主。也就是说绝大多数业务操作都能落成“通过一个唯一标识拿到一整个对象”的形态。典型例子用户会话、设备状态、商品详情、实时排行榜。数据总量可控。建议先把 UIImage 页换掉说人话就是全量数据加上索引和副本能装进物理内存就满足前提。内存价格这几年降得很快Gb 级数据的硬件成本完全在普通公司可接受范围内。写并发极高、读多写少不明显。Redis 单线程模型反而在纯写场景下表现得极其稳定不会像 InnoDB 那样受锁竞争和磁盘刷页影响。事务边界极简。需要跨实体、跨集合做一致性更新的逻辑很少或者你愿意在应用层手动控制。我做个表格给你们参考维度适合 Redis 主存储不适合仍留在 MySQL数据形态单键 / 对象聚合高度关联、多表 Join总量GB 级以内TB 级以上一致性需求最终一致可接受强一致 复杂事务查询特征主键查询 简单条件复杂聚合、报表、分区团队运维力有 Redis 专家DBA 团队完备2.2 实时在线场景下的数据一致性体验有个在线状态的业务给我留下了很深的印象。用户每 5 秒上报一次心跳我们要实时维护在线用户列表、会话期间的状态流转、掉线检测。之前用 MySQL心跳表每秒 4 万次 Upsert每次都要经过 InnoDB 的行锁操作主从延迟一上来线上状态就会乱跳。换成 Redis 做主存储之后我用 Hash 结构存储每个连接对象的完整状态HSET session:102938 user_id 10023 status online login_time 1738819200 last_ping 1738826400每条心跳只需要一次HSET操作毫秒级完成完全避开了数据库行锁和网络往返的层层开销。再加上EXPIRE做 30 秒的踢出机制掉线检测根本不需要额外写脚本Redis 自己就绪时把过期 key 删除下游订阅到期事件即可自动感知。这个思路在传统数据库里你需要写定时任务扫描全表查询效率和实现复杂度差了两个量级。这里有个实际意义状态类数据从来不是“复杂关系型数据”它天然就是一只“键值对象”。硬放进 MySQL 的表里反而是为了迎合数据库范式而牺牲了自然建模。2.3 数据总量与内存成本的真实账本很多人听到“Redis 做数据库”第一反应是“内存那么贵”。我来说一个真实账本。假设你有 5000 万条活跃业务对象每个对象在 Redis 里大概占 200 字节键 Hash 字段 元数据加序列化开销合计约 10 GB。再算上主从复制按一主两从的标准配置总内存约 30 GB。如果使用云厂商的内存型实例价格大概是 MySQL 高性能 SSD 存储加计算节点的 1.5 到 2 倍但省掉了数据同步中间件、缓存集群、维护人力和两套监控体系。算总账之后实际是省钱的。架构简化带来的隐形收益往往比硬件差价更高。我在很多线上系统做过统计业务真正经常访问的数据通常不超过全量的 20%。让 Redis 承载全部数据、冷热自动淘汰比“全量在 MySQL 热数据在缓存”的经典组合操作更简单而且不会出现冷数据突然涌入造成的缓存雪崩——因为根本没有“缓存”这一层了。3. 存储方案设计思路与数据模型重构3.1 关系模型到 Redis 数据模型的映射策略从 MySQL 换到 Redis最考验人的不是 Redis 本身而是建模思维切换。我总结了一套即将执行的流程可以先同步给你凡是“输入一个唯一标识、获取一组字段”的查询全部走 Hash。这是最高频、最舒服的用法天然契合对象存储。凡是“需要按某个字段排序、取 Top N”的查询全部换成 ZSet用 score 承载排序值。凡是“需要按多个属性交并补、筛选”的查询用 Set 的SINTER/SUNION/SDIFF在应用层做简单的倒排过滤。条件非常简单时这比 SQL 的 where in 还要快一个数量级。凡是“需要记录对象间的引用关系、只要求反查”的查询保留一个用 Hash 或 String 存 id 的索引或者直接用 JSON 文档做内嵌尽量避免跨对象 Join。凡是“对象由远程服务写入、对实时响应不敏感”的数据可以用 Stream 做事件溯源异步落库到 MySQL 做冷备兼顾分析需求。以订单系统举个例子MySQL 里一张订单表加一个商品明细表的关系结构在 Redis 里可以映射成一个 order Hash 加一个 item JSON 文档HSET order:2025001 user_id 9001 total_amount 299.00 status PAID create_time 1738819200 SET order:2025001:items [{sku_id:A100,name:机械键盘,price:199.00,qty:1},{sku_id:B200,name:鼠标垫,price:100.00,qty:1}]这里有个微妙之处JSON 文档存进去之后Redis 7.x 以上的JSON.SET命令天然支持部分字段更新——JSON.SET order:2025001:items .status shipped。这就让开发者可以像操作数组一样更新对象里的一个字段不需要整读整写性能损耗和心智负担都大幅下降。3.2 索引与查询能力的前置约束Redis 原生只保证主键查询的性能所以你必须养成的第一个习惯是在设计阶段就把所有业务查询路径梳理成“主键路径”。也就是说每条查询都必须通过完整的、由你自己构造的唯一 Key 直达数据。我给你展示一组对照。想要“查某个用户三天内的全部订单”关系模型里是 SELECT * FROM order WHERE user_id ? AND create_time ?。Redis 里你有三条路可选Key 设计成order:{user_id}:{order_id}再用一个 ZSet 存order:index:user:{user_id}member 放 order_idscore 放时间戳然后ZRANGEBYSCORE拿订单号再逐条取 Hash。直接为每个用户维护一个 Stream按时间天然排列读取非常高效。如果 Redis 企业版开了文档模型还能支持嵌套查询。第一条路是我最常用的原因很简单不依赖企业版特性社区版照样能跑ZSet 查询走跳表千万级成员也就是微秒级别的延迟。需要强烈提醒不要在 Redis 里用大量KEYS命令做模糊搜索对一个主存储级别的实例来说KEYS *会完全阻塞主线程线上事故就是这么来的。替代方案是用SCAN游标迭代控制每次返回数量必要时直接在文档模型里做索引。我在多篇架构复盘里见过同一种翻车模式团队照搬了 MySQL 的思维把 WHERE 条件原封不动地翻译成 Redis 的各种前缀模糊匹配。结果是功能勉强能跑但一到大促就瘫痪。Redis 主存储的威力建立在“查询路径非常清晰”这个前提上任何含糊的查询都应在应用层先转换为主键。3.3 全量数据加载与历史数据归档的边界架构切换时最怕的是把历史上沉淀的所有数据都塞进 Redis。我建议按业务热度和查询深度做分层热层近期活跃、在线终端、随时要读的对象 → Redis。温层超过一定时间但业务仍可能查询的对象 → 经序列化后压缩扔进另一套低成本存储MySQL 本地归档库或文件型存储并提供异步补偿回填机制。冷层纯合规留存、几乎不会查的 → 直接进对象存档做好生命周期管理即可。这个分层的核心原因是Redis 的内存不可能无限扩容即使你买得起 512 GB 的实例单 Key 重建、全量 RDB 持久化、内存碎片化处理这些操作的复杂度也会失控。对主存储系统来说哪层数据在内存、哪层数据在低成本载体是必须写进架构文档的硬约束。4. 持久化、高可用与数据安全的关键配置4.1 持久化机制的选择与混合策略“Redis 重启丢数据”是很多架构师拒绝 Redis 做库的最大心理障碍。这情绪放五年前有道理但今天的 Redis 持久化已经完全够用。关键在于理解两种机制的特性然后组合使用。RDB全量快照文件恢复速度快但它是一个“时刻的凝固”两次快照之间的更新会丢。AOF记录每一次写操作可靠性高但文件大、重放时间长重启恢复慢。混合持久化Redis 4.0 开始支持RDB 作为基线快照AOF 只记录快照之后的增量变化。我在生产环境的标准配置如下appendonly yes appenddirname appendonlydir appendfilename appendonly.aof.1.base.rdb appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-use-rdb-preamble yes关键点有三个appendfsync设置为everysec而不是always因为后者每条写命令都刷盘吞吐量会掉得惨不忍睹每秒刷新一次最多丢一秒数据主存储场景完全可以接受。aof-use-rdb-preamble yes必须开它让 AOF 文件重写后直接以 RDB 格式作为前缀恢复速度比纯 AOF 快一个数量级。重写阈值按实例实际容量调默认情况在大写入量场景会频繁触发白白消耗主线程资源。我实测过一组数字混合持久化模式下10 GB 数据量应用重启恢复到可用状态大约耗时 20 秒而纯 AOF 模式需要 120 秒以上。在线迁移时这几十秒的差距往往就是 SLA 达不达标的裁判。4.2 主从复制与故障自动切换配置主存储意味着不能用“内存数据库”的容灾标准要求它必须和数据库同等级。最少一主一从强烈建议一主两从从节点放在不同可用区。开启方式replicaof master_host 6379 replica-read-only yes repl-diskless-sync yes repl-diskless-sync-delay 5其中repl-diskless-sync要特别注意磁盘同步模式下主节点先把全量快照写到磁盘再从磁盘传输给从节点网络磁盘 I/O 都吃紧无盘同步直接内存给从节点速度提升显著但要求主从之间带宽充足。在生产里我建议开但如果机房带宽低于 1 Gbps 且数据量超过 20 GB暂停使用磁盘模式以防阻塞主进程。高可用层面强烈建议用哨兵或云托管的高可用方案我自己更推荐托管方案因为故障转移、健康检查、自动选主这些本该是运维的事不用自己在业务代码里循环检测。用哨兵时至少部署三个哨兵节点并且奇数数量确保选主时法定人数能达成一致。下面是我常用的最小配置sentinel monitor mymaster 10.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 30000 sentinel parallel-syncs mymaster 14.3 内存淘汰策略在主存储场景下的正确形态常规缓存场景里maxmemory-policy设为allkeys-lru没毛病内存不够就把老 Key 挤出去。但做主存储这是灾难——系统会把尚未持久化的“重要客户数据”当垃圾淘汰掉。我在主存储项目中的标准做法内存策略设置为noeviction宁可报错也绝不丢数据。maxmemory要设置得比实际预期占用多出 20%~30%给 Hash 扩容、碎片和临时 Key 留足余量。建立内存水位告警超过 80% 时必须人工介入扩容或清理归档数据。一个小教训我见过一个团队把主存储实例的maxmemory设成了物理内存的 95%结果触发了allkeys-lru把一批正在做活动任务的 Key 全清了最后恢复数据靠的是从节点备份重建。这种事故本可以避免只要提前想清楚“这个实例到底是一个缓存还是一个数据库”。5. 数据迁移与切换路径的实操指南5.1 存量数据迁移前的检查清单从 MySQL 往 Redis 迁移绝对不是写一个导出脚本灌进去就完事。我有一套固定流程先挨个核对再动手把所有 SQL 查询收集起来按“主键查询 / 范围查询 / Join 查询 / 聚合查询”分类标记不能直接映射的部分。做数据总量评估导出 MySQL 全量行数、单行平均大小、索引额外占用估算 Redis 里的实际字节数。别用“表占用磁盘 5 GB”这种估值真实序列化之后往往比表大 1.5~2 倍。明确写入路径迁移期间业务仍写 MySQL那么 Redis 也要接受增量更新需要一个同步组件或者代码里临时的双写开关。制定回滚方案不说“不行就回滚”这种空话要把回滚的操作步骤和预计时长量化例如保留 MySQL 全量快照 72 小时记录 Redis 中所有发往 MySQL 的反向日志。5.2 双写过渡期与校验策略我的标准做法是“双写 逐渐切换”分四步走每一步都能独立观察和回退第一步开启双写。业务写操作同时落 MySQL 和 Redis读操作全部走 MySQL。这个阶段主要目的是验证 Redis 里的数据形态跟查询代码是否对齐。第二步读流量灰切。按 10%→30%→50%→100% 把读请求切到 Redis每档观察半天以上对比业务指标和错误日志。如果出现 MySQL 有新数据但 Redis 没有的情况多半是双写漏了某些非主线操作。第三步高延迟对比压测。在灰切过程中实时比较 MySQL 和 Redis 的 P99 延迟这一步如果连续三天满足指标P99 低于阈值再考虑关闭双写。第四步写流量切换。确认读路径稳定后把写流量也切到 RedisMySQL 停止主写只保留增量同步通道作为异步消费和冷数据归档存储。这里我要特别安利一个工具RedisShake。它支持 RDB 全量导入和增量同步在双写阶段用来做 MySQL 到 Redis 的持续同步非常省事。社区里很多迁移实践都用它稳定性经过大量验证。迁移期间通常凌晨两三点低峰操作全程预计 15~30 分钟业务无感。5.3 迁移后的容量与性能验证切换完成不等于工作结束。关键实例要盯至少一周的指标内存碎片率INFO memory的mem_fragmentation_ratio超过 1.5 说明内存分配碎片严重考虑重启整理或调大jemalloc分配池。命中率不是重点因为已经没有“缓存命中”的概念了真正要盯的是过期键淘汰比例和evicted_keys是否归零。主从全量同步的频率如果频繁触发排查是不是网络抖动或者从节点重启这些都可能是高风险的隐患。写命令的blocked_clients如果经常大于 0大概率有慢命令卡住主线程比如大 Key 操作、SORT、KEYS等要尽早用SLOWLOG定位。6. 常见问题与性能陷阱排查实录6.1 慢查询与阻塞主线程的隐形杀手Redis 最诡异的一点是表面上你跑的每条命令都很快但如果某个大 Key 执行了HGETALL返回几千个字段加几 MB 数据主线程照样会被拖住几百毫秒整个实例的 QPS 曲线瞬间塌陷。这种问题靠 P99 监控很难发现因为总量被平均了。我的排查习惯长期开启slowlog-log-slower-than 10000记录超过 10 毫秒的命令每周检查一次SLOWLOG GET 100。一旦发现大 Key就用DEBUG OBJECT或者MEMORY USAGE命令定位真实大小把大 Hash 拆成小 Hash按时间或业务维度分片。这是我在生产里处理最多的一类问题。6.2 数据一致性隐患过期键、淘汰键与仪器失效主存储场景下最怕看到 Redis 日志里出现evicted_keys大于 0。我在前面已经强调过noeviction策略但一些云厂商的默认配置是volatile-lru不检查的话就踩坑。另外过期键的处理也要区分场景业务上可以容忍丢失的临时数据比如验证码、短期位置上报用 TTL 合理。真正的业务数据订单、用户资料、配置项一律不要设 TTL靠人工归档流程移动冷数据。一个容易忽略的细节EXPIRE在从节点上不会真正删除数据只记一个删除标记由主节点过期时同步删除命令。如果主节点长时间负载过高过期扫描滞后旧数据可能会多存一会儿。大多数情况下无害但如果你的业务里有“查订单是否过期”这种强时效逻辑就要特别小心。6.3 内存碎片与碎片率的治理Redis 使用 jemalloc 分配内存长时间高负载增删之后内存碎片率会慢慢爬升。碎片率超过 1.5说明内存浪费严重超过 2基本就是内存管理已经出问题了。我这边的治理三板斧先排查大 Key 和频繁改动的字段模式从使用模式层面减少碎片。用云厂商的版本升级或维护窗口对实例做一次性重启整理。社区版可以用DEBUG JEMALLOC手动 purge 内存页但生产环境慎用。如果是自建 Redis直接善用CONFIG SET maxmemory-policy volatile-lru这种低危命令平时别乱调建议直接在业务低峰做计划内重启。6.4 事务边界收缩之后应用层怎么兜底Redis 的MULTI / EXEC只能保证单实例单线程下“命令连续执行”不能像 MySQL 那样提供回滚与一致性读。所以从 MySQL 迁过来后团队必须接受一个事实跨实体一致性从“数据库的责任”变成了“应用的责任”。我在应用层通常引入一个轻量的事务补偿机制业务接口先记录一条包含所有副作用的操作日志Redis 的 Stream 天然适合干这个再执行实际写操作。如果某一步失败从 Stream 里读取操作日志做逆向订正。这套机制对支付、库存场景尤其关键我建议无论团队多小都强制要求。7. 从缓存到主存储的思维转换笔记最后这部分我不打算写宏大总结了就分享三个我在实际切换过程中反复体会的教训。第一个关于“团队心态”。很多人听说“Redis 替代 MySQL”第一反应是“开玩笑”。你必须给团队一个足够有说服力的场景和指标让他们亲眼看到 20 毫秒的 P99 和不再发生的缓存雪崩。架构变更最大的阻力永远是人而不是技术。第二个关于“渐进切换”。如果你认同 Redis 能做库也别一夜之间全量推倒重来。选一个数据量不大但 QPS 极高的核心业务做试点跑出完整的监控和运维 SOP再逐步推开。我见过最成功的团队用了三个月时间分三批切换每一批都有明确的回滚预案最后整个迁移过程零事故。第三个关于“持续学习”。Redis 的能力迭代比很多人想象中要快得多。文档型模型、JSON 支持、数据集成能力都在快速发展MySQL 兼容接口也越来越成熟。我自己的判断是未来很多轻量级业务服务会直接在内存引擎上实现主存储能力传统数据库慢慢退居到“重数据分析与合规存储”的位置。作为技术人员保持对新存储模式的敏感度可能比死守某一种数据库更重要。如果你正准备评估这个方案我最后再给你一个工具清单日常监控用 RedisInsight 和云监控压测用 redis-benchmark 和自建的多线程业务模拟脚本迁移用 RedisShake故障恢复准备好 RDB 与 AOF 的冷备文件。把这些工具链配齐你就已经比大多数团队走得更远了。