
Redis从入门到集群这一篇就够了附踩坑实录写在前面本文整理自Redis全套学习笔记从基础概念到主从、哨兵、集群实战一条龙讲透。建议收藏面试前翻出来再看一遍。一、Redis 是个啥RedisRemote Dictionary Server是完全开源的遵守 BSD 协议是一个高性能的key-value 数据库。1.1 Redis 的三大特点数据持久化可以把内存中的数据存到磁盘重启后还能加载回来不然断电就寄了丰富数据结构不止支持简单的 key-value还提供 list、set、zset、hash 等数据结构数据备份支持 master-slave 模式的数据备份1.2 Redis 有多快对比项RedisMySQLQPS10万~100万几千~几万响应时间微秒级毫秒级存储位置内存磁盘白话理解Redis 就是个内存里的超级大字典查东西直接翻内存不用像MySQL那样翻硬盘速度快几个数量级。1.3 五种数据类型Redis 支持五种基础数据类型string字符串最基础hash哈希存对象list列表有序可做队列set集合无序去重zset(sorted set)有序集合排行榜神器1.4 哈希槽是个啥Redis 集群把整个键空间划分为16384 个哈希槽0-16383这是经过大佬们权衡后拍板的固定数量。映射公式HASH_SLOT CRC16(key) mod 16384为啥是16384不是16万也不是160万163842^14这个数字在心跳包大小和集群扩展性之间取得了完美平衡。说白了就是大佬算过了这个数最合适。二、Redis 都能用在哪些地方2.1 热点数据缓存最经典电商、社交等高频访问场景把热点数据商品详情、用户信息缓存到 Redis大幅降低数据库压力。实现要点缓存策略Cache-Aside 模式先查缓存没命中再查库并更新缓存过期控制设置合理的 TTL别让脏数据一直待着键设计业务前缀:唯一标识如product:info:1001空值处理查不到的数据也缓存个空值短TTL防止缓存穿透2.2 分布式锁分布式系统中多个服务要抢共享资源时用SET NX命令实现分布式锁。# 加锁不存在才设置过期时间30秒SET lock:order:1001 uuid123 NX PX30000# 解锁必须用Lua脚本原子判断删除不然会误删别人的锁EVALif redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end1lock:order:1001 uuid1232.3 计数器与限流INCR原子递增命令天然适合做计数器结合过期时间就是限流。文章阅读量、视频播放次数接口访问频率限制每分钟最多100次秒杀活动库存计数2.4 排行榜系统Sorted Set有序集合完美适配排行榜按分数实时排序。商品销量榜、用户积分榜游戏排行榜实时投票结果2.5 其他常见场景场景用啥实现分布式会话String/Hash 存session简单消息队列List LPUSH/BRPOP用户签到Bitmap 位图附近的人/店铺GEO 地理坐标三、Redis 为啥这么快3.1 单线程模型重点面试必问Redis 6.0 之前一直是单线程处理请求为啥单线程还这么快纯内存操作数据都在内存里不像数据库要折腾磁盘核心功能简单就是读写内存不像数据库还有约束、联合查询啥的额外开销避免线程竞争单线程不用加锁没有线程切换的开销IO多路复用用 epoll 一个线程管一堆 socket⚠️注意说Redis是单线程其实不太准确早期版本是单进程单线程处理请求但后台还有其他线程干特定的活比如fsync刷盘、关闭文件描述符。3.2 IO多路复用epoll举个生活化的例子select模式你去买烧烤、饺子、炒菜自己在三个摊位之间来回跑着问好了没——效率低epoll模式你先去三个摊位下单跟老板说好了叫我然后该干嘛干嘛哪个好了老板喊你——一个人等三份饭效率高Linux 上三套IO多路复用APIselect你自己挨个问没人提醒你性能差poll和select差不多有点改进epoll事件通知/回调机制哪个socket有数据了内核主动通知你Redis用的就是这个3.3 Redis 使用注意事项一次只执行一条命令别搞长命令避免慢命令keys *、flushall、flushdb、大集合操作、慢Lua脚本生产环境千万别随便用keys *分分钟把Redis打挂四、缓存三大坑穿透、击穿、雪崩这三个概念面试100%会考必须分清楚4.1 缓存雪崩定义缓存层大面积失效比如同一时间批量过期或者Redis服务宕机所有请求瞬间涌入数据库把数据库搞崩。通俗理解游乐场所有出口的闸机同时坏了几千人一下子全冲向检票口大门直接被挤爆。发生场景批量Key同时过期比如电商首页1000个商品缓存都设了10分钟时间一到全打库Redis集群宕机请求无路可走直接穿透到DB解决方案过期时间加随机值10分钟 1~5分钟随机打散过期时间搭建高可用集群多主多从、哨兵模式避免单点故障服务限流熔断用Sentinel或Hystrix限制并发保护数据库多级缓存本地缓存Guava RedisRedis挂了本地还有数据4.2 缓存穿透定义查询一个根本不存在的数据缓存里没有数据库里也没有每次请求都绕过缓存直接查数据库。通俗理解你拿张假身份证去检票检票员Redis说没这票让你去后台查数据库。后台查半天也没有就让你回去了。结果来一万个拿假身份证的后台直接累瘫。发生场景攻击者恶意查询user_id -1或不存在的商品ID业务代码Bug导致反复查无效Key解决方案接口层校验ID做基础校验id0的直接拦截缓存空结果空结果也缓存起来短TTL下次就不用再查库了布隆过滤器把所有可能存在的数据Key提前存到布隆过滤器请求来了先过一遍布隆过滤器不存在的直接拦截4.3 缓存击穿定义某个热点Key访问量极大在某个时刻过期恰好此时大量并发请求同时打过来全部去查数据库。通俗理解游乐场只有一个VIP通道热点Key这个通道刚好关闭了过期了但此时一万人正排队等着通过大家一拥而上把旁边的闸机数据库挤坏了。雪崩 vs 击穿 区别重点雪崩大面积挂很多Key一起过期击穿单点挂一个热点Key过期但它特别重要解决方案加锁排队查数据库的时候加锁只放一个请求去查其他等结果热点Key永不过期特别热点的数据直接设为永不过期数据更新时主动刷新缓存五、Pipeline 流水线为啥能提速5.1 RTT 是啥Redis客户端执行一条命令分4步发送命令 → 命令排队 → 命令执行 → 返回结果这个过程叫Round Trip TimeRTT往返时间。算笔账客户端在北京Redis服务端在上海两地距离约1300公里。光在光纤里跑的时间 1300×2 / (30万×2/3) ≈ 13毫秒。也就是说一次RTT就要13ms1秒也就执行80次命令这跟Redis百万级QPS的高并发特性完全背道而驰啊5.2 Pipeline 原理Redis提供了mget、mset等批量命令来节约RTT但大部分命令不支持批量比如你要执行100次hgetall没有mhgetall命令啊。Pipeline 就是来解决这个问题的把一组命令打包通过一次RTT全部发给Redis再按顺序返回所有结果。不用Pipeline执行N条命令需要N次RTT用了Pipeline执行N条命令只需要1次RTT结论网络延迟越大Pipeline的性能提升越明显。同机房可能感觉不出来跨城跨区那提升是肉眼可见的。六、Redis 安装实战CentOS 7/86.1 CentOS 7 源码安装# 1. 安装依赖包yuminstalltcl gcc gcc-c-y# 2. 解压安装包tarzxvf redis-6.2.14.tar.gz-C/usr/local/# 3. 编译安装cd/usr/local/redis-6.2.14/makemakeinstall# 4. 启动并放后台redis-server redis.conf# 5. 查看启动端口netstat-antp|grep6379# 6. 客户端连接redis-cli127.0.0.1:63796.2 CentOS 8 yum 安装# 安装redisdnfinstall-yredis# 设置开机自启并启动systemctlenableredis--now# 查看端口ss-tunlp|grep6379# 测试连接redis-cli127.0.0.1:6379pingPONG6.3 开启多实例# 再开一个6380端口的实例redis-server--port6380# 连接指定端口redis-cli-p63806.4 为啥默认端口是6379这其实是作者的一个冷知识Redis 作者 antirez 当年选端口号的时候直接用了手机键盘上“MERZ”对应的数字。“MERZ” 是他和朋友用来形容愚蠢的俚语源自一位意大利女演员 Alessia Merz。说白了就是——大佬随便起的没有任何技术含义 七、Redis 配置文件详解vim/etc/redis.conf配置项默认值说明bind127.0.0.1监听地址远程访问要改成0.0.0.0记得配密码protected-modeyes保护模式没密码且绑外网IP时只允许本地连接port6379监听端口tcp-backlog511TCP连接队列长度高并发要调大timeout0客户端空闲超时0表示永不超时tcp-keepalive300每300秒发一次探测包检测死连接daemonizeno是否后台运行容器里一般保持no八、持久化RDB vs AOFRedis 数据都在内存里断电就没了所以需要持久化到磁盘。Redis 提供了两种持久化方式RDB和AOF。8.1 RDB快照模式原理某一时刻把内存数据全量快照保存到dump.rdb文件。触发方式# 方式1save命令同步会阻塞生产别用127.0.0.1:6379save# 方式2bgsave命令异步fork子进程来做127.0.0.1:6379bgsave Background saving started# 方式3配置文件自动触发# 900秒内改了1个key就触发save9001# 300秒内改了10个key就触发save30010# 60秒内改了10000个key就触发save6010000RDB 优缺点优点缺点恢复速度快直接加载二进制文件宕机会丢失最后一次快照后的数据文件紧凑适合备份save命令会阻塞主进程用子进程做对性能影响小bgsave时fork子进程还是会短暂阻塞8.2 AOF追加日志模式原理记录每一次写操作命令追加到appendonly.aof文件末尾。重启时重新执行这些命令来恢复数据。开启方式# redis.conf配置appendonlyyes# 开启AOFappendfilenameappendonly.aofappendfsync everysec# 写入策略dir/var/lib/redis⚠️大坑预警第一次开启AOF千万别直接改配置文件重启因为AOF优先级高于RDB但AOF文件是空的重启后所有数据直接清零正确姿势先在线执行CONFIG SET appendonly yesRedis会自动触发AOF重写把现有数据写入AOF文件然后再改配置文件永久生效。三种写入策略策略说明安全性性能always每次写操作都fsync到磁盘最安全最慢everysec每秒fsync一次默认最多丢1秒数据折中no交给操作系统决定什么时候写最不安全最快8.3 AOF 重写AOF文件会越来越大Redis提供了AOF重写机制来压缩文件。举个例子# 原来6条命令rpush listArpush listBrpush listCrpush listDrpush listErpush listF# 重写后变成1条rpush listABCDEF本质不是去解析旧AOF文件而是直接从当前数据库状态读出来用最少的命令重新生成。跟快照差不多但是以命令形式保存。九、Redis 数据类型与常用命令9.1 String 类型# 设置值setnamezhangsan# 获取值get name# 数字递增原子操作incr counter# 1incrby counter10# 10# 设置过期时间settoken abc123 EX3600# 3600秒后过期9.2 Hash 类型存对象神器# 设置字段hset user:1001 name张三age25# 获取字段hget user:1001 name hgetall user:1001# 删字段hdel user:1001 age9.3 List 类型队列/栈# 左边插入栈lpush mylistabc# 右边插入队列rpush mylistd# 弹出lpop mylist# 从左弹rpop mylist# 从右弹# 范围查询lrange mylist0-1# 查全部9.4 Set 类型无序集合去重# 添加元素sadd mysetabc# 差集、交集、并集sdiffset1 set2# 差集sinter set1 set2# 交集sunion set1 set2# 并集9.5 ZSet 类型有序集合排行榜# 添加元素带分数zadd rank100player1200player2150player3# 按分数排序从高到低zrevrank rankplayer1zrange rank0-1WITHSCORES# 排行榜Top3zrevrange rank02WITHSCORES十、主从复制10.1 啥是主从复制主从复制就是一个Master可以有多个SlaveMaster负责写Slave负责读数据从Master单向同步到Slave。特点一个Master可以有多个Slave一个Slave只能有一个Master数据流向Master → Slave 单向Master可读可写Slave只读10.2 同步原理Slave向Master发送sync命令Master启动后台存盘进程收集所有修改命令Master存盘完成后把整个数据文件发给SlaveSlave接收数据文件加载到内存完成首次完全同步后续新数据产生时Master继续把修改命令发给Slave同步10.3 配置实战实验环境1主2从主机名IP地址系统master192.168.108.10CentOS 7.9slave01192.168.108.11CentOS 7.9slave02192.168.108.12CentOS 7.9所有节点配置vimredis.conf# 监听所有网卡bind0.0.0.0 -::1从节点配置slave01、slave02都要配vimredis.conf# 指向Master的IP和端口replicaof192.168.108.106379 也可以在线配置不用改文件重启# 新版推荐127.0.0.1:6379REPLICAOF192.168.108.106379# 旧版即将淘汰127.0.0.1:6379SLAVEOF192.168.108.106379验证# Master上查看127.0.0.1:6379info replication role:master connected_slaves:2# Slave上查看127.0.0.1:6379info replication role:slave master_host:192.168.108.10 master_link_status:up取消主从同步# 在从节点执行127.0.0.1:6379REPLICAOF NO ONE# 注意取消后从节点数据不会清空只是不再同步了十一、哨兵模式Sentinel主从复制有个问题Master挂了需要手动把一个Slave提升为Master这就很麻烦。哨兵模式就是来解决这个问题的——自动故障转移。11.1 哨兵是干啥的哨兵是一个独立的分布式监控系统主要功能监控持续检查Master和Slave是不是还活着通知Redis实例出问题了通过API通知管理员自动故障转移Master挂了自动选一个Slave当新Master配置提供者客户端通过哨兵获取当前Master地址哨兵本身不存数据只负责监控和协调。11.2 故障转移流程主观下线SDOWN某个哨兵发现Master没响应标记为主观下线客观下线ODOWN多个哨兵达到quorum数量都确认Master挂了标记为客观下线选举Leader哨兵之间通过Raft算法选一个Leader来执行故障转移提升新主Leader选一个最优的Slave执行REPLICAOF NO ONE变成新Master重配从节点其他Slave重新指向新Master通知客户端告诉客户端Master换人了11.3 配置实战延续上面的1主2从实验三台机器都要配哨兵# 备份配置文件cpsentinel.conf sentinel.conf.bak# 编辑配置vimsentinel.conf# 第84行监控的Master名称、IP、端口、投票数2个及以上哨兵确认才算客观下线sentinel monitor mymaster192.168.108.1063792# 第125行超过30秒没响应就主观下线单位毫秒sentinel down-after-milliseconds mymaster30000启动哨兵redis-sentinel sentinel.conf查看哨兵状态redis-cli-p26379127.0.0.1:26379info sentinel master0:namemymaster,statusok,address192.168.108.10:6379,slaves2,sentinels3⚠️哨兵要部署奇数个3个、5个不然容易脑裂。而且哨兵和Redis节点最好分开部署不然Redis挂了哨兵也跟着挂了那就没人干监控的活了。十二、Redis Cluster3主3从集群哨兵模式解决了高可用问题但没有解决数据分片问题——所有数据都存在一个Master上内存不够了咋办这时候就需要Redis Cluster了。12.1 核心概念Redis Cluster 是无中心架构的分布式系统核心就是三件套数据分片 主从复制 去中心化故障转移。关键角色Master节点处理读写、管理哈希槽、参与故障投票Slave节点复制Master数据Master挂了自动顶上哈希槽集群固定16384个槽0~16383是数据分片的最小单位12.2 哈希槽机制HASH_SLOT CRC16(key) mod 16384比如3个Master的集群Master1负责 0 ~ 5460 号槽Master2负责 5461 ~ 10922 号槽Master3负责 10923 ~ 16383 号槽为啥不用一致性哈希Redis选了哈希槽方案好处是扩容缩容时迁移数据更可控。加一个节点从每个Master那里匀一段槽过去就行不用全量重哈希。12.3 请求路由流程客户端随便连一个节点发命令节点计算这个Key属于哪个槽槽是自己的 → 直接处理槽不是自己的 → 返回MOVED重定向告诉客户端正确的节点地址聪明的客户端会缓存槽位映射表下次就直接连对节点了12.4 故障转移某个Master超时没响应多数Master投票确认它挂了它的Slave们发起FAILOVER选举请求Master们投票选一个Slave升级为新MasterGossip协议同步新拓扑集群恢复12.5 搭建实战3主3从环境准备6台机器或者一台机器开6个实例# 所有节点配置redis.confvimredis.confbind0.0.0.0 -::1 port6379# 每个实例改不同端口daemonizeyescluster-enabledyes# 开启集群模式cluster-config-file nodes-6379.conf cluster-node-timeout15000appendonlyyes启动所有节点后创建集群redis-cli--clustercreate\192.168.108.21:6379\192.168.108.22:6379\192.168.108.23:6379\192.168.108.24:6379\192.168.108.25:6379\192.168.108.26:6379\--cluster-replicas1--cluster-replicas 1表示每个Master配一个Slave6个节点正好3主3从。十三、总结Redis 技术演进路线一张图看懂Redis架构是怎么一步步演进的单机Redis → 主从复制数据冗余 读写分离 → 加上自动故障转移 → 哨兵模式高可用 → 再加上数据分片和写扩展 → Redis Cluster分布式集群架构解决啥问题适合场景单机简单缓存测试环境、小项目主从读写分离、数据备份读多写少哨兵自动故障转移、高可用中小规模高可用Cluster数据分片、水平扩展大规模高并发大数据量