
我第一次把 Redis 装进项目是因为一个统计接口慢到被领导约谈。当时那个接口在 MySQL 里跑了将近 3 秒产品急着要数据数据库已经扛不住持续的业务流量。我从缓存两个字开始搜搜到了 Redis试了一下午接口从 3 秒降到了几十毫秒。从那以后Redis 几乎成了我每个项目的标配。这篇教程是给真心想入门 Redis 的人写的不管你是在 Windows 上折腾下载安装还是想用 Docker 一条命令跑起来不管你是想搞懂数据类型、可视化客户端怎么选还是已经在 Java 项目里被 RedisTemplate 的 increment() 报错折磨过这篇文章都会给你一条清晰、能照着做的路径。我尽量把每一个步骤背后的为什么也讲清楚而不是只丢给你命令。1. 先别急着装搞懂Redis为什么快才是正经事1.1 Redis到底是什么RedisRemote Dictionary Server是开源的、基于内存的键值对存储系统。你可以把它理解成一个超大的 HashMap只是这个HashMap经过了专门优化支持的数据结构远不止字符串而且数据全部存放在内存里所以读写速度极快。单机跑几万 QPS 是常态配合 Pipeline 甚至能上十万这是传统关系型数据库很难达到的量级。和 MySQL 这类数据库不一样Redis 不要求你先设计表结构你直接塞一个user:123 - {name: zhangsan, age: 25}进去就能用。也正是因为这一点很多人误以为 Redis 只是个高级缓存。但实际上缓存只是 Redis 最常见的用法它还被大量用于分布式锁、排行榜、计数器、限流、消息队列、Session 共享等场景。缓存数据库这四个字其实低估了它的价值。1.2 单线程为什么还这么快初学 Redis 时很多人都会纠结一个点现在服务器动不动几十核Redis 为什么长期保持单线程模型它还能这么快靠的是什么答案主要是两条。第一Redis 的数据全在内存里内存访问速度比磁盘快几个数量级这是它快的根本第二Redis 用 IO 多路复用机制让一个线程可以同时处理成千上万个网络连接配合事件驱动模型避免了多线程上下文切换和锁竞争的开销。四个字总结就是对症下药——既然瓶颈在网络 IO 和内存访问没必要用多线程给自己增加复杂度。需要注意Redis 的单线程指的是命令执行引擎是单线程的从 6.0 开始网络 IO 部分已经支持多线程了。这个特性带来一个重要的实际价值所有命令都是有序、原子执行的所以你不需要担心多个客户端同时对同一个 key 做INCR会产生竞态问题。但单线程也有单线程的代价。如果某条命令本身就特别耗时比如在超大 key 上执行KEYS *整条命令执行期间会阻塞 Redis其他所有请求都要排队等着。这也是为什么生产环境里面KEYS命令基本是禁用状态后面我会再提。1.3 内存数据库为什么还要持久化既然 Redis 是内存数据库有人就会问那宕机了数据不就全丢了吗生产环境为什么还敢大规模用它这就牵扯到 Redis 的持久化机制主要是 RDB 和 AOF 两种。RDB 是生成某一时间点的二进制快照文件通过 fork 子进程把内存数据写入磁盘恢复速度非常快适合做备份和灾难恢复。缺点是两次快照之间的数据可能丢失。AOF 则是以日志形式记录每一次写操作数据安全度高但同样的数据量下 AOF 文件更大恢复也慢一些。实际项目里经常两种同时开启重启时优先用 AOF 恢复保证数据尽量不丢。如果你的 Redis 只是纯缓存丢了也能从数据库重建那可以只开 RDB 甚至完全不开启持久化性能会更好。这个取舍没有标准答案取决于你对数据丢失的容忍度这也是面试很爱考的点。2. Windows和Docker两条路装Redis我替你踩过的坑都写出来了2.1 Windows本机安装官网根本不给你装包很多人一上来就搜redis下载“redis安装”冲到官网 redis.io 找了半天发现官方只提供 Linux 源码和 Docker 镜像没有 Windows Installer。原因很简单Redis 官方并不支持 WindowsWindows 版本是社区维护的。所以你在 Windows 上装 Redis通常就两条路用第三方维护的 Windows 移植版或者用 WSL/Docker 跑一个 Linux 环境。如果只是本地开发调试推荐去 GitHub 下载第三方仓库编译好的 Windows 版本比如 tporadowski/redis。下载 zip 解压后目录里有redis-server.exe和redis-cli.exe。双击启动redis-server.exe它默认监听 6379 端口然后打开另一个命令行窗口执行redis-cli.exe ping返回PONG就说明服务已经起来了。想把 Redis 注册为 Windows 服务随开机自启可以用redis-server --service-install redis.windows-service.conf --service-name Redis redis-server --service-start --service-name Redis有一点要提醒你这种 Windows 移植版版本通常落后官方我在本地装过 6.0 系的第三方编译版日常开发够用但 7.x 的新特性就用不上。如果你的生产环境都是 Linux强烈建议直接走 Docker。2.2 Docker方式安装一条命令和一份compose文件Docker 是现在最推荐的安装方式因为镜像和 Linux 生产环境几乎完全一致不存在 Windows 移植版的差异。先确保本机有 Docker然后执行docker run -d --name redis -p 6379:6379 redis:7.2没有 redis 镜像时 Docker 会自动拉取这就是很多人搜redis镜像的原因。容器起来后执行docker exec -it redis redis-cli ping输出PONG就成功。但真实项目里很少有人直接docker run裸跑。我更习惯用 docker compose 管理因为配置、持久化、密码都写在文件里换机器一键起来。一个适合入门的docker-compose.yml长这样services: redis: image: redis:7.2 container_name: redis restart: always ports: - 6379:6379 command: [redis-server, --requirepass, yourpassword, --appendonly, yes] volumes: - ./redis-data:/data--appendonly yes开启 AOF 持久化数据写入容器内/data目录通过 volume 挂载到宿主机容器删了数据也不丢。这个配置虽然是入门级别但已经是生产部署的雏形了。后面第 6 节我会给出带主从的 compose 方案。2.3 装完先改三件事否则迟早踩坑Redis 默认配置可以直接连但有三件事我建议第一时间改掉这是很多线上事故的源头。第一设置密码。redis.conf 里加一行requirepass yourpassword不设密码如果 Redis 暴露在公网或云服务器上扫描器扫到 6379 端口就可以直接清库。第二限制绑定地址和 protected-mode。本机使用就把 bind 设为127.0.0.1保持protected-mode yes。需要远程访问时绑定了外网 IP那更要有强密码并且通过防火墙限制来源 IP。Redis 的 protected-mode 是在没有密码且没有绑定外网地址时自动拒绝远程连接的一种保护机制新手经常被它莫名其妙拦住后面可视化客户端一节我会详细讲。第三提前配置日志和持久化路径。本地调试无所谓生产环境一定要把logfile、dir、dbfilename配置成可管理的路径否则日志写到哪都不知道。安装方式版本一致性上手难度适用场景Windows 移植版滞后低本地快速验证Docker与官方一致低开发、生产、跨环境统一编译源码完全一致高需要定制化编译3. 五种数据类型把Redis从缓存工具变成数据结构服务器3.1 String最简单也最容易被用错String 是 Redis 里最基础的类型value 就是一个字符串最大长度 512MB。常用命令无非是SET、GET、DEL加上一组数值命令INCR、DECR、INCRBY、DECRBY。很多人以为 String 只能存普通字符串实际上INCR系列命令会把 value 当作十进制数字处理所以它天然适合做计数器文章浏览量、接口调用次数、限流计数、分布式 ID 生成等。这里有个细节非常容易踩坑INCR对 value 有严格要求值必须是数字字符串否则会报value is not an integer or out of range。这个报错在 Java 项目里很常见我第 5 节会单独复盘。另外不建议把对象直接序列化成一整坨 JSON 塞进 String。如果对象经常要更新某个字段整体读出来改再写回去成本很高这种场景应该优先考虑 Hash。3.2 Hash、List、Set、ZSet四种场景导向的类型Hash 类型可以理解成一个 field-value 映射表最适合存对象。比如HSET user:123 name zhangsan age 25 HGET user:123 name相比整个 JSON 塞进 StringHash 支持只改某个字段不用整体反序列化和重写。List 是链表结构支持两端推入弹出典型场景是消息队列和时间线。用LPUSH加BRPOP可以做一个简单的任务队列LTRIM可以控制列表只保留最近 N 条。Set 是无序集合天然去重支持交集、并集、差集运算。典型场景是用户标签、共同好友计算、抽奖随机去重。SADD添加元素SINTER求交集一行命令就能拿到两个集合的交集。ZSet 在 Set 基础上加了一个 score 排序字段根据分数排序并支持范围取值这是排行榜场景的标配。用户 ID 作为元素分数作为 scoreZREVRANGE直接拿 Top N。类型底层结构常用命令典型场景String动态字符串SET / GET / INCR缓存、计数器、分布式锁Hash哈希表 / 压缩列表HSET / HGET / HGETALL存储对象、用户信息List双向链表 / 快速链表LPUSH / BRPOP / LRANGE消息队列、时间线Set哈希表 / 整数集合SADD / SINTER / SPOP去重、标签、抽奖ZSet跳表 / 压缩列表ZADD / ZINTER / ZREVRANGE排行榜、实时排名3.3 过期时间、惰性删除和内存淘汰Redis不会无限变大新手很容易忽略一件事Redis 数据全在内存里内存是有限且昂贵的所以它必须有过期清理和内存淘汰机制。每个 key 都可以设置过期时间EXPIRE key seconds或者SET时带EX参数。Redis 对过期 key 的清理不是到点就删而是采用惰性删除 定期删除两种策略结合。你访问一个已过期的 key 时它才会被标记删除后台同时定期采样一批 key把过期的大批量数据清掉。如果 key 没设过期时间内存又满了Redis 根据maxmemory-policy触发淘汰。默认策略是noeviction内存满时写操作直接报错。常用策略还有allkeys-lru淘汰最近最少使用的 key、volatile-lru只在设置了过期时间的 key 中淘汰、allkeys-random等。缓存场景一般用allkeys-lru就够。理解了这套机制缓存雪崩这个问题就好解释了。大量 key 同一时间过期请求全部打到数据库这就是雪崩。解决思路是在过期时间上增加随机偏移避免集体失效。4. 可视化客户端工具RDM和Another Redis Desktop Manager怎么选4.1 工具横向对比命令行操作 Redis 适合调试但日常维护、查看数据、分析 key 分布时没有图形界面确实抓狂。我最早用的是 Redis Desktop ManagerRDM老牌工具UI 成熟但新版本已经转向商业授权免费版功能受限。现在更多人用 Another Redis Desktop ManagerGitHub 开源的跨平台客户端支持 Windows、macOS、Linux中文界面连接管理、key 查看、命令执行、SSH 隧道都支持免费易用。还有一款官方出品的 RedisInsight完全免费支持数据分析、慢日志、集群拓扑展示适合排查性能和做深度管理。工具收费情况跨平台主要偏好Redis Desktop Manager商业授权是老牌用户Another Redis Desktop Manager开源免费是日常开发维护主力RedisInsight免费是性能分析、集群管理工具没有绝对好坏我的建议是日常开发用 Another Redis Desktop Manager因为轻量排查性能和 debug 数据时用 RedisInsight官方工具能直接看到集群、内存、命令统计这类深层信息。4.2 连接不上时按这个顺序排查很多初学者连客户端工具时会遇到connect to redis at 127.0.0.1:6379 failed这种问题。我按踩坑频率高低给你一个排查顺序。第一步确认 Redis 真的启动了本机执行redis-cli ping如果能返回 PONG服务就是活的。第二步看 bind 和 protected-mode 配置。如果 bind 只写了127.0.0.1那远程客户端必然连不上。远程连接需要改成bind 0.0.0.0或具体网卡 IP并确认protected-mode no或设置了密码。第三步看密码。如果设置了 requirepass客户端必须填密码否则会报NOAUTH Authentication required。第四步检查防火墙和云服务器安全组。本机连不上可能是 Windows 防火墙拦截了 6379 端口云服务器连不上基本是安全组没放行 6379。最后多说一句允许外部连接时一定先设置强密码否则就是让 Redis 裸奔在公网这和给攻击者送人头没什么区别。5. Java接入Redis从RedisTemplate到increment()报错的完整复盘5.1 引入依赖和基础配置Java 生态里现在基本都是 Spring Boot 整合 Redis。先在 pom.xml 引入dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency然后在 application.yml 配置连接信息spring: data: redis: host: 127.0.0.1 port: 6379 password: yourpassword timeout: 3000ms注意不同 Spring Boot 版本的配置前缀不一样2.x 是spring.redis3.x 开始改成spring.data.redis。这个差别不大但每次都有人栽在这里。5.2 序列化问题为什么key在客户端里是一堆乱码Spring Data Redis 提供一个叫 RedisTemplate 的高级封装但默认使用 JdkSerializationRedisSerializer 来序列化 key 和 value。这个序列化器会把 Java 对象转成二进制字节流所以你在客户端里看到的 key 可能长这样\xac\xed\x00\x05t\x00\x0cuser:123不仅不可读更坑的是相同 key 如果换序列化器去读会被当成不同的 key完全对不上。这是 Spring 整合 Redis 最典型的坑。解决办法是显式配置序列化器key 用 StringRedisSerializervalue 用 GenericJackson2JsonRedisSerializerConfiguration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } }如果你只操作字符串键值对Spring Boot 还提供了 StringRedisTemplate默认就是字符串序列化。一个关键经验是同一个 key 一旦用某种方式写入读取和运算时必须用同一种序列化器中途不要换来换去否则各种类型转换异常会让人怀疑人生。5.3 increment()报错value is not an integer or out of range的完整排查有一个很具体的搜法java中redis使用redistemplate的increment()报错不是integer or out of range。我也被这个问题折磨过。当时是在记录商品访问次数redisTemplate.opsForValue().increment(product:visit:1001);第一次调用就抛异常提示 value 不是整数或超出范围。排查过程如下。方向一key 的位置存了非数字内容。比如这个 key 之前用opsForValue().set()放过对象对象序列化后变成二进制内容Redis 尝试把二进制解析成十进制自然失败。更隐蔽的是用 JSON 序列化器存过10它实际存的可能是带引号的字符串10同样解析失败。方向二序列化器不一致。比如同一个 key项目某处用 StringRedisTemplate 写入另一处用 RedisTemplate 读取两边序列化方式不同value 的底层字节流对不上。排查时用可视化客户端打开这个 key看一眼实际存的值到底是什么类型很快就能定位。解决办法分两种。如果业务写入逻辑有问题就去改写入位置的代码确保存的是数字字符串或 Long 类型。如果已经写了脏数据删掉这个 key 重新写入正确值或者换一个新 key 名同时统一所有读写操作的序列化方式。这里我强烈建议项目中所有对同一个 key 的操作都统一放在同一个 Service 层别在 Controller 里到处直接调用 RedisTemplate不然这种问题会反复出现。5.4 分布式锁SET NX EX和Redisson哪个靠谱redis分布式锁是搜索热词。为什么要用 Redis 做分布式锁因为多个服务实例同时操作同一个临界资源时Java 内置的 synchronized 和 JVM 锁无法跨进程生效需要一个所有服务都能访问的第三方来协调Redis 天然适合。最基础的命令是SET lock:order:1001 uuid_value NX EX 30NX表示 key 不存在时才能设置成功EX 30表示锁自动过期时间 30 秒。设置成功表示抢到锁业务处理完后删除锁释放锁。但直接用这条命令有个经典问题如果业务执行时间超过 30 秒锁自动过期了另一个线程又抢到锁这时第一个线程业务结束把第二个线程的锁删了造成锁失效和并发问题。更稳的做法是删除锁之前先检查 value 是否是自己写入的唯一标识再用 Lua 脚本保证判断 删除两步原子性if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end生产项目里我通常直接用 Redisson 框架它封装了看门狗自动续期机制锁没执行完会自动延长过期时间从根上避免锁提前过期。新手学分布式锁先搞懂 SET NX EX 和 Lua 原理再跳到 Redisson理解会清晰很多。6. 缓存治理与生产环境部署入门之后必须补的课6.1 缓存穿透、击穿、雪崩三兄弟要分清缓存相关的面试题里穿透、击穿、雪崩几乎必考。我用大白话拆解一下。缓存穿透是查询一个根本不存在的数据。比如用户传了一个不存在的商品 ID缓存没有数据库也没有于是每次请求都穿过缓存打到数据库数据库压力巨大。解决思路有两个一是缓存空值把查不到的结果也缓存一份设置较短过期时间二是在缓存前面加布隆过滤器把可能存在的数据 ID 预先放进去不存在就直接拦截请求根本到不了数据库。缓存击穿是某一个热点 key 在过期的一瞬间大量请求同时打过来全都打到数据库。解决思路是互斥锁缓存失效时只允许一个请求去数据库重建缓存其他请求等待或者采用逻辑过期方案在 value 里记录一个逻辑过期时间异步重建真正的缓存用户拿到的还是旧数据保证可用性。缓存雪崩是大量 key 在同一时间段集体过期或者 Redis 服务整体宕机导致所有请求瞬间打到数据库。针对过期给过期时间加随机值最简单针对宕机要靠 Redis 集群、主从架构、限流降级等方案兜底。这三个问题的共同核心是在缓存失效时怎么保护数据库。你可以从拦截无效请求限制并发重建错开过期时间保持高可用四个角度设计自己的方案。6.2 Docker Compose部署Redis主从从单机走向高可用很多人搜docker安装redis主从主从复制是 Redis 高可用的基础。主节点负责写从节点负责读和备份主节点宕机后从节点可以晋升为主节点继续服务。用 docker compose 部署一个最小主从结构可以这样写services: redis-master: image: redis:7.2 container_name: redis-master restart: always ports: - 6379:6379 command: [redis-server, --requirepass, masterpass, --appendonly, yes] redis-slave: image: redis:7.2 container_name: redis-slave restart: always ports: - 6380:6379 depends_on: - redis-master command: [redis-server, --slaveof, redis-master, 6379, --masterauth, masterpass, --appendonly, yes]从节点的--slaveof让它复制主节点数据--masterauth完成主从认证。启动后在主节点写入任意 key在从节点都能查到。这还只是高可用第一步。生产环境通常加哨兵做自动故障转移或者直接用 Redis Cluster 分片集群。对入门阶段来说先把主从复制跑通理解数据怎么同步的已经是一大步了。6.3 日志、慢日志和性能排查最后聊一个不太被新手重视但线上非常关键的模块Redis 日志和慢查询。日志级别通过loglevel配置有 debug、verbose、notice、warning 四个级别。生产环境一般用 notice 或 warning避免日志量过大拖累性能。debug 只在本地调试用千万不要在生产开。慢日志是排查性能问题的利器SLOWLOG GET可以查看执行时间超过阈值的命令。常见慢命令包括大量 key 遍历、超大的 value、大集合上的复杂操作。定位后优化方向一般是拆分大 key、避免KEYS、改用SCAN分批遍历、给 value 大小设上限。监控方面经常看看INFO命令的输出重点关注used_memory、connected_clients、instantaneous_ops_per_sec这几个指标。进阶一点可以接入 Prometheus Grafana通过 redis_exporter 展示完整监控面板。入门阶段先把INFO读明白比什么都强。最后分享一个我个人的体会。学 Redis 最忌讳的就是光看命令不动手我见过太多人背了一堆命令面试全对一上手连 redis-cli 都找不到。你完全可以在 30 分钟内完成安装、启动、操作数据类型、查看持久化文件这一整套闭环再去看分布式锁、主从集群这些进阶话题整个人会有一种打通了任督二脉的感觉。这篇教程里的所有命令和配置建议你都亲手跑一遍遇到报错才是学习的真正开始。