ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Redis实战完全指南:从数据类型到集群高可用

Redis实战完全指南:从数据类型到集群高可用 兄弟们搞技术这么多年如果说有哪个中间件是“面试必问、实战必用、性能还炸裂”的那Redis绝对排前三。从缓存、分布式锁到排行榜、消息队列它几乎无处不在。我最早接触Redis还是幺几年那会儿那时候它还是个只配当缓存的小透明现在已经是高并发系统的标配了。这篇东西不是官方文档翻译是我用Redis这些年踩坑、爬坑、填坑之后整理出来的完全指南从概念原理到安装配置从数据类型到缓冲治理从持久化到集群争取一篇讲透你把这篇吃透日常开发和面试基本够用了。我自己接手过几次线上事故有一半以上多多少少都和Redis的使用姿势有关。很多人把Redis当MySQL用存一堆大key结果把内存打爆还有人不做持久化策略重启直接丢数据更别提那些分布式锁锁了个寂寞的经典案例。这些坑我这篇里都会提到还会告诉你底层逻辑是什么为什么这么做会炸。内容会有点长但我保证没有废话全是实操。1. 先搞清楚Redis到底是什么以及它为什么这么快1.1 一个基于内存的键值数据库Redis全称是Remote Dictionary Server说白了就是个基于内存的KV存储系统。它和MySQL这种关系型数据库最大的区别在于MySQL的数据大部分时间躺在磁盘上通过索引去检索而Redis的数据直接泡在内存里读写都在内存中完成。内存的随机访问速度是纳秒级的而磁盘即使上了NVMe也还在微秒级这就是数量级的差距。我见过很多新人把Redis理解成“一个HashMap”这么理解不算错但不完整。它确实像个大HashMap存键值对但它远不止这个。它支持几十种数据结构内置了持久化机制、主从复制、哨兵、集群方案甚至还能跑Lua脚本、做发布订阅。我会在后面章节逐一拆。Redis默认放在内存里跑所以它非常依赖内存容量和带宽。一台机器内存越大能存的数据越多网卡越好吞吐越高。我这边压测单实例Redis轻松就能跑到10万以上的QPS这数据库界的跑车名号不是白给的。1.2 为什么它能这么快IO模型、事件驱动和单线程Redis快不只是因为内存。它底层用的是多路复用IO模型配合事件处理器在Linux上就是epoll一个线程就能伺候成千上万个客户端连接。它不是来一个请求开一个线程而是一个线程轮询所有连接哪个连接有数据来了就处理谁没有事件就休眠。这套模型在IO密集型场景下效率极高避免了线程频繁切换的开销。传统的多线程模型阻塞IO每个连接占用一个线程连接一多CPU就大量花在上下文切换上。很多人会问Redis为什么到6.0之前一直是单线程正是因为纯内存操作本来就快单线程还能省掉锁竞争、上下文切换这些麻烦反而更容易把性能榨干。那为什么6.0之后引入了多线程这里的多线程是专门针对网络读写和协议解析的核心命令执行仍然是单线程这样既避免了锁又提升了大流量包的吞吐能力。我实测过6.0的IO多线程开启后在多核机器上网络吞吐有明显改善但单实例纯命令性能提升幅度并没有想象中夸张普通业务单线程模型完全够用。1.3 Redis的典型应用场景与能力边界聊到应用场景最经典的就是缓存。把高频访问、变化频率不高的数据放到Redis里把对数据库的压力降下来。我处理过一个业务原来接口直接查MySQL高峰期数据库CPU飙到90%加上只读缓存后数据库CPU直接降到20%以内接口延迟从50毫秒降到3毫秒体验完全不一样。除了缓存Redis还干这几种活分布式锁多实例并发操作同一个资源时用Redis加锁防止互相踩踏SET NX EX命令就是干这个的。排行榜ZSET天然支持按分数排序做榜单、积分排名、延迟队列都很方便。计数器与限流INCR命令做自增计数非常丝滑接口限流、库存扣减都常用。会话存储把用户登录态、Session信息放进Redis支持分布式共享登录态。消息队列Stream类型和Pub/Sub可以实现轻量级消息队列但可靠性不如专业的MQ量大时还是建议用正规队列。但Redis不是万能的。首先它是单机存储容量受内存限制不能像MySQL那样存TB级数据硬存必炸。其次虽然它有持久化机制但毕竟是内存为主的设计极端情况下仍可能丢数据。我建议把它当作“热数据加速层”来用而不是包打天下的数据库。在做架构选型时想清楚边界遇到冷数据、超大数据量、强事务一致性场景老老实实用关系型数据库别为难Redis。2. 安装与基础配置Windows、macOS、Docker全讲透Redis官方其实不支持Windows官方推荐Linux和macOS。Windows上大家用的是微软当年移植的开源版本或者重新编译的版本所以网上搜索“redis windows 下载”会找到各种资源。这些版本和Linux上的官方版本大同小异日常学习足够了但生产强烈建议跑在Linux上稳定性和性能差异还是实实在在存在的。2.1 Windows环境安装免安装包和绿色版Windows上最省事的方式是下载免安装压缩包。在GitHub上搜Redis-x64-*.zip当时5.0.14.1这个版本用的人最多直接把zip解压到指定目录比如D:\Redis里面就能看到redis-server.exe和redis-cli.exe。启动方式也简单在解压目录下打开命令行redis-server.exe --port 6379或者带配置文件启动redis-server.exe redis.windows.conf默认监听6379端口下载下来就能跑。如果嫌命令行麻烦也可以把redis-server注册成Windows服务这样开机自启省心不少redis-server.exe --service-install redis.windows.conf --loglevel verbose redis-server.exe --service-start提醒一句Windows版本的Redis功能比起官方版会有差异比如某些AOF持久化细节和内存映射特性没有完全对齐。学习可以真上生产别在Windows上赌。2.2 macOS安装Homebrew一键搞定macOS开发机上装Redis我推荐直接用Homebrew两行命令brew search redis brew install redis安装完默认会放到/opt/homebrew/opt/redisApple Silicon或/usr/local/opt/redisIntel。你可以手动启动redis-server /opt/homebrew/etc/redis.conf也可以注册成后台服务brew services start redis用brew services方式启动的好处是自从自动启动重启机器后Redis也会跟着拉起来开发调试非常方便。装完先验证一下版本redis-server --version redis-cli ping能看到PONG就说明服务跑起来了。顺便说下macOS上还能用Docker跑Redis但那更适合测试隔离场景日常本机开发直接brew就赢了。2.3 Docker部署Redis和主从配置现在很多团队环境都已经容器化了用Docker装Redis是非常标准的操作。先拉镜像docker pull redis:7.0然后跑一个单机实例docker run -d --name redis-server \ -p 6379:6379 \ -v /data/redis:/data \ redis:7.0 \ redis-server --appendonly yes --requirepass 123456这里把宿主机的/data/redis挂载到容器内的/data目录用于存放AOF和RDB文件appendonly yes表示开启AOF持久化--requirepass设置访问密码。不加密码的话裸奔在公网等于给攻击者送钱包分分钟被挖矿脚本扫到。主从就更简单了。准备两个容器一个做master一个做slave。启动slave时在命令里指定副本来源docker run -d --name redis-slave \ -p 6380:6379 \ --link redis-server:master \ redis:7.0 \ redis-server --slaveof master 6379 --masterauth 123456稍等几秒在master上执行info replication如果看到role:masterconnected_slaves显示1就说明主从同步成功了。不过提醒一句Docker里链接主从如果容器重启IP变化可能导致从库重新连接失败生产环境建议放到Docker Compose里配合固定网络或者直接用k8s部署IP漂移问题交给服务发现解决。2.4 配置文件核心参数解读Redis的配置项非常多我挑几个真正影响日常运行的说看配置文件的时候优先关注这几个配置项默认值说明daemonizeno是否后台运行生产建议yesport6379监听端口要防冲突bind127.0.0.1 -::1绑定地址外网访问要改protected-modeyes保护模式没密码时拒绝外部访问requirepass(none)客户端访问密码maxmemory0不限制最大内存0表示不限制生产必须设置maxmemory-policynoeviction内存淘汰策略见下面表格appendonlyno是否开启AOF持久化save3600 1 300 100 60 10000RDB快照触发条件timeout0超时关闭空闲连接0表示不断开再展开说一下内存淘汰策略。当Redis达到maxmemory上限时写命令会报错noeviction或者触发淘汰这个策略直接关系到缓存失效率和数据安全性。常用策略如下volatile-lru从设置了过期时间的key里淘汰最久没被使用的allkeys-lru从所有key里淘汰最久没被使用的volatile-ttl从设置了过期时间的key里淘汰剩余时间最短的volatile-random / allkeys-random随机淘汰noeviction默认策略内存满了直接拒绝写请求像我这边做缓存服务一般用allkeys-lru因为缓存本来就是允许丢的淘汰最久没用的合理。但如果Redis里还存了少量不能丢的业务状态数据就要谨慎把“不可丢数据”和“可丢缓存”分实例或者用volatile-lru确保只有带TTL的key被淘汰。生产环境还有一个必须做的动作把protected-mode关掉或者设置requirepass二选一。很多人刚上手图省事不设密码也不改保护模式结果Redis默认端口6379被扫描工具扫到一条命令就被清空数据然后写入勒索信息。这种事真的见太多了。3. 核心数据结构详解String、List、Hash、Set、ZSetRedis为什么能这么受欢迎很大一部分原因就是它自带丰富的数据结构让开发者可以少写一堆业务代码。这五种基本数据类型是必须烂熟于心的我就按“底层原理常用命令实战运用”来说。3.1 String最简单的键值功能却不简单String是Redis最基础的类型一个key对应一个valuevalue最大能到512MB。又是字符串也是数字甚至可以存二进制数据。常用的命令SET key value GET key INCR key DECR key SETNX key value SETEX key seconds value GETSET key valueINCR/DECR是原子自增自减底层是单线程执行所以不会出现并发加错的问题做计数器、库存扣减特别香。我做过一个抽奖系统用INCR记录中奖次数在多线程发送请求的环境下计数依然准确因为Redis命令执行是串行化的不会两个请求同时读到同一个值再写回去。SETNX是“set if not exists”结合EXPIRE可以实现分布式锁的雏形。真正常用的分布式锁命令长这样SET lock_key unique_value NX EX 10这串命令的意思是只有lock_key不存在时才能写入且10秒后自动过期。用一个线程自己的唯一标识作为value释放锁时先GET判断value是不是自己的再用Lua脚本原子删除防止误删别人的锁。String适合的场景缓存JSON字符串、计数器、分布式锁、验证码存储、Session共享。3.2 List消息队列和最新列表底层是双向链表支持头部尾部插入删除。核心命令LPUSH key value RPUSH key value LPOP key RPOP key LRANGE key start stop LLEN key BLPOP key timeoutList做消息队列是经典玩法生产者RPUSH消费者BLPOP阻塞消费。为什么用阻塞而不是的时候轮询因为阻塞模式在列表为空时会让客户端挂起等待不占CPU消息来了立刻返回效率和实时性都更高。我用它做过一个轻量级异步任务队列单队列消费速度每秒几千条完全扛得住。List还能用来做“最新动态”列表比如用户发布动态用LPUSH塞进列表LRANGE取前20条展示。注意一点List是线性结构随机访问中间元素的复杂度是O(N)要取中间某条还不如直接用LRANGE滑过去别指望它像数组一样索引一击命中。还要提醒如果List长时间为空建议直接删掉key不要留一个空list占内存。我见过有人写代码只做LPUSH消费端处理完不清理结果空了还留着key占用一大片内存。3.3 Hash适合存对象结构化数据Hash类型相当于一个key下挂着一个小字典适合存Object。比如用户信息key是userIdfield是属性名value是属性值HSET user:1001 name zhangsan age 25 HGET user:1001 name HGETALL user:1001 HDEL user:1001 age HINCRBY user:1001 score 10用Hash存对象的好处是部分字段更新只需要写一个field不用整个对象序列化重写。String存整个JSON的话改一个字段就得取出整个对象、反序列化、改字段、再序列化、写回性能和代码复杂度都高不少。Hash则天然支持局部更新网络传输量也更小。从底层看Hash在数据量小的时候用ziplist压缩存储数据量大了自动转成hashtable所以它对内存和访问效率做了平衡。我实战里存用户资料卡、商品详情这类结构化的数据都优先用Hash缓存里的可视化程度也高用可视化工具查看时一目了然。3.4 Set去重、交集、并集利器Set是无序去重集合基于哈希表实现操作复杂度都是O(1)。典型命令SADD key member SMEMBERS key SISMEMBER key member SINTER key1 key2 SUNION key1 key2 SDIFF key1 key2 SREM key memberSet的价值在于集合运算。做社交类功能时常用SINTER求好友共同关注、SUNION做推荐合并。举个例子抽奖系统里用户的参与ID直接放进Set抽奖时随机抽取SISMEMBER判断是否中奖去重天然生效不会同一用户中两次。还有一个高级玩法用Set过期时间做当前在线用户统计用户登录时SADD进“online:today”集合定期统计集合大小就是日活但要配合TTL清理过期成员否则集合无限膨胀。3.5 ZSet有序集合排行榜神器ZSet在Set基础上给每个元素加了一个score分数Redis按score自动排序这就是排行榜系统的核心实现。命令ZADD leaderboard 100 userA ZINCRBY leaderboard 10 userA ZRANGE leaderboard 0 9 WITHSCORES ZREVRANGE leaderboard 0 9 WITHSCORES ZSCORE leaderboard userA ZRANK leaderboard userA ZREM leaderboard userAZREVRANGE就是按分数从高到低取榜单。排行榜逻辑用代码自己排序很麻烦要维护排序数组、处理分数变更、处理并发Redis用跳表skiplist搞定插入、删除、查找的时间复杂度都在O(log N)几千万元素也能轻松应付。我做积分排行时就是用ZINCRBY不停累加积分ZREVRANGE取Top100响应时间永远是毫秒级。除了排行榜ZSet还能做延时队列score存任务的执行时间戳消费者用ZRANGEBYSCORE取score小雨当前时间的任务处理完再ZREM。这样就有了一个简单可靠的延时任务调度器不用依赖外部调度框架。3.6 其他常用类型Bitmap、HyperLogLog、Stream面试常问Redis有几种数据类型如果你只答五种就少了点底气。在高版本Redis里还有Bitmap位图、HyperLogLog基数统计、Geo地理位置、Stream消息流。Bitmap底层是String按位操作。适合做打卡记录、在线状态、用户签到。比如每天一条位图key某一位为1表示该用户签到。命令有SETBIT、GETBIT、BITCOUNT。HyperLogLog统计不重复元素个数标准误差0.81%内存占用极低固定约12KB就能统计上亿级别的去重数适合做UV统计不精确但够用。Geo地理位置存储底层依赖ZSet实现支持计算两个地理位置的距离、查找附近的点适合做LBS场景。Stream在5.0版本引入的流式数据结构支持消费组比Pub/Sub可靠得多消息不会丢失可以作为轻量级MQ。多知道几个类型在面试时就是加分项在日常开发里也能选对工具少写很多烂代码。4. 缓存治理缓存穿透、缓存击穿、缓存雪崩讲到Redis绕不开缓存三大问题穿透、击穿、雪崩。我把每个问题的现象、原因、解法都讲清楚顺便说下我实测过的方案效果。4.1 缓存穿透缓存和库里都没有的数据所谓穿透就是大量请求查询一个根本不存在的数据缓存和数据库都没有命中请求直接打到数据库。恶意攻击最喜欢这么干疯狂请求不存在的id数据库压力瞬间飙升。我处理过真实案例线上有个查询接口有人扫了一个不存在的用户ID每秒几十个查询全穿透到MySQL数据库瞬间打满。解决思路分几层布隆过滤器Bloom Filter在缓存前面加一层布隆过滤器请求先判断key是否存在不存在直接返回根本不进缓存和数据库。布隆过滤器用多个哈希函数映射到位图里查询时候判定位是否为1存在误判但不存在的肯定能挡掉。缓存空值如果数据库查询结果为空也缓存一个空对象设置一个较短的过期时间比如5分钟下次同样key请求就直接返回空缓存不再打库。参数校验在接口入口对id做基础校验格式不对的直接拒绝。我现在的习惯是两套一起上。小系统用缓存空值就够了大流量再用布隆过滤器避免缓存空值占大量内存还有就是防止空值堆积把Redis搞爆。4.2 缓存击穿热点key过期瞬间的并发穿透击穿和穿透不一样。击穿是某个热点key在缓存过期的瞬间大量请求同时涌入发现缓存没了直接去数据库拿数据数据库秒崩。区别在于穿透是数据本身不存在击穿是数据存在但缓存刚好失效。经典场景秒杀活动的商品库存key一过期所有抢购请求瞬间打到数据库。解决手段互斥锁Mutex缓存失效后只有一个请求能拿到锁去查数据库并回填缓存其他请求等锁或直接返回默认值。逻辑过期不设置物理TTL而是在value里存一个逻辑过期时间。查询时发现逻辑过期就异步线程去刷新缓存请求还是返回旧数据保证前端不卡。加长TTL 定时刷新热点key不要等到被动过期而是搞个定时任务提前刷新。互斥锁实现简单但会阻塞请求逻辑过期适合高并发场景但增加了复杂度。我一般给热点key设置一个较长的过期时间配合定时任务主动刷新这样既避免击穿又不阻塞请求简单有效。4.3 缓存雪崩大量key同时过期或者Redis挂了雪崩指缓存中大量key在同一时间过期或者Redis整个节点宕机不可用导致所有请求直接打到数据库数据库扛不住直接挂。这个问题的解法可以从多个角度组合过期时间加随机值不要让大量key的过期时间完全一致TTL设置一个基础值再叠加随机数比如5分钟偏量300秒内随机这样不同key的过期时间错开不会在同一秒内集体失效。这个方法最简单强烈建议所有缓存都这样设计。缓存预热系统上线前或大促前把热点数据预先塞进缓存回避瞬时加载。多级缓存本地Caffeine加上RedisRedis挂了还有本地缓存兜底数据库压力大减。Redis高可用主从复制配合哨兵或者直接上Redis Cluster主节点挂了自动切换从节点保证Redis本身不会整体不可用。接口限流降级在网关层加限流数据库层加连接池高峰期保护某个组件挂了其他链路还能撑住。说句实话缓存三大问题不会只出现一个很多时候是同时出现的。我在做架构设计时会把它们连起来考虑每层加防护不指望一个骚操作拯救世界。5. 分布式锁从入门到源码级理解5.1 为什么需要分布式锁单体架构里多个线程同时修改一个变量用synchronized或者ReentrantLock就能锁住。但上了微服务多个服务实例部署在不同机器上每个实例都有自己的一块锁空间传统的JVM锁根本锁不住跨节点的并发请求。这时候就需要一个所有实例都能访问的公共区域放锁Redis就是最常见的选择。典型场景秒杀系统扣减库存、定时任务防重复执行、订单支付后回调处理等。这些场景要求同一时间只有一个节点执行关键代码否则会出现超卖、重复处理等事故。5.2 基于SET NX EX的正确实现早期大家在Redis里实现分布式锁用SETNX和EXPIRE两条命令分两步操作有个坑如果执行完SETNX之后突然崩溃EXPIRE没执行锁永远不释放其他节点就永远等待。解决方式是用单条原子命令SET lock_key unique_value NX EX 10这个命令在Redis 2.6.12之后支持SETNX加EXPIRE的原子版要么全部成功要么全部失败不存在中间状态。释放锁也不能直接DEL因为有可能当前线程的锁已经被别的线程覆盖了。正确姿势是用Lua脚本校验valueif redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end这个脚本保证只有持有锁的线程才能释放锁别人删不掉。SpringBoot里用Redisson的话它的RLock就是封装好的一整套方案支持自动续期和看门狗机制比手写省心。5.3 锁续期、可重入和红锁的取舍只SET NX EX的锁有个隐患业务逻辑执行时间超过了锁过期时间锁自动释入了其他节点拿到锁执行了同样的逻辑数据一致性问题就来了。Redisson的看门狗机制会每隔一段时间自动续期锁的过期时间业务没执行完锁就不会过期。另外可重入锁的需求也很常见。同一个线程再次进入被同一把锁保护的代码块标准Redisson实现支持这个能力底层记录线程和重入次数用完后次数归零才释放锁。再往上走就是RedLock红锁问题。Redis主从模式下如果主节点同步还没完成就挂了锁可能丢失第二个节点还能拿到锁。RedLock就是向多个独立的Redis节点同时申请锁超过半数节点成功才算持锁。但红锁的设计在业界争议很大它依赖多个节点完全独立可用性下降也很明显。我个人的实践是业务对数据一致性极端敏感就引入数据库事务兜底Redis分布式锁作为性能优化手段组合使用比单一方案稳得多。5.4 生产实战中的坑位提醒用分布式锁时这几个坑我踩过必须说锁value要用全局唯一标识UUID、业务请求ID都可以不要两个线程共用同一个value。过期时间不能设太短结合业务预估留一定余量用Redisson可以自动续期但也要理解看门狗机制别完全依赖。不要锁粒度太大比如所有订单共用一个锁key等于全系统串行化性能灾难。锁粒度能细到订单号就尽量细。监控锁的获取时长如果大量线程在等待锁说明锁竞争严重可能要考虑拆分锁或换方案。6. 持久化机制RDB和AOF搞明白别让数据白丢Redis是内存数据库进程一挂内存数据全没。持久化机制就是为了在重启后恢复数据。主流的两种方式RDB快照和AOF日志。6.1 RDB快照全量数据的压缩备份RDB就是在指定时间点对内存数据生成一份二进制快照保存到硬盘上的dump.rdb文件。默认配置save 3600 1 save 300 100 save 60 10000意思是1小时内至少1次写入就快照5分钟内至少100次写入就快照60秒内至少10000次写入就快照。RDB的优点是文件紧凑、恢复速度快、适合做备份。缺点是快照之间有间隔如果Redis在两次快照之间宕机这部分变更完全丢失。RDB生成快照用的是fork子进程写时复制COW父进程继续服务不受影响但fork瞬间内存会翻倍的风险大内存机器要注意。6.2 AOF日志记录每一次写命令AOF不像RDB那样全量拍快照而是把每一条写命令追加到文件类似MySQL的binlog。配置项appendonly yes后每次写操作都会打到appendonly.aof文件。重启时逐条执行命令恢复数据。AOF的写盘策略有三种策略描述数据安全性always每条命令都刷盘最安全但性能最低everysec每秒刷一次盘最多丢1秒数据性能和安全的折中no由操作系统决定刷盘时机性能最高但可能丢大量数据我一般选everysec原因很简单生产中完全接受丢失最近1秒的数据换来的是性能几乎不受影响。如果你要求极致安全选always但性能至少要降一个档次。AOF还有个问题日志文件不断变大。Redis提供了AOF重写机制把相同key的多次写命令合并成极少数命令文件体积大幅缩小。手动执行BGREWRITEAOF或者在配置里设置auto-aof-rewrite-percentage触发自动重写。6.3 混合持久化和恢复顺序从Redis 4.0开始支持RDBAOF混合持久化。开启方式aof-use-rdb-preamble yes这样AOF文件头部是RDB格式的全量快照后面追加增量命令兼具RDB的快速恢复和AOF的低丢数据率。我线上用的就是混合持久化。重启时恢复顺序是优先加载AOF文件因为AOF数据更完整没有AOF再加载RDB。6.4 备份恢复演练心得持久化不是配个配置就完事。我强烈建议定期做备份恢复演练从线上实例备份RDB文件在测试环境启动一个Redis实例加载备份验证数据能正常恢复。我遇到过备份文件时间很老、恢复后发现数据丢了半天的情况还有一种情况是备份文件本身损坏Redis启动时直接拒绝加载。做过一次演练心里才有底。还有一个注意点RDB和AOF文件不能放在系统盘最好放在单独的目录比如/data/redis避免系统故障连带数据盘炸了。文件权限别随便777Redis默认读取目录权限要求严格写太松会有安全风险。7. 集群与高可用主从、哨兵、Cluster三选一单机Redis再好也不可能无限扩展而且单点故障是生产绝对不能接受的。Redis高可用方案有三条路线主从复制、哨兵Sentinel、Cluster集群我按适用场景一个一个说。7.1 主从复制从节点热备和读写分离主从复制是Redis高可用的基础。一个master可以挂多个slavemaster负责写slave负责读数据单向同步。配置方式有两种配置文件里写slaveof master_ip master_port或者在运行中用命令SLAVEOF 192.168.1.10 6379同步过程用的是全量快照增量命令。第一次连接master生成RDB发给slave同时把后续命令放到缓冲区slave加载RDB后再追赶增量命令之后就是实时命令传播。主从复制解决了读压力和热备问题但master挂了需要人工干预把某个slave提升为master这个过程不可自动化。所以就有了哨兵机制。7.2 哨兵Sentinel故障自动转移Sentinel是个独立运行的Redis进程作用是监控master和slave节点的健康状态。它的核心能力是故障检测和自动故障转移。当master挂了哨兵集群会选出一个slave提升为新master客户端自动感知到新的master地址。哨兵本身建议部署奇数个至少3个避免脑裂。怎么理解“奇数”因为哨兵决定故障要多数派同意3个哨兵挂了1个还有2个能投票2个哨兵挂1个就只剩1个永远无法达到多数根本没法完成故障转移。部署Sentinel时除了监控master还要配好密码和权限sentinel monitor mymaster 127.0.0.1 6379 2 sentinel auth-pass mymaster yourpassword sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 15000上面的2表示至少2个哨兵同意master下线才执行故障转移。客户端连接也用哨兵提供的地址比如SpringBoot里配spring.redis.sentinel.master和nodes它会自动通过哨兵获取真实master地址。7.3 Cluster集群自动分片和水平扩展当单机内存达到几十G甚至更大或者写入性能到瓶颈就需要Cluster集群。Cluster是Redis 3.0引入的完整分布式方案核心机制是槽位分配。整个集群有16384个哈希槽每个key通过CRC16算法算出一个槽位槽位分布在各个节点上。你存一个keyRedis算出来它属于哪个节点就直接路由到那个节点存储。Cluster的好处是数据自动分片、支持在线扩容缩容、没有中心节点去中心化架构、每个节点都是平级的。配置Cluster需要至少3个master节点每个master又可以有从节点实现数据副本。Cluster集群的部署比单机复杂得多一般用脚本或Docker Compose来简化操作。如果追求省心可以用云厂商的托管版本比如阿里云、腾讯云的Redis集群自动完成监控、运维和扩容。7.4 生产环境选型建议做方案选型时我给你一个直接可抄的答案单机Redis开发测试、数据量小、可接受短时不可用的场景。主从哨兵读写比例高、需要自动故障恢复但数据量没到单机瓶颈的场景。Cluster集群数据量大、写并发也高、需要横向扩容的生产核心场景。云托管Redis不想运维、预算够、对管理成本和出故障概率都比较敏感的场景。我自己的项目早期就是主从哨兵后来业务增长、数据量过了30G果断上了Cluster性能和运维成本都改善了不少。选型别一上来就Cluster复杂度会吞掉你的精力。8. 可视化工具与日常调试Redis Desktop Manager、Redis Insight和命令行实战Redis服务端只是一个内存数据库没有官方带图形界面的交互工具尤其Windows用户连官方版本都没有。好在生态里有不少成熟的可视化客户端学习、调试、排查起来方便很多。8.1 Redis Desktop Manager和Another Redis Desktop ManagerRedis Desktop ManagerRDM是最老牌的可视化工具支持Windows/macOS/Linux连接Redis后用图形界面浏览所有key查看value执行命令监控慢日志和服务器信息。现在很多团队也在用Another Redis Desktop Manager它算是RDM的社区替代品界面更现代更新还更勤快功能包括连接管理、数据浏览、命令行等日常用足够了。填写连接信息时注意几个字段HostRedis服务器地址本机是127.0.0.1远程是服务器的公网或内网IPPort默认6379Auth如果你在redis.conf里设置了requirepass这里填密码DatabaseRedis默认有16个逻辑数据库默认连0号库可视化工具最大的价值是排查问题。比如查看某个key的TTL、内存占用或者直接跑到命令行执行慢命令分析比对着终端接口直观得多。我排查线上问题时经常先用可视化工具扫一眼全局key分布再精确定位问题key效率翻倍。8.2 命令行神器redis-cli不管用什么GUIredis-cli必须熟登录服务器排查问题时只有命令行可用。常用命令redis-cli -h 127.0.0.1 -p 6379 -a password ping redis-cli --latency redis-cli --bigkeys redis-cli --scan --pattern user:* redis-cli -a password info replication--bigkeys是排查大key的利器会扫描整个库找出占用内存最大的key列表。--latency用来测延迟如果数值波动大要考虑网络或Redis实例性能问题。--scan配合pattern可以批量扫描key比KEYS命令安全得多因为KEYS在大数据量时会阻塞Redis。还有个冷门的--stat可以实时输出Redis的请求数、内存和连接数调试时开着像监控面板一样。8.3 慢查询日志和日志分析Redis慢查询日志不是看日志文件专门的命令CONFIG GET slowlog-log-slower-than CONFIG SET slowlog-log-slower-than 10000 SLOWLOG GET 10 SLOWLOG RESETslowlog-log-slower-than单位是微秒10000微秒就是10毫秒。执行时间超过阈值的命令会被记录最多保存128条。线上如果发现接口慢先查慢查询日志看是不是Redis命令执行超时。如果你刷日志经常能看到类似“Command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException”这是SpringBoot的Lettuce客户端报的经典错误。出现这个错误的原因通常是Redis服务端负载过高、网络抖动或者有慢命令阻塞。排查顺序先看Redis服务器CPU和慢日志再看网络和客户端连接池配置最后看是否有bigkey操作导致阻塞。8.4 Windows下没有官方版怎么办Windows生产环境说过了不建议用但如果是个人开发环境那也可以用编译好的Windows版本Redis。常见的就是tporadowski维护的microsoftarchive版本和官方推荐的MemuraiWindows版Redis替代品。Memurai兼容Redis API官方支持Windows可以免费开发使用只是社区版有限制。Windows下载还要注意下载到的文件是否带病毒因为第三方编译版本比较多建议下载后先杀毒尽量选择star数量多的GitHub仓库。9. 常见问题排查与性能调优实录这个章节直接上干货把我在生产环境遇到过的经典问题列出来附带诊断思路和解决方案你可以当速查表用。9.1 大Key和热Key问题大Key指String类型value过大或者集合类型元素数量过多比如一个Hash里有几百万个field。大Key会让Redis阻塞在删除或者序列化操作上导致其他命令排队等待。排查方式直接用redis-cli --bigkeys扫描。定位之后处理方法拆分成多个小key比如Hash拆成多个子Hash按业务维度区分。压缩value比如JSON压缩后再存。设置合理的TTL防止无限堆积。用UNLINK替代DEL删除大keyUNLINK是异步删除不会阻塞主线程。热Key指某个key的访问频率特别高导致单节点CPU打满。应对方式可以给key加后缀分散到多节点或者用本地缓存扛掉一部分再不行做读写分离把热key的读压力分散到从节点。9.2 内存暴涨和内存碎片内存暴涨大部分原因是缓存key无限增加且没设过期时间或者过期时间设置得太长。先跑INFO memory看used_memory再用redis-cli --bigkeys看哪些类型占内存最大。清理手段就是删除垃圾key、优化数据结构、调低过期时间。另外Redis在频繁删除和修改后会产生内存碎片mem_fragmentation_ratio大于1.5就需要关注了可以执行memory purge或者干脆重启实例整理内存。9.3 连接数打满和超时出现“max number of clients reached”表示连接数达到了配置上限redis.conf里maxclients默认10000。客户端连接数打满的背后问题通常是连接池配置不合理或者有连接泄漏没释放。排查方向检查应用连接池最大数和最小空闲数对Redis客户端连接用完后一定要close把客户端空闲连接timeout设置短一点超时通常就是前面说过的客户端连接超时Lettuce和Jedis都会报。除了看Redis判断负载还要检查应用和Redis之间的网络尤其是跨机房访问延迟天然不可控能同机房就同机房。9.4 主从同步中断问题线上主从同步偶尔会断常见原因有网络抖动、master节点内存不够导致复制积压缓冲区写满、从节点处理不过来。排查方式INFO replication关注master_repl_offset和slave_repl_offset的差值如果差距持续增大说明从节点消费太慢。还有master_sync_in_progress标志如果长时间处于同步中看是不是大key导致的RDB生成传输速度太慢。解决手段优先考虑增加带宽、调整repl-backlog-size配置默认1MB建议至少16MB、或者从节点太多时做级联复制减轻主节点同步压力。9.5 Redis延迟高的排查路径服务端延迟高先跑redis-cli --latency -h 127.0.0.1 -p 6379看平均延迟和最大延迟。如果延迟持续波动基本就这几个原因慢查询、大key操作、内存交换swap、fork阻塞、网络拥塞。慢查询按之前说的SLOWLOG查。大key操作检查--bigkeys结果。内存交换INFO memory看used_memory和maxmemory的比值如果swap使用率高要么加内存要么淘汰数据。fork阻塞INFO stats看latest_fork_usec如果fork耗时过长比如上千毫秒说明子进程创建瞬间阻塞了主流程大内存机器尤其明显。9.6 Redis的监控指标建议日常运维我建议至少把这几项指标接进监控指标命令/来源预警阀值内存使用率INFO memory的used_memory/maxmemory超过80%告警命中率INFO stats的keyspace_hits/hitsmisses低于80%关注连接数INFO clients的connected_clients超过80% maxclients告警慢查询SLOWLOG GET有持续新增就告警主从延迟INFO replication的master_repl_offset与slave差值差值持续增大告警持久化失败INFO persistencerdb_bgsave_in_progress异常告警10. 面试高频问题与学习路线最后这部分写给准备面试的朋友。Redis相关的问题在面试里出现频率极高几乎可以算Java后端必考。我梳理几个最常见的层级作为一个查漏补缺的清单。10.1 高频面试题目Redis为什么快答IO多路复用、纯内存操作、单线程避免竞争、高效的数据结构。Redis的数据类型有哪些五种基础类型三种高级类型要都能说出来。Redis的持久化方式有哪些RDB和AOF的区别、优缺点、恢复策略要熟。什么是缓存穿透、击穿、雪崩分别怎么解决Redis分布式锁怎么实现SET NX EX、Lua脚本、看门狗、红锁。Redis主从复制的原理是什么全量同步和增量同步的区别哨兵机制如何判断主节点客观下线为什么要奇数个哨兵Redis集群的槽位分配机制16384个槽怎么路由10.2 从入门到精通的建议路线给自己一个学习路径参考先在Windows或macOS把Redis装起来跑通五种数据类型的基本命令。写一个SpringBoot项目用Redis做缓存感受下缓存命中率变化。用Docker搭一个主从哨兵环境手动关掉master模拟故障转移。用Cluster搭一个三主三从集群观察数据分片逻辑。系统性看一遍Redis官方文档的Commands和Topics。阅读《Redis设计与实现》这本书重点看数据结构和持久化章节再深入看IO模型和事件循环。10.3 实战里持续积累工具和命令可以快速上手但真正的功力在实战中积累的坑里。比如你亲手处理过一次线上缓存雪崩就知道为什么TTL一定要加随机值处理过一次分布式锁误删就知道为什么value一定要校验唯一标识。这些经验面试时就是你的硬通货比背十遍八股文有用。我做Redis调优这几年最深刻的一个体会是Redis本身够快、够简单但越简单的工具越容易被人用复杂。理解了底层原理按业务特性做选型和配置才能让它在系统里真正发光。最后分享一个我自己的小习惯每次接一个新项目我会先画一张系统缓存架构图标清楚哪些数据缓存、哪些不缓存、过期时间谁决定的、缓存挂了降级到哪一步。这个习惯帮我躲过好多次线上事故。你们也可以试试花一小时画图省下熬夜排查的心力值得。
返回列表