ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Redis实战全解析:从配置、数据结构到持久化与故障排查

Redis实战全解析:从配置、数据结构到持久化与故障排查

简介:Redis 是广泛使用的开源内存数据结构存储系统,常用于缓存、数据库和消息代理。这份分享 PPT 面向后端开发与运维人员,适合用来快速建立 Redis 知识框架或作为组内技术分享的讲义。资源包含 1 个 PPTX 演示文稿,整体仅 1.59MB,内容紧凑,已有 161 人浏览学习。演示从 Redis 简介出发,介绍了其读 110000 次/秒、写 81000 次/秒的高性能表现,以及 string、hash、set、sorted set、list 等丰富数据结构;同时分析了主从复制、读写分离和原子性操作带来的优势,也指出了在线扩容困难、宕机影响读写等局限。配置文件部分梳理了 redis.conf 中 port、timeout、daemonize、databases 等关键项。持久化部分重点对比了 RDB 快照与 AOF 日志的优缺点,并说明 save、appendfsync、auto-aof-rewrite 等核心参数的含义。命令部分整理了 EXISTS、DEL、EXPIRE、SET、GET、INCR 等常用 key 与 string 操作。通过这份资源,可系统理解 Redis 的核心机制与实际应用场景,为后续项目选型和调优提供参考。

1. 为什么技术分享总拿Redis开刀:读11万写8.1万的“快”是怎么来的

Redis是一款基于内存的key-value数据结构服务器,读取速度能达到11万次/秒,写入速度8.1万次/秒,这个性能数字是它在缓存领域站稳脚跟的根本原因。我第一次在生产环境用Redis,是解决多节点会话共享的问题:之前session存本地内存,节点一多就失效,换成Redis之后,登录状态随便切节点都不会丢。这份技术分享PPT从基础特性讲起,覆盖配置文件、五大数据结构、RDB与AOF持久化、事务以及发布订阅,适合两类人:一是想系统过一遍Redis的后端开发者,二是要在团队内做技术分享、需要一份完整底稿的从业者。下面按这份PPT的知识推进顺序,把每个模块的技术点讲透,并补上实际踩过的坑。

2. Redis配置文件实战:redis.conf里值得细抠的七个参数

2.1 从默认配置到生产可用:端口、守护进程、日志级别怎么调

PPT把配置放在很前面的位置是有道理的:Redis装好之后,第一步不是敲命令,而是把redis.conf里的基础项先理清楚。新手最容易翻车的地方是启动方式:直接执行redis-server会以前台方式运行,终端一关,Redis进程跟着就没了。要让它常驻后台,得先改配置里的daemonize。

# 定位配置文件 find / -name "redis.conf" 2>/dev/null # 修改核心配置项 vim /usr/local/redis/redis.conf # redis.conf 核心基础配置 port 6379 # 监听端口,默认6379;多实例建议用6380、6381错开 timeout 0 # 客户端闲置N秒后关闭;0表示不主动断开 daemonize yes # 后台守护进程方式运行 tcp-backlog 511 # 已完成连接队列长度,高并发场景可调大 logfile "/var/log/redis/redis.log" # 日志文件绝对路径 loglevel notice # 日志级别:debug/verbose/notice/warning databases 16 # 逻辑库数量,默认16个,默认操作0号库

配置要解释的地方不少。port默认是6379,这个端口号是Redis社区的历史习惯,线上同一台机器部署多实例时,通常顺着6380、6381往下排,避免端口冲突。timeout设为0的意思是服务端不主动断开闲置连接,内部服务一般这么配;如果连接数紧张,可以设一个300秒的闲置超时,这能在连接池配置不合理的情况下,兜底释放一部分坏连接。

daemonize改成yes之后,Redis转入后台运行,日志不再打到终端,所以logfile必须写明绝对路径。我见过有同事把logfile留空,服务跑了两个月,出问题时找不到任何日志来分析,只能靠复现来定位,这就是一开始没把日志当回事的教训。loglevel在生产建议用notice,debug会输出海量内部命令日志,线上开启会拖慢性能,只适合本地排障时临时打开。

