
简介这份PPT面向后端开发、运维工程师及Redis初学者系统梳理了Redis的核心知识体系可用于技术分享、内部培训或自学复习。资源包共1个pptx文件大小约1.59MB以幻灯片形式组织内容便于直接演示或按页查阅。目前已有161人学习下载。内容覆盖Redis简介、配置文件详解、持久化机制与常用命令四大模块从读写性能、原子性、主从复制等优缺点切入逐项说明redis.conf中端口、超时、守护进程、数据库数量等配置含义重点对比RDB快照与AOF日志两种持久化策略的配置项、适用场景及各自优劣并整理key、String等命令的用法与返回值。整体结构清晰、要点集中适合作为Redis入门梳理或团队分享的参考材料。1. 单线程的 Redis 为什么能跑到 11 万 QPS从一次压测翻车说起很多人第一次看到 Redis 的性能数据都会愣一下读 110000 次/s、写 81000 次/s而它处理命令的主循环居然是单线程的。按直觉单线程应该慢才对多线程才能压榨多核。可现实恰恰相反——Redis 用一条线程把绝大多数请求都扛了下来还成了缓存领域的事实标准。这背后的机制值得搞懂因为它直接决定了你写业务代码时哪些操作是安全的、哪些会拖垮整个实例。这份 Redis 技术分享把简介、配置、持久化、命令、事务、发布订阅串成了一条线正好可以顺着它把「为什么这么设计」一层层拆开。搞懂之后你会发现Redis 的快不是玄学而是一连串取舍的结果。2. 内存 单线程 原子性性能数字背后的三个设计支点2.1 为什么把数据放内存里而不是「内存 磁盘」混合Redis 被定义为一个「内存存储的 key-value 数据结构服务器」这句话里最关键的字是「内存」。磁盘随机读一次大概要几十到上百微秒内存访问只要几十纳秒差了三个数量级。Redis 把全部数据常驻内存读写路径上几乎没有磁盘 I/O这是它能跑到十万级 QPS 的物理基础。但纯内存有个致命问题断电就没了。所以 Redis 又补了持久化机制把内存数据定期或实时落到磁盘。注意这里的顺序——内存是主存储磁盘是备份而不是反过来。这跟传统数据库「磁盘为主、内存做缓存」的思路正好相反。理解这个定位后面看 RDB 和 AOF 的取舍就顺了它们服务的目标不是「每次读写都保证落盘」而是「尽量少丢数据同时别拖慢主路径」。常见的实现思路是Redis 在启动时把磁盘上的持久化文件加载回内存之后所有读写都在内存完成持久化在后台异步进行。所以 Redis 的「持久」是有窗口的不是每笔操作都同步落盘。2.2 单线程模型不是不能多线程是不值得Redis 的核心命令处理是单线程的这一点经常被误解成「Redis 只能用一个 CPU 核」。准确说法是命令的执行是单线程的但持久化、集群同步这些事会 fork 子进程或开额外线程去做。为什么命令执行要用单线程因为多线程处理共享数据结构要加锁加锁就有竞争、有上下文切换、有死锁风险。Redis 的操作大多是内存里的简单读写单次执行极快如果为了并行而引入锁锁的开销可能比操作本身还大。单线程反而避免了锁竞争让每次操作都是原子的——这正是分享里强调的「所有操作都是原子性的」的来源。注意单线程的原子性指的是「单条命令」原子不是「多条命令组合」原子。多条命令要原子得靠事务或 Lua 脚本。单线程也带来一个硬约束任何一条慢命令都会阻塞后面所有请求。比如对一个存了几百万 key 的实例执行KEYS *它会遍历整个键空间期间所有请求排队等待。这就是为什么生产环境禁用KEYS改用SCAN系列增量迭代。2.3 原子性与数据结构为什么丰富类型比「只有字符串」更值分享里列了 string、hash、set、sorted set、list 五种基础结构。很多人觉得这只是「方便」其实它直接影响原子性和性能。举个例子用 hash 存一个对象的多个字段HSET、HINCRBY这些命令在服务端一次完成天然原子如果只有 string你得先GET出来、在客户端改、再SET回去这中间就有并发窗口两个客户端同时改就会丢更新。INCR是另一个典型。计数器场景下INCR key在服务端一步完成读-改-写不需要客户端加锁。如果换成「读出来加一写回去」高并发下必然出错。所以数据结构的丰富性不只是 API 好用它把「需要原子保证的操作」下沉到了服务端减少了客户端协调成本。代价是内存开销。每种结构都有自己的底层编码比如小数据量时 list 用 ziplist、大了转 quicklisthash 小了用 ziplist、大了转 hashtable。这些编码转换对使用者透明但会影响内存占用和单条命令的耗时。理解这层才能解释为什么同样存一百万个 key用 hash 聚合和用独立 string内存能差出好几倍。3. RDB 与 AOF持久化到底在保什么代价是什么3.1 RDB 快照fork 出来的子进程在干什么RDB 的思路很直白把某一时刻内存里的全部数据写成一个二进制快照文件默认叫dump.rdb。恢复时直接把这个文件读回内存。核心配置是save 60 1000意思是 60 秒内有 1000 次写操作就触发一次保存。真正值得拆的是「怎么在不阻塞主线程的前提下把内存写下来」。Redis 用的是 fork 加写时复制Copy-On-Write。执行保存时主进程 fork 出一个子进程子进程看到的是 fork 那一刻的内存快照它负责把这份数据写盘。主进程继续处理请求。当主进程要修改某个内存页时操作系统会先把这一页复制一份给子进程保证子进程看到的数据不变。这个机制解释了分享里 RDB 的两个缺点。第一fork 本身要复制页表数据量越大越耗时期间主进程会被短暂卡住这就是「数据量大时 fork 非常耗时导致无法在毫秒级响应」。第二如果保存过程中出错stop-writes-on-bgsave-error no决定是否停止接收写入——设成 no 意味着即使快照失败也继续写风险是下次恢复时数据更旧。RDB 的优点是文件紧凑、适合备份、恢复快缺点是两次快照之间的数据会丢。save 60 1000意味着最坏情况下丢 60 秒的写入。3.2 AOF 日志为什么「重放命令」能恢复数据AOF 换了个思路不存数据快照而是把每一条写命令追加到文件末尾。恢复时从头到尾重放一遍数据就回来了。配置里appendonly yes开启appendfsync控制同步策略策略行为丢数据窗口always每条命令都 fsync 到磁盘几乎不丢everysec每秒 fsync 一次最多丢 1 秒no交给操作系统决定何时刷盘不可控everysec是默认值也是大多数场景的平衡点。它把 fsync 放到后台线程做主线程只管写缓冲区所以不会因为磁盘慢而卡住命令执行。AOF 文件会越来越大因为同一个 key 可能被改了一万次文件里就有一万条命令。所以需要 rewriteauto-aof-rewrite-percentage 100表示当前文件是上次 rewrite 后的一倍时触发auto-aof-rewrite-min-size 64m表示文件至少到 64MB 才考虑。rewrite 不是去读旧文件而是直接根据当前内存状态生成一份「最小命令集」比如一个 key 最终值是 5就只写一条SET key 5而不是历史上所有修改。no-appendfsync-on-rewrite no这个配置容易被忽略。rewrite 期间子进程在大量写盘如果此时主线程还要 fsync磁盘 I/O 会打架。设成 yes 表示 rewrite 期间不 fsync牺牲一点安全性换性能。3.3 两种持久化怎么选不是二选一是看你能丢多少分享里给了对比但实际决策可以更具体。如果数据能从源头重建比如纯缓存RDB 足够甚至可以不持久化。如果数据丢了业务会出问题比如订单状态用 AOF 的everysec最多丢一秒。如果两者都要可以同时开启——Redis 重启时优先用 AOF 恢复因为它的数据更新。一个常见的坑是只开了 RDB然后以为「我配了持久化就不会丢数据」。实际上save 60 1000在写入不频繁时可能几十分钟都不触发一次宕机就丢一大段。另一个坑是 AOF 文件涨到几十 GB 才发现没配 rewrite恢复时重放要几个小时。这些都不是配置写错而是没理解机制背后的时间窗口。4. 命令与事务哪些操作是原子的哪些只是看起来像4.1 key 管理与过期TTL 背后的惰性删除EXPIRE key seconds设置生存时间TTL key查剩余时间PERSIST key移除过期。这里有个容易误解的点key 过期后并不是立刻从内存消失。Redis 用的是「惰性删除 定期删除」组合——访问一个 key 时发现它过期了才删同时后台定期抽样删除一批过期 key。这带来一个现象你EXISTS一个已过期的 key 返回 0但内存里可能还占着。如果大量 key 同时过期又没被访问内存不会马上释放。排查内存异常时这是常见盲区。KEYS pattern支持通配符KEYS *匹配所有 key。前面说过这个命令会遍历整个键空间生产环境慎用。替代方案是SCAN cursor MATCH pattern COUNT count它每次只返回一小批不阻塞主线程。4.2 五种数据结构的命令设计逻辑String 的命令围绕「值可以是数字也可以是文本」展开。INCR、DECR、INCRBY、DECRBY把字符串当整数做原子增减key 不存在时先初始化为 0。APPEND追加内容GETRANGE取子串STRLEN取长度。SETEX是SET加过期的组合适合存会话这类有时效的数据。Hash 适合存对象。HSET设字段HGET取字段HGETALL取全部。HINCRBY对字段做原子增减适合做对象内的计数器。HSETNX只在字段不存在时设置可以用来做「首次写入才生效」的逻辑。List 是双向链表语义。LPUSH从头部插入RPUSH从尾部插入LPOP/RPOP从两端弹出。BLPOP/BRPOP是阻塞版本列表为空时连接会挂起直到有元素或超时——这是实现简单队列的常用手段。LTRIM只保留指定区间配合LPUSH可以做一个固定长度的最新列表。Set 是无序不重复集合。SADD添加SISMEMBER判断存在SINTER/SUNION/SDIFF做交并差。SINTERSTORE把交集结果存到另一个 key适合做「共同好友」这类计算后还要复用的场景。Sorted Set 在 Set 基础上给每个成员带一个分数按分数排序。分享里没展开它的命令但它的典型用途是排行榜分数是热度或时间ZADD更新ZRANGE按排名取。4.3 事务MULTI/EXEC 到底保证了什么Redis 事务用MULTI开始之后命令进队列EXEC时按顺序一次性执行。DISCARD放弃WATCH监视 key。关键要理解它和数据库事务的区别。Redis 事务不保证「部分失败回滚」——如果队列里第三条命令执行时报错前两条已经生效后面的继续执行。它保证的是「这批命令在执行期间不会被其他客户端的命令插进来」也就是隔离性不是原子回滚。WATCH提供乐观锁。执行WATCH key后如果EXEC之前这个 key 被别的客户端改过整个事务被打断。这是实现「读-改-写」并发安全的常用模式WATCH余额读出计算MULTISET新值EXEC。如果中途有人改了余额EXEC返回失败客户端重试。# 乐观锁更新余额的典型流程 import redis r redis.Redis() def transfer(key, delta): while True: try: r.watch(key) # 监视 key current int(r.get(key) or 0) new_val current delta pipe r.pipeline() pipe.multi() # 开启事务 pipe.set(key, new_val) pipe.execute() # 若 key 被改过则抛异常 return new_val except redis.WatchError: continue # 冲突则重试这段代码里watch是乐观锁的入口multi把后续命令入队execute触发原子执行。WatchError表示监视期间 key 被改动需要重试。注意重试是客户端行为Redis 不会自动帮你重来。4.4 发布订阅为什么它不保证消息可靠SUBSCRIBE channel订阅PUBLISH channel message发布PUBSUB CHANNELS列出活跃频道PUBSUB NUMSUB查订阅者数量UNSUBSCRIBE退订。发布订阅的模型是「即发即忘」消息发出时只有当前在线的订阅者能收到没有订阅者消息就丢了也不会存起来等订阅者上线。这跟消息队列的持久化投递是两回事。所以它适合做实时通知、配置推送这类「错过就错过」的场景不适合做订单、支付这类不能丢的消息。理解这一点就不会拿它当可靠队列用。需要可靠投递得用 List 的BLPOP或者专门的流结构。5. 避坑与排查那些配置看起来对、跑起来翻车的时刻5.1 现象写入正常但重启后数据少了一大截原因只配了 RDB且save阈值没触发。比如save 60 1000业务写入量小60 秒内不到 1000 次快照一直没生成宕机时内存数据全丢。解决确认数据能丢多少。不能丢就开 AOFappendfsync everysec。或者调小 RDB 阈值但注意频繁 fork 的代价。5.2 现象AOF 文件涨到几十 GB重启恢复要几小时原因没配 rewrite或者auto-aof-rewrite-percentage设得太大。AOF 记录的是所有写命令同一个 key 改一万次就有一万条。解决确认auto-aof-rewrite-percentage 100和auto-aof-rewrite-min-size 64m生效观察日志里有没有 rewrite 记录。已经涨大的文件可以手动触发一次 rewrite。5.3 现象执行某个命令后整个实例卡住几秒原因大概率是KEYS *、HGETALL大 hash、SMEMBERS大 set 这类 O(N) 命令。单线程模型下一条慢命令阻塞所有请求。解决用SCAN、HSCAN、SSCAN增量迭代替代全量命令。排查时看慢查询日志slowlog-log-slower-than设一个阈值比如 10000 微秒把慢命令记下来。5.4 现象内存占用比预期高很多删了 key 也没降原因过期 key 惰性删除没被访问就不释放或者大量小 key 的元数据开销累积。解决用SCAN配合TTL找出过期未删的 key主动DEL。评估内存时把每个 key 的元数据开销算进去别只算值的大小。5.5 现象主从同步时从机数据比主机旧原因主从复制是异步的主机写完后立即返回同步到从机有延迟。分享里提到「主机从机的宕机都会导致前端部分读写请求失败」就是这个窗口。解决对一致性要求高的读走主机能容忍延迟的读走从机。别默认从机数据实时一致。6. 从「会用」到「敢调」把配置项当成设计决策来读回头看这份分享里的配置表每一条其实都是一个设计决策的暴露面。timeout 0表示不主动断开空闲连接省了重连开销但占着文件描述符tcp-backlog 511是三次握手队列长度高并发下太小会丢连接databases 16给了 16 个逻辑库但集群模式下只有 0 号库可用。这些不是「默认值背下来就行」而是要知道改了会动到什么。我自己的习惯是每次动持久化配置前先问三个问题这份数据丢了能不能从源头重建能接受多长的丢失窗口恢复时能等多久这三个答案基本就决定了 RDB 和 AOF 怎么配。RDB 适合「能重建、要快恢复」AOF 适合「不能丢、能等恢复」两个都要就同时开接受 AOF 恢复慢的代价。另一个值得建立的判断是Redis 的快来自「内存 单线程 原子命令」这套组合任何破坏其中一环的操作都会让它变慢。大 key、全量遍历命令、频繁 fork都是在跟这套设计对着干。排查性能问题时先看有没有这类操作比盲目加机器有效得多。至于在线扩容难这个缺点本质是数据分片和迁移的复杂度问题不是配置能解决的。容量规划要提前做别等集群满了才想扩。这份分享把命令、配置、持久化、事务、发布订阅都覆盖到了适合当成一份随时翻的底稿——不是背命令而是理解每条命令和每个配置背后的取舍。需要完整内容的话可以顺着这份材料把每个机制自己跑一遍比只看结论扎实得多。希望帮到你。本文还有配套的精品资源点击获取