Redis 大概是后端技术栈里“学了就会用用了就想吐槽吐槽完还得接着用”的典型代表。你说它难吧日常无非是 get/set 那几个命令你说它简单吧真到缓存穿透、分布式锁、序列化乱码这些场景翻车的人一抓一大把。这份速记不是从零开始的完整教程而是我自己这几年在项目里折腾 Redis 攒下来的笔记。内容覆盖面比较杂包括Windows 和 Docker 环境下的安装部署、五种核心数据类型的选型思路、GUI 连接工具的选择与避坑、分布式锁和序列化两个高频翻车点、缓存穿透/击穿/雪崩的治理套路、日志与慢查询的排查方法外加一份面试题底层逻辑速记。不管你是在校生准备面试还是后端开发想把手上的 Redis 用得更稳这份笔记应该都能帮你省掉一些试错的时间。需要提前说明的是文章里的命令和配置我都在 Redis 6.x/7.x 上验证过如果用的是老版本比如 3.x/4.x个别参数可能对不上务必以你本机的redis-server --version为准。1. 安装部署这块先把坑摸清楚1.1 Windows 安装路线怎么选很多人在公司用的是 Windows 笔记本本地调试想装个 Redis搜“redis下载”就懵了官方不提供 Windows 安装包Windows 版只是社区维护的移植分支。所以在看到某个所谓的“redis下载官网”时先看清楚站点到底是不是官方再决定装不装。我在 Windows 上装 Redis 的三种方式按推荐程度给你排个序用 WSL 装官方版。sudo apt update sudo apt install redis-server就完事了版本跟 Linux 一致不会踩 Windows 移植版的坑。缺点是 WSL 2 的网络端口映射偶尔让人头疼需要确认宿主机能访问到 WSL 里的 6379。直接下载社区维护的 Windows 二进制包比如 tporadowski/redis。解压后redis-server.exe就能跑胜在省事适合快速验证。注意这类包没有注册 Windows 服务重启之后不会自动启动。用 Chocolatey 包管理器choco install redis-64。装完环境变量自动配好命令随便敲适合喜欢包管理器的同学。这里有个 Windows 特有的坑很多教程让你双击 exe 启动结果窗口一关 Redis 就没了。你在本地调试还行但要是想让它常驻得注册成服务才行。1.2 Docker 单机和主从部署搜“docker安装redis主从”能翻出一大堆教程但多数只是把两个容器跑起来就算完事完全没考虑持久化、密码、节点间认证。我这边给一份能直接拿去用的docker-compose.yml思路很简单主节点负责写从节点负责读两者配置都挂载出来方便改参数。version: 3.8 services: redis-master: image: redis:7.0-alpine container_name: redis-master restart: always ports: - 6379:6379 command: [redis-server, /usr/local/etc/redis/redis.conf] volumes: - ./master/redis.conf:/usr/local/etc/redis/redis.conf - ./master/data:/data redis-slave: image: redis:7.0-alpine container_name: redis-slave restart: always ports: - 6380:6379 command: [redis-server, /usr/local/etc/redis/redis.conf] volumes: - ./slave/redis.conf:/usr/local/etc/redis/redis.conf - ./slave/data:/data depends_on: - redis-master从节点的配置文件里核心就三行slaveof redis-master 6379 masterauth yourpassword requirepass yourpassword注意masterauth不能少。主节点设了密码后从节点同步数据时必须先完成认证否则日志里会持续刷MASTER aborted replication with an error: NOAUTH Authentication required。这个过程不会立刻报错但读从库你会发现数据一直不更新属于那种“看起来没事、其实已经坏了”的隐蔽故障。官方镜像选哪个 tag搜“redis镜像”的话我建议直接用redis:7.0-alpine。alpine 版本体积小、依赖少生产环境省内存该有的功能一个不少。如果你是给公司建内部基础设施记得顺便配一个私有镜像仓库别让公网镜像源成为你部署链路上的单点。1.3 配置参数改错了可能直接玩崩Redis 的默认配置在本地跑没问题但放到生产环境有几个参数是必须改的。我把最重要的汇总成一张表参数默认值建议备注maxmemory0不限制按机器内存的 70% 设置超过后触发淘汰策略maxmemory-policynoeviction缓存场景用allkeys-lrunoeviction会导致写命令直接报错appendonlynoyes开启 AOF 持久化防重启丢数据save多条按业务保留RDB 快照的触发条件requirepass空生产必设别用太简单的密码bind127.0.0.1按需改改成0.0.0.0时一定配合密码最容易被忽略的是maxmemory-policy。我见过不止一次这样的情况团队把 Redis 当缓存用但没配淘汰策略流量一上来内存就被打满然后所有写命令返回OOM command not allowed when used memory maxmemory接口瞬间全挂。最简单的做法就是理解清楚allkeys-lru适合纯缓存不设过期时间的 key 也会被淘汰volatile-lru只淘汰设置了过期时间的 key适合部分数据需要留存的场景。2. 数据类型别背命令先想场景2.1 五种基础类型速查表Redis 的数据类型面试必考、实战必用。这里我按“结构特点、常用命令、典型场景”三个维度做个速查String最简单的 KVvalue 可以是字符串、数字或二进制。常用命令SET、GET、INCR、DECR、SETNX。典型场景计数器、分布式 ID、缓存热点数据。Hashfield-value 的散列结构适合存对象。常用命令HSET、HGET、HGETALL。典型场景用户资料、商品详情、配置项。相比把整个对象序列化成 StringHash 可以单独操作某个字段节省带宽。List双向链表支持头尾插入弹出。常用命令LPUSH、RPUSH、LPOP、BRPOP。典型场景消息队列简单的任务排队、最近列表。BRPOP是阻塞读取适合做简单的消费者模式。Set无序去重集合。常用命令SADD、SPOP、SMEMBERS、SISMEMBER。典型场景标签、好友关系、抽奖去重。SISMEMBER判断成员是否存在是 O(1)。ZSet有序集合每个成员带一个 score按 score 排序。常用命令ZADD、ZRANGE、ZREVRANGE、ZSCORE。典型场景排行榜、延迟队列、限流滑动窗口。底层是跳表 哈希表插入和查询都是 O(logN)。2.2 三个真实场景教你怎么选光看表还是容易迷糊我用三个工作中真实遇到过的场景来说明。第一个是排行榜。需求是展示用户积分前 100支持实时更新排名。用 ZSet 是天然适配ZADD rank 100 user_1写入或更新积分ZREVRANGE rank 0 99 WITHSCORES查前 100 名ZREVRANK rank user_1查某个用户的排名。三条命令解决全部 O(logN)。如果不用 ZSet你要么在数据库里建排行榜表要么用 Redis 的 List 每次全量排序都很别扭。第二个是“最近浏览记录”。很多人第一反应是 ListLPUSH history user_1 product_2然后LTRIM history user_1 0 99截断。但你要是想判断“这个商品用户是不是已经浏览过”List 只能遍历很尴尬。更好的做法是 Set 和 List 配合Set 负责去重List 负责顺序。写入时先SADD返回 1 说明是第一次浏览才LPUSH压入列表。第三个是防重的限流场景。比如限制某个用户每分钟最多请求 10 次。简单粗暴的写法是用一个过期 key 计数SET rate:user_1001 1 EX 60 NX后续INCR并判断是否超过阈值。更优雅的方案是用 ZSet 做滑动窗口score 存时间戳每次请求ZREMRANGEBYSCORE清理窗口外的记录再ZCARD统计窗口内请求数。窗口限流比固定窗口限流更平滑不会出现“最后 1 秒猛冲”的毛刺。顺带提一下 key 的命名。很多项目里 key 命名极其随意user_1001、u1001、user::1001混着来后期排查问题就是灾难。建议统一成业务名:实体名:ID的格式比如user:info:1001、cart:list:1001。冒号分隔写起来清晰用SCAN批量匹配时也方便。3. 连接工具与日常操作3.1 选 RDM 还是 Another RDM搜“redis desktop manager”或“redis连接工具”时市面上主流的 GUI 客户端其实就那几个。我个人的建议是如果你在 Redis 7 上工作直接用 Another Redis Desktop ManagerARDM如果你还在用老版本 RedisRDM 免费版也能满足日常需求。RDMRedis Desktop Manager是老牌工具界面简洁连接、看 key、执行命令都很快但免费版在 Redis 7 的数据类型展示上有些兼容问题。ARDM 是基于 Electron 的开源客户端界面现代支持暗色主题和树形 key 展示团队排查问题的时候比纯命令行直观很多。它的内存占用稍微高一点但这在 GUI 工具里属于正常水平不影响体验。使用 GUI 工具时有个经常被忽略的细节数据库编号。Redis 默认有 16 个逻辑库db0 到 db15很多项目只用 db0但有些项目会切到 db1 存缓存、db2 存临时数据。你如果连上工具后发现看不到 key先去右上角切换一下数据库编号十有八九能解决。另一个安全细节连接生产环境时务必用密码连接并且别把 6379 端口暴露到公网。有些人图方便把 Redis 端口映射到云服务器公网没设密码或密码很弱结果被扫描器爆破数据被删、被勒索的新闻你肯定看过。生产环境的 Redis宁可访问麻烦一点也不要裸奔在公网上。3.2 命令行速查与生产禁用命令GUI 工具再方便命令行永远是最后那道保险。这里整理一份我平时最常用的命令备忘# 连接与认证 redis-cli -h 127.0.0.1 -p 6379 -a yourpassword AUTH yourpassword # Key 操作 SET key value [EX seconds] [NX] GET key EXISTS key DEL key TTL key EXPIRE key 60 # 各类型常用命令 HSET user:1001 name 张三 age 30 HGETALL user:1001 LPUSH queue task1 BRPOP queue 0 SADD tags:1001 vip SISMEMBER tags:1001 vip ZADD rank 100 user_1 ZREVRANGE rank 0 9 WITHSCORES # 诊断命令 INFO memory INFO clients SLOWLOG GET 100 DBSIZE CLIENT LIST这里必须多说一句线上环境禁用KEYS *。Redis 是单线程模型KEYS *会遍历整个 key 空间数据量大时直接阻塞所有请求。需要批量遍历时用SCAN 0 MATCH user:info:* COUNT 100每次只返回少量 key不会卡主线程。这个坑我见得太多很多“Redis 突然卡死”的事故最后查出来都是有人手动敲了KEYS。4. 分布式锁与序列化两个高频翻车点4.1 分布式锁正确实现和容易“看着对”的写法搜“redis分布式锁”的人不是面试就是踩坑。我先把最常见的错误写法放在这里你看看眼不眼熟SETNX lock_key 1 # 执行业务 DEL lock_key这段代码至少有四个问题业务抛异常时锁永远不会释放进程崩溃时锁也会变成死锁锁超时但业务没执行完导致锁提前失效、两个线程同时进临界区解锁时没有校验持有者身份可能误删别人的锁。四舍五入这就是个雷区。行业里目前比较稳妥的落地方式有两个方向。方向一用 Redisson 的RLock它自带看门狗自动续期Java 生态直接引入依赖就不用管续期问题。方向二自己用 Lua 脚本保证加锁/解锁的原子性。-- 加锁SET 命令带 NX PX -- key: 锁名, value: 唯一标识, ttl: 过期时间(ms) if redis.call(set, KEYS[1], ARGV[1], NX, PX, ARGV[2]) then return 1 else return 0 end -- 解锁先比对唯一标识再删除 if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end为什么 value 里要存唯一标识因为如果不校验线程 A 的锁过期后被线程 B 抢到A 执行完直接DEL把 B 的锁给删了临界区就废了。用 UUID 做 value解锁前比对就能避免这种情况。这个细节在面试里也是高频考点回答“从 Redisson 源码讲起”比只说“加锁解锁”要加分不少。4.2 序列化乱码从现象到根源再到解法搜“redis序列化”的人绝大多数症状都一样用 Spring Boot 往 Redis 里存对象重启后读出来一串以\xAC\xED\x00\x05开头的乱码或者存进去的时候是对象读出来强转直接抛异常。这个问题的根源在于Spring Data Redis 默认用 JDK 序列化。JDK 序列化会把对象转成二进制字节流体积大、不可读而且要求类实现Serializable接口。解决办法是统一改用 JSON 序列化器。下面是一份我在项目里验证过的配置Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); StringRedisSerializer stringSerializer new StringRedisSerializer(); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); GenericJackson2JsonRedisSerializer jsonSerializer new GenericJackson2JsonRedisSerializer(); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }注意两个细节。第一key 用 String 序列化value 用 JSON 序列化不要一刀切。第二用GenericJackson2JsonRedisSerializer而不是普通 Jackson 序列化器因为前者会在 JSON 里自动带上class类型信息反序列化时才能还原成正确的类。还有一个很容易跟序列化混淆的问题泛型丢失。很多人在 Redis 里存了一个ListString读出来强转成ListString时报类型转换异常。原因不是序列化器问题而是反序列化时类型信息被擦除了。解决办法是读的时候用ObjectMapper的TypeReference来指定具体泛型类型或者直接存 JSON 字符串业务层自己解析。5. 缓存治理与日志监控5.1 缓存穿透、击穿、雪崩应对套路一次讲清这三个词是面试高频也是线上事故高发。我用自己的话说一遍顺便带做法。缓存穿透查询一个根本不存在的数据每次请求都会打到数据库。攻击者完全可以构造大量不存在的 ID 来拖垮你的数据库。应对手段有三种接口层做参数校验非法 ID 直接拒绝缓存空值把不存在的 key 也缓存 60 秒左右用布隆过滤器挡在前面。我这边推荐“参数校验 缓存空值”的组合性价比最高。布隆过滤器虽然好用但要考虑误判率和维护成本小项目不一定划算。缓存击穿某个热点 key 过期的一瞬间大量请求同时落到数据库。解法是互斥锁缓存没命中时先抢锁抢到锁的线程查库回填缓存其他线程等待锁释放后再查缓存。注意这里的锁要用上一条说的分布式锁别自己SETNXDEL糊弄过去。缓存雪崩大量 key 在同一个时间点集中过期数据库瞬间被打爆。解法是让过期时间分散开比如EXPIRE key (base random*300)另一个思路是热点数据永不过期由后台任务提前更新缓存。说个我踩过的真实例子曾经有个列表接口业务方把所有 key 的过期时间统一设成了整点后的第 30 分钟导致每天 10:30、11:30、12:30 这种时刻数据库压力都会有一个尖峰。后来改成“基础过期时间 随机偏移量”曲线就平稳了。这种问题排查起来非常难因为你不是每次都能注意到数据库压力尖峰和缓存过期时间的关系。5.2 日志与慢查询排查问题从哪下手搜“redis日志”的基本都是在线上遇到状况了。Redis 的日志体系分两块运行日志和慢查询日志。运行日志用logfile指定路径Docker 部署时建议挂载到宿主机logfile /data/redis.log loglevel noticeloglevel有四档debug、verbose、notice、warning。生产环境用 notice 就够debug 在流量上来的时候日志能刷到磁盘直接被打满。慢查询日志配置很简单slowlog-log-slower-than 10000 # 单位微秒这里表示 10ms slowlog-max-len 128查看方式SLOWLOG GET 50如果慢查询里频繁出现某个命令基本就是大 key 或者 O(N) 操作。最常见的有KEYS *、SMEMBERS、大数据量的HGETALL。解决方向是把大 key 拆分或者把一次取大量数据的逻辑改成多次增量读取。还有一个排查利器MONITOR命令能实时打印 Redis 收到的所有命令适合定位“到底是谁在连接 Redis、发了什么命令”。但生产环境慎用因为在高流量下它会把大量的命令输出到客户端反而拖垮 Redis。我一般只在测试环境或流量很低的时候用。6. 常见问题排查速查表6.1 连接类问题快查连接问题是最常见的入门问题直接上表现象原因排查步骤Could not connect to Redis at 127.0.0.1:6379Redis 没启动确认进程是否存在redis-server启动本机能连远程连不上bind配置限制检查redis.conf的 bind 项和防火墙连接报NOAUTH缺少密码认证用-a参数或AUTH命令连接后立刻断开日志提示max number of clients reached连接数超过maxclientsINFO clients查看连接数优化连接池必要时调大maxclients只有 Win 本机连不上 Docker Redis端口映射未开docker ps看端口绑定检查 Windows 防火墙客户端工具连不上命令行能连工具的 IP/端口/密码配置错误检查连接配置确认是否选择了正确的数据库编号6.2 内存与性能问题快查这类问题一出现就是线上事故我把经验浓缩成排查路径。内存问题先INFO memory看used_memory和maxmemory。如果内存持续上涨优先查 key 是否没设过期时间。用redis-cli --bigkeys能扫描大 key但注意这命令本身也是遍历式扫描挑业务低峰期跑。删除大 key 用UNLINK而不是DEL因为UNLINK是异步删除不会阻塞主线程。CPU 飙升Redis 单线程模型下CPU 高基本就是 O(N) 操作太多。用redis-cli --stat看实时请求量用SLOWLOG定位慢命令重点排查KEYS、SMEMBERS、HGETALL这些命令。命令超时如果慢查询日志为空但客户端确实超时检查网络往返时间用redis-cli --latency和客户端连接池配置别急着甩锅给 Redis。这里有个我每次写文档都会强调的小技巧给 Redis 做一个最小化的监控。不需要一上来就上 Prometheus Grafana 那套全家桶写个每分钟执行的脚本把INFO memory、INFO clients、SLOWLOG GET的关键字段打到日志或者群机器人就已经能提前发现 80% 的问题了。7. 面试题背后的底层逻辑7.1 高频问题与回答思路“redis面试题”能搜出一堆面经但很多都在背答案。我挑几个高频题讲清楚考官到底在考什么。Redis 为什么快考点内存操作 单线程避免上下文切换 IO 多路复用。可以额外提一句单线程也带来约束一个慢命令会阻塞所有请求所以KEYS要禁用。这样比单纯背“快因为内存”要立体。RDB 和 AOF 选哪个考点两种持久化的权衡。RDB 是快照型恢复快但可能丢最后一次快照后的数据AOF 是追加型根据fsync策略最多丢几百毫秒数据但文件大、恢复慢。生产上建议 RDB AOF 都开AOF 用于尽量减少丢失RDB 用于快速恢复。缓存和数据库一致性怎么保证考点无法做到强一致只能追求最终一致。我用的方案是“先更新数据库再删缓存”删缓存失败的兜底用消息队列重试。这里如果能把“为什么是删缓存而不是更新缓存”讲清楚面试官会觉得你真懂。Redis Cluster 为什么是 16384 个槽位考点CRC16 算法对 key 计算后取模得到槽位然后槽位分布到节点。回答时能补充“哈希槽的设计是为了数据均匀分布和扩缩容时的小范围迁移”就到位了。7.2 几个容易加分的深入点面试想拿高分光会背基础题不够还要能体现深度。我整理几个加分项。Redis 的 IO 多路复用到底是怎么工作的可以讲讲 epoll 和 select 的区别Redis 的事件循环文件事件和时间事件的调度。能讲到这个层次说明你不是只会用工具。分布式锁的 RedLock 到底好不好用很多大厂其实没用 RedLock因为它在极端网络分区下并不能保证绝对安全。如果你能说出这个观点并给出“业务幂等 简单锁”的兜底方案会让面试官眼前一亮。Redis 的淘汰策略和过期策略的区别过期策略是被动过期访问时检查 定期抽样删除淘汰策略是内存满了以后主动删。很多人会把两者混为一谈能分开讲就是加分项。大 key / 热 key 的治理方案大 key 的问题在于阻塞和网络开销解决方案是拆分、压缩、异步删除热 key 的问题是单点压力解决方案是本地缓存、读写分离、多副本。这些在你的简历项目里最好都真实做过面试时才能讲出细节。回想这些年和 Redis 打交道的经历我最想分享的不是某个具体命令而是一种处理问题的思路先看数据是怎么流动的再看每个环节可能挂在哪最后再决定用什么命令去解决。安装、数据类型、GUI 工具是“术”分布式锁、序列化、缓存一致性是“道”。这份速记是我自己踩坑换来的总结你拿去用的时候也建议每一条都亲手验证一遍。后面的路还长Redis 的生态还在不断演进希望这份笔记能陪你走一段省下一些本来可以避免的夜宵和凌晨三点。