还有一点容易被忽略:修改redis.conf之后,不是直接执行redis-server就能生效。不带参数启动时,Redis会使用内置默认配置运行,你改动过的配置文件根本不会被加载。很多新手的服务配置改了没效果,问题就出在这一步。正确的启动方式是redis-server /usr/local/redis/redis.conf,启动后也可以用CONFIG GET daemonize确认当前值。

2.2 databases 16背后:多库隔离与select切换

PPT里提到默认数据库数量是16,默认操作0号库。这个设计允许单实例通过select命令切换逻辑库,表面上实现了业务隔离。

redis-cli -p 6379 127.0.0.1:6379> select 3 OK 127.0.0.1:6379[3]> set order:20250101 "pending" OK 127.0.0.1:6379[3]> get order:20250101 "pending" 127.0.0.1:6379[3]> select 0 OK 127.0.0.1:6379> get order:20250101 (nil)

这段命令演示了多库切换之后,key在不同库之间是相互隔离的,3号库写入的order:20250101在0号库读不到。排查“数据写进去了但读不到”的问题时,先DBSIZE看一下当前库的key数量,再用select切库验证,能快速确认是不是库选错了。逻辑上多库很方便,但生产环境我不建议用多库做业务隔离,原因有两个。

第一,多库之间没有权限隔离。任何客户端连上Redis,默认就能select到所有库,根本没有“这个库只允许这个业务访问”的控制能力,安全边界等于没有。第二,Redis Cluster集群模式只支持0号库,将来要从单实例迁到集群,所有多库的key都得重新规划前缀和迁移方案,改造工作量比想象中大得多。

我一般会建议:一个业务独占一个Redis实例,用key前缀做命名空间,比如user:1001、order:20250101。这样排障时能在keys user:*里直接看到全部相关key;将来迁移集群时也按前缀分槽即可;监控报警还可以按实例粒度去配置。PPT里列出的databases 16只是默认值,真正决定用几个库的是架构设计。

2.3 改完配置不用重启:CONFIG命令的运行时修改

配置文件不是修改Redis参数的唯一途径。CONFIG GET和CONFIG SET可以在运行时动态调整参数,省去一次重启窗口。但这里有个容易忽略的细节:CONFIG SET只改内存中的值,改完直接重启,配置会回到原样。要让改动落到磁盘上的redis.conf,还需要执行CONFIG REWRITE。

redis-cli -p 6379 127.0.0.1:6379> CONFIG GET maxmemory 1) "maxmemory" 2) "0" 127.0.0.1:6379> CONFIG SET maxmemory 2gb OK 127.0.0.1:6379> CONFIG GET maxmemory 1) "maxmemory" 2) "2gb" 127.0.0.1:6379> CONFIG REWRITE OK

这段命令先把maxmemory从0改为2gb,然后通过CONFIG REWRITE写回配置文件。maxmemory在默认配置下是0,表示不限制内存上限,这在生产环境是危险的:内存打满时操作系统会直接杀掉Redis进程,连个像样的错误日志都看不到。设置一个明确的内存上限,再配好淘汰策略,是上线前必须做的事。

CONFIG SET虽然是热生效,但不是所有参数都适合线上直接改。以maxmemory-policy为例,如果当前内存占用已经超过新设的上限,Redis会立刻启动key淘汰流程,在业务高峰期这可能表现为大量GET请求返回nil,甚至引发缓存雪崩。改这类参数前,先通过INFO memory看一下used_memory距离上限还有多少余量,评估淘汰可能命中的key范围,再决定是否执行。这个“改参数前先看存量”的习惯,能帮你避开大多数配置引发的事故。

3. 数据结构与命令:从Key到Set集合运算的实战选型

3.1 Key的全局操作与过期管理

PPT里对Key命令列得很全:EXISTS、DEL、EXPIRE、TTL、PERSIST、RANDOMKEY、RENAME、TYPE、KEYS。这些命令看起来零散,实际上分成三组:存在性判断、过期时间管理、元信息查询。

redis-cli -p 6379 127.0.0.1:6379> SET session:token:abc "user_1001" EX 300 OK 127.0.0.1:6379> EXISTS session:token:abc (integer) 1 127.0.0.1:6379> TTL session:token:abc (integer) 283 127.0.0.1:6379> PERSIST session:token:abc (integer) 1 127.0.0.1:6379> TTL session:token:abc (integer) -1 127.0.0.1:6379> DEL session:token:abc (integer) 1

这段命令模拟了一个带过期时间的会话token:SET时通过EX参数直接指定300秒生存期;EXISTS确认key存在;TTL返回剩余时间,单位是秒;PERSIST把key从“带过期”改成“永久”,执行后TTL返回-1;最后DEL删除key。TTL返回-2表示key不存在,-1表示key存在但没有关联过期时间,这两个负数返回值是新手常见盲区,排查过期问题时先分清这两个状态。

KEYS命令要特别提醒:线上生产环境不要用KEYS *去扫key,这个命令会阻塞Redis主线程,当key数量达到百万级别时,一次扫描可能阻塞几十秒。PPT里的KEYS pattern用法适合学习阶段,不适合生产排查。替代方案是SCAN命令,分批迭代返回,不会阻塞服务。

redis-cli -p 6379 127.0.0.1:6379> SCAN 0 MATCH user:* COUNT 100 1) "184" 2) 1) "user:1001" 2) "user:1002"

SCAN的第一个返回值是下一次迭代要用的游标,传0开始,返回的游标变成184,下一次继续用SCAN 184去扫。COUNT只是提示,不是精确返回条数。这个用法要记牢,线上排查数据分布时全靠它。

3.2 String与Hash:缓存对象时怎么选

String类型是Redis最基本的类型,SET、GET、MSET、MGET这类命令属于高频操作。PPT里列出的INCR、DECR、INCRBY、DECRBY自带原子性,适合做计数器场景。SETEX可以把值和过期时间一次性设置好,减少一次网络往返。

Hash类型则适合存结构化对象。两种做法对比如下:

场景String做法Hash做法
存用户信息set user:1001 '{"name":"zhang","age":30}'hset user:1001 name "zhang" age 30
读单个字段get后自行解析JSONhget user:1001 name
更新单个字段整个JSON读出来改完写回hset user:1001 age 31

用String存JSON的好处是读写都简单,一个GET就能拿到整个对象;坏处是只要改一个字段,就得把整个JSON读出来、改完再写回去。用Hash把字段打散,更新单个字段只需一次HSET。大多数缓存场景我会优先考虑Hash,特别是对象字段经常局部更新的情况。

但Hash也有边界:如果字段特别多,比如一个对象有上百个字段,HGETALL的返回体很大,内存占用和序列化开销都要重新评估。字段少、整体读多写少的,也可以直接用String。没有银弹,选型标准就两条:更新粒度细不细、读取范围全不全。

127.0.0.1:6379> HSET user:1001 name "zhang" age 30 city "beijing" (integer) 3 127.0.0.1:6379> HGET user:1001 name "zhang" 127.0.0.1:6379> HINCRBY user:1001 age 1 (integer) 31 127.0.0.1:6379> HGETALL user:1001 1) "name" 2) "zhang" 3) "age" 4) "31" 5) "city" 6) "beijing"

HSET一次设置多个字段,返回本次新增字段数量;HGET取单个字段,避免全量解析;HINCRBY对整数类型的字段做原子自增;HGETALL取回全部字段,结果按field、value交替排列。注意HINCRBY要求字段的值是整数,如果误存了非数字字符串,会返回语法错误。

3.3 List:队列操作与阻塞命令

List类型的命令也很直观:LPUSH从头部插入,RPUSH从尾部插入,LRANGE取区间元素,LPOP/RPOP弹出。PPT重点列出的BLPOP和BRPOP是阻塞版本,在列表为空时会阻塞连接,直到有数据写入或超时。这两个命令是“轮询转通知”的关键,用它们做任务队列可以省掉反复拿空的轮询请求。

redis-cli -p 6379 127.0.0.1:6379> RPUSH task:queue "job_1001" "job_1002" (integer) 2 127.0.0.1:6379> BLPOP task:queue 5 1) "task:queue" 2) "job_1001" 127.0.0.1:6379> LLEN task:queue (integer) 1

BLPOP task:queue 5在队列有数据时立即返回队尾元素;没有数据时阻塞最多5秒,超时返回nil。客户端拿到nil后可以选择继续调用,也可以退出循环。阻塞命令虽然不占CPU,但会占一个连接,连接池大小要预留足够,否则大量阻塞连接会把连接池打满。

List做队列有个经典问题:消息消费后如果处理程序中途崩溃,LPOP/RPOP返回的消息就彻底丢了。可靠一点的做法是用RPOPLPUSH把消息先转存到备份列表,确认处理成功后再从备份列表删除,这相当于给消息上了一份后悔药。代价是逻辑复杂度上升,需要业务侧配合,不是Redis单方面能解决的。

3.4 Set:集合运算做标签筛选

PPT里Set的命令占了一大页,SADD、SCARD、SMEMBERS、SPOP、SISMEMBER,以及三个集合运算:SDIFF差集、SINTER交集、SUNION并集,每个都有带STORE后缀的版本,可以直接把结果写进目标key。

举个例子:一个用户兴趣标签系统,两个集合分别存“看过A课程的用户”和“看过B课程的用户”。要找出两个都看过的用户,交集命令一次搞定。

127.0.0.1:6379> SADD course:a:users "u1001" "u1002" "u1003" (integer) 3 127.0.0.1:6379> SADD course:b:users "u1002" "u1003" "u1004" (integer) 3 127.0.0.1:6379> SINTER course:a:users course:b:users 1) "u1003" 2) "u1002" 127.0.0.1:6379> SINTERSTORE course:common:users course:a:users course:b:users (integer) 2

SINTER直接返回交集结果,适合结果集不大、临时查询的场景;SINTERSTORE把交集结果写入新key,适合结果集很大、后续还要多次读取的场景。SPOP可以从集合中随机弹出元素,适合抽奖、随机推荐这类逻辑。Set类型的去重特性是天然优势,比在应用层用List加contains判断高效得多。

4. Redis持久化实操:RDB快照与AOF日志的取舍与恢复验证

4.1 RDB快照:save 60 1000背后的触发逻辑

Redis持久化解决的是“内存数据在进程退出后不丢”的问题。PPT里把两种方式拆得很清楚:RDB是某一时刻的全量数据快照,AOF是操作命令的追加日志。

RDB的核心配置PPT列了几项。save 60 1000的意思是:60秒内如果发生1000次写操作,就触发一次快照保存。这个条件是“时间”和“写入次数”同时满足才触发,不是二选一。stop-writes-on-bgsave-error设为no,表示快照保存出错时继续接受写入;如果设成yes,持久化出错的同时Redis会拒绝所有写请求,这是一种保护策略,但代价是业务写入中断。rdbcompression yes对快照文件做压缩,省磁盘但多耗CPU。

# redis.conf RDB相关配置 save 60 1000 # 60秒内1000次写入触发快照 stop-writes-on-bgsave-error no # 快照出错时是否停止写入 rdbcompression yes # 是否压缩RDB文件 dbfilename dump.rdb # 快照文件名 dir /var/lib/redis # 快照文件保存目录

手动触发可以用SAVE或BGSAVE。SAVE是前台执行,会阻塞Redis直到快照写完;BGSAVE由子进程执行,不阻塞主线程。生产环境一般只用BGSAVE,除非你明确想用阻塞行为来人工控制流量节奏。

redis-cli -p 6379 BGSAVE Background saving started redis-cli -p 6379 LASTSAVE (integer) 1735689600

LASTSAVE返回的是最近一次成功快照的Unix时间戳。想在备份脚本里判断快照是否成功,可以定期执行LASTSAVE并和当前时间做差,超过RDB触发周期还没更新,基本可以判断快照链路出了问题。

4.2 AOF:appendfsync三种策略的丢数据边界

AOF的核心配置首先是appendonly yes,开启后每个写命令都会追加到aof文件末尾。appendfsync控制同步策略,三个值的取舍直接决定丢数据范围:

策略行为丢数据范围
always每个写命令都执行磁盘同步最多丢1条命令
everysec每秒执行一次磁盘同步最多丢1秒内的写命令
no由操作系统决定何时同步取决于系统刷盘时机,可能丢几秒数据

默认是everysec,性能和数据安全之间取中间值。PPT里说得很直接:默认每秒写一次AOF,那么最多丢失1秒的数据。always性能最差但最安全,适合对数据一致性要求极高的场景;no性能最好但最不可控,生产不推荐。

AOF文件会不断增长,所以需要rewrite压缩机制。PPT里的两个配置:auto-aof-rewrite-percentage 100表示当前文件大小达到上一次rewrite后文件大小的一倍时触发rewrite;auto-aof-rewrite-min-size 64m表示文件至少64MB才执行rewrite。两个条件同时满足才触发。rewrite本质是把当前内存里的数据重新生成一份精简的命令序列,替换掉历史积累的庞大日志。

redis-cli -p 6379 BGREWRITEAOF Background append only file rewriting started

4.3 两种持久化的优缺点对比

PPT给了一个很清晰的对比,整理成表:

维度RDBAOF
数据备份能力保存某一时间点的数据,适合备份丢失数据范围小,恢复粒度细
性能影响fork子进程保存,主线程几乎不受影响每秒写盘有性能损耗,always损耗最大
文件体积压缩后体积小相同数据集下体积通常大于RDB
恢复速度直接加载快照,恢复快重放命令,文件大时恢复慢
数据丢失两次快照之间的数据可能丢everysec最多丢1秒数据

这个对比表在实际选型里的作用是:RDB用于定期备份性价比很高,文件小、加载快;AOF用于崩溃恢复更可靠,丢数据范围可控。生产最常见的组合是两者都开,RDB做日常备份,AOF做崩溃恢复兜底。需要注意AOF和RDB同时开启时,Redis启动优先加载AOF文件,因为AOF的记录更完整。

4.4 恢复验证:手动触发快照与AOF重放

配置了持久化不等于万事大吉,恢复流程值得在测试环境完整走一遍。模拟一次“进程崩溃后从AOF恢复”的操作:先启用AOF并写入数据,然后强制kill进程,再重新启动Redis,检查数据是否还在。

# 1. 启动Redis并写入数据 redis-server /usr/local/redis/redis.conf redis-cli -p 6379 SET order:1001 "paid" # 2. 强制杀掉Redis进程(模拟崩溃) kill -9 $(redis-cli -p 6379 PID) # 3. 查看AOF文件是否存在 ls -lh /var/lib/redis/appendonly.aof # 4. 重启Redis redis-server /usr/local/redis/redis.conf # 5. 确认数据恢复 redis-cli -p 6379 GET order:1001 "paid"

kill -9是模拟进程被强杀的最直接方式。重启后Redis发现appendonly.aof存在,会重放文件里的命令来恢复数据。如果数据没有恢复,优先检查dir配置指向的目录里AOF文件位置是否正确,权限是否足够。注意如果用的是Redis 4.0以上版本,可以额外开启aof-use-rdb-preamble,让AOF重写时把存量数据以RDB格式写入,重写后的AOF文件更小、恢复更快。这个参数PPT里没展开,但生产环境我会建议打开。

5. Redis常见问题排查:事务、主从、扩容、发布订阅的四类坑

5.1 事务的“伪原子性”:MULTI/EXEC不会回滚

PPT里列出了MULTI、EXEC、DISCARD、WATCH、UNWATCH这套事务命令。Redis的事务机制和关系型数据库的事务有本质区别:MULTI开启后,命令进入队列,EXEC一次性执行,中间不会插入其他客户端的命令,但某条命令执行出错时,已经执行的命令不会回滚。

现象:执行EXEC时,其中一条命令报错,事务不会撤销,已经成功的命令数据照样改了。

原因:Redis事务设计成“批量执行命令队列”,而不是“要么全成功要么全失败”。WATCH可以在执行前监视key,如果key被改动则整个事务不执行,但这只是乐观锁层面的保护,不是回滚机制。

解决:依赖事务保证数据强一致是不现实的。常见做法是执行前先把队列里的命令在本地验证一遍,比如用EXISTS确认key存在、用TYPE确认类型正确,再进入事务;事务执行后检查每个命令的返回值,发现异常立即做补偿操作。

redis-cli -p 6379 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> SET count:1001 100 QUEUED 127.0.0.1:6379> INCR count:1001 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) (integer) 101

示例里两条命令都成功。真正踩坑的场景是:一个事务里混着SET和针对错误数据类型的操作,比如对字符串值执行LPUSH,队列阶段不报错,EXEC阶段才报错,前面的SET已经生效。如果你需要事务里有条件判断,用WATCH配合重试机制,这个模式也叫乐观锁事务。

5.2 主从复制延迟:刚写入主的key在从库读不到

PPT提到Redis支持主从同步、读写分离。但主从之间是异步复制,主节点写成功后立即返回客户端,从节点的同步存在网络延迟和队列积压。

现象:客户端向主库写入数据后,立刻从从库读取,读不到;或者从库读到的是旧值。

原因:复制是异步执行的,主库收到写命令后先更新自身内存,再通过复制流把命令传给从库。从库积压了较多命令时,延迟会更明显。另外从库因为不主动执行过期删除,可能在主库已经删掉key之后短暂读到过期数据,需要靠主库同步DEL来清理。

解决:业务上要接受“最终一致”而不是“强一致”。对于必须立即读到最新值的场景,读写都走主库;能接受短暂延迟的读请求才路由到从库。同时用INFO replication监控从库的lag值,lag超过阈值时把该从库从负载均衡里摘掉一段时间。

redis-cli -p 6380 INFO replication # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:3 master_sync_in_progress:0

重点关注master_last_io_seconds_ago,这个值表示距离最近一次主从通信过去了多少秒,持续增长且数值过大,说明主从链路有异常。如果主库宕机而没配置自动故障转移,写请求会一直失败,直到人工把从库提升为主库。PPT里说主机从机的宕机都会导致前端部分读写请求失败,就是这个原因。

5.3 在线扩容的痛:集群容量到上限之后的三种选择

PPT在缺点部分明确写了:较难支持在线扩容,集群容量达到上限时在线扩容会变得很复杂。这一点在Redis Cluster尤其明显。

现象:业务增长导致内存吃紧,想给集群加节点,发现数据迁移期间请求延迟升高,部分slot迁移报错。

原因:Redis Cluster的扩缩容本质是把哈希槽从一个节点迁移到另一个节点,迁移过程涉及大量key的搬运,期间新旧节点都要处理路由请求,在一个大key或多个热点key的迁移中,阻塞感很明显。

解决:扩容尽量放在业务低峰期执行;迁移前用redis-cli --bigkeys提前识别大key,把大key先拆分或延迟迁移;迁移过程中把cluster-require-full-coverage设为no,避免部分slot不可用时整个集群拒绝写入。单实例内存远没有到上限的时候,先用maxmemory限制和淘汰策略撑一段时间,把扩容往后挪,也是一种务实选择。

5.4 发布订阅的消息不落地:客户端掉线期间的消息去向

PPT介绍了SUBSCRIBE/PUBLISH命令,可以用于简单的消息发送与订阅。但发布订阅模式下消息是不落地的。

现象:发布者发布消息时,订阅者刚好断线或阻塞,消息就静静消失了,订阅者重连后收不到。

原因:Redis的pub/sub模式是实时转发,消息发到频道后,只有当前在线的订阅者才能收到,Redis不会为离线客户端保存消息。

解决:如果业务需要离线消息补发,不要用pub/sub,改用List做持久化消息队列:生产者用LPUSH写入列表,消费者用BRPOP阻塞读取,消息在消费成功前不会丢。pub/sub适合的场景是实时通知、在线状态广播,对消息丢失不敏感的业务。发布订阅还有个隐藏问题:订阅者处理速度慢时,消息会在客户端缓冲区积压,积压到一定阈值,Redis会强制断开连接。

5.5 四条高频踩坑记录:现象、原因、解决

踩坑一:keys * 导致Redis卡死 现象:执行keys user:*后,客户端命令在几十秒内全部超时。 原因:keys是O(N)遍历,数据量到百万级时阻塞主线程。 解决:用SCAN分批代替,或者在从库上执行查询。

踩坑二:设置了maxmemory却没有淘汰策略 现象:内存到上限后,写入报错OOM command not allowed when used memory > 'maxmemory'。 原因:maxmemory设置了上限,但maxmemory-policy保持默认的noeviction,不淘汰任何key。 解决:按业务类型设置allkeys-lru或volatile-lru,并确认热点key不会被误淘汰。

踩坑三:并发登录导致Redis连接数打满 现象:客户端报too many connections,或者服务日志大量出现连接超时。 原因:连接池配置不当,每个请求都新建连接,TIME_WAIT堆积。 解决:用连接池复用连接,把timeout参数设为合理值,并设置maxclients上限。

踩坑四:业务日志显示写入成功但重启后数据全没了 现象:Redis重启后,之前SET的数据查询不到。 原因:持久化未开启,或者RDB/AOF配置没有生效,数据只存在内存里。 解决:确认appendonly yes和save策略已配置,用CONFIG GET appendonly检查当前值,并在测试环境执行一次完整的kill -9恢复演练。

6. 验证与进阶:用INFO命令给Redis做一次真实体检

6.1 INFO stats:命中率与命令分布一眼看穿

看完这份PPT,全套理论都有了,但真正判断Redis跑得好不好,得靠INFO命令。INFO stats提供的是累计统计值,重点看三个指标:keyspace_hits和keyspace_misses决定命中率,total_commands_processed反映压力大小,rejected_connections和evicted_keys直接暴露连接问题和淘汰风险。

redis-cli -p 6379 INFO stats # Stats total_commands_processed:8654321 keyspace_hits:7210000 keyspace_misses:1444321 evicted_keys:125 rejected_connections:0

命中率=keyspace_hits/(keyspace_hits+keyspace_misses),大概算一下,7210000/8654321大约是83%,这个值算健康。如果低于60%,就要考虑缓存key的过期时间是不是太短,或者key的命名空间设计导致大量不命中。evicted_keys如果持续增长,说明内存淘汰正在发生,热点key可能随时被挤出,需要检查maxmemory-policy的设置。rejected_connections大于0且持续增加,说明连接数已经到过上限,需要立刻排查连接池配置。

6.2 把PPT做成一场真的技术分享:验证每个结论

我建议拿到这份PPT后,别急着只读一遍,按下面这个路径完整实操一次:

章节验证动作预期结果
配置改daemonize、logfile后重启实例进程后台运行,日志文件生成
数据结构用Hash存对象,用Set做交集命令返回符合预期
持久化写入数据后kill -9,重启检查AOF恢复数据成功
事务故意制造错误命令,确认不回滚看到部分命令成功的效果
主从起一个从库并同步INFO replication显示lag正常
发布订阅订阅频道,发布消息在线订阅者收到推送

这套动作走下来,知识点就真正变成操作记忆了,比单纯看PPT有效得多。我在公司做过一次Redis分享,当时按这个流程演示,现场提问最多的反而是INFO replication的日志解析和AOF恢复的实战过程,因为这些都是PPT之外、实际运维里一定会撞上的问题。

从那以后,我每次拿到一份技术分享资料,都会强制自己把里面所有命令在本地环境完整敲一遍,再对照配置项逐一确认含义,最后补一轮故障模拟。这份Redis PPT我也是一样做的,里面的命令基本都验证过,照着走不会有大坑。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进