资讯动态

Redis 基础教程:从常用命令到实际业务场景

发布时间:2026/10/27 2:07:10 来源:尧图企业网站定制
文章目录1. Redis 介绍与简单使用从内存键值数据库到常见业务场景1.1 先理解 Redis 在系统中的位置1.1.1 Redis 不是“另一种写法的 MySQL”1.1.2 为什么 Redis 通常很快1.1.3 Redis 的常见应用场景2. 启动、连接与基础操作2.1 Redis 的运行模型2.1.1 客户端与服务端2.1.2 安装与启动2.2 配置文件中最需要关注的选项2.2.1 连接与进程配置2.2.2 不要把 Redis 直接暴露到公网2.3 基本连接与数据库编号2.4 键的基本管理2.4.1 键命名建议2.4.2 判断和删除键2.4.3 遍历键时不要使用 KEYS *3. Redis 的核心数据类型3.1 数据类型的总体认识3.1.1 键统一值有多种结构3.2 String最基础也最常用的类型3.2.1 基本读写3.2.2 计数与条件写入3.2.3 String 常见使用场景3.3 Hash保存对象的字段3.3.1 常用命令3.3.2 Hash 与 String 的选择3.4 List顺序、重复与队列3.4.1 常用命令3.4.2 List 的边界3.5 Set去重与集合运算3.5.1 常用命令3.5.2 不要把 SMEMBERS 当作大数据遍历3.6 Sorted Set排序、分数和名次3.6.1 常用命令3.7 其他常用高级类型3.7.1 Bitmap3.7.2 HyperLogLog3.7.3 GEO3.7.4 Stream4. 过期时间与内存淘汰4.1 TTL 的基本语义4.1.1 设置与查询过期时间4.1.2 过期不是精确倒计时4.2 淘汰策略4.2.1 区分过期与淘汰4.2.2 常见策略4.3 大键与内存风险5. 持久化Redis 重启后如何恢复数据5.1 RDB 快照5.1.1 工作机制5.1.2 RDB 的优缺点5.2 AOF 追加日志5.2.1 工作机制5.2.2 AOF 的优缺点5.3 RDB 与 AOF 如何配合6. 事务、原子操作与 Lua6.1 Redis 事务的命令6.2 容易误解的“事务”6.3 用 Lua 完成条件原子操作7. 缓存使用模式与常见问题7.1 Cache Aside最常用的旁路缓存7.1.1 读流程7.1.2 写流程7.2 缓存穿透7.2.1 现象7.2.2 常用处理7.3 缓存击穿7.3.1 现象7.3.2 常用处理7.4 缓存雪崩7.4.1 现象7.4.2 常用处理7.5 缓存一致性8. 分布式锁、会话与消息通信8.1 用 SET NX EX 实现基本锁8.2 会话存储8.3 Pub/Sub 与 Stream 的区别8.3.1 Pub/Sub8.3.2 Stream9. 简单实战与排错9.1 一组可直接练习的命令9.1.1 保存用户资料与过期会话9.1.2 计数器9.1.3 排行榜9.1.4 标签集合9.2 查看运行状态9.3 常见错误清单9.3.1 用 KEYS * 排查线上数据9.3.2 只设置键不设置过期时间9.3.3 把 Redis 当成完全不会丢数据的主数据库9.3.4 锁释放不校验持有者9.3.5 把 Pub/Sub 当作可靠队列9.3.6 所有对象都序列化成一个巨大 JSON10. 本课总结与复习10.1 一张图串起 Redis10.2 自测题10.2.1 Redis 为什么不能简单理解为“内存中的 MySQL”10.2.2 什么场景应选择 Hash而不是 String10.2.3 TTL 返回 -1 和 -2 分别表示什么10.2.4 为什么缓存写入通常采用“更新数据库后删除缓存”10.2.5 Redis 事务会像 MySQL 一样在部分命令失败时完整回滚吗10.2.6 为什么不能把 Pub/Sub 当作可靠消息队列1. Redis 介绍与简单使用从内存键值数据库到常见业务场景Redis 是一个把数据放在内存中、以键值对为基本模型、同时提供多种数据结构的服务端数据库。它依靠内存访问、精简的数据结构和高效的网络模型获得远高于传统磁盘数据库的读写性能常用于缓存、会话、计数、排行榜、分布式锁和消息通信但它的持久化、容量和一致性边界同样需要在设计中认真考虑。1.1 先理解 Redis 在系统中的位置1.1.1 Redis 不是“另一种写法的 MySQL”MySQL 以表、行、列、主键、外键和事务等关系模型组织数据擅长按复杂条件查询并用磁盘保证长期持久化。Redis 则以键值对为入口把更多语义放进值的数据结构里例如字符串、哈希、列表、集合和有序集合。两者最常见的配合方式是请求 ↓ 先查 Redis ├─ 命中直接返回 └─ 未命中查询 MySQL ↓ 写回 Redis ↓ 返回结果Redis 可以单独作为数据库使用也可以作为缓存、消息通信组件或临时状态存储使用。但在强事务、复杂关联查询和长期事实数据等场景中通常仍由关系型数据库承担核心数据职责。1.1.2 为什么 Redis 通常很快Redis 的性能来自多个因素共同作用不能简单归结为“用了内存”数据主要存放在内存中内存随机访问延迟通常远低于机械磁盘或网络存储。键值模型直接定位数据大多数命令通过键即可找到目标不需要解析复杂 SQL 再制定多表执行计划。数据结构针对操作优化列表、集合、有序集合等结构可以直接完成对应操作不必把所有数据取到客户端处理。命令执行路径短Redis 的核心命令执行线程按顺序处理命令减少了大量线程同步和切换成本。网络 I/O 高效Redis 使用事件驱动和 I/O 多路复用较新版本还支持多线程处理网络读写但命令的真正执行仍保持清晰、原子化的语义。这里的“单线程”主要指核心命令执行模型并不是说 Redis 进程从头到尾只有一个线程。持久化、异步释放、网络 I/O 和部分后台任务都可能使用额外线程。1.1.3 Redis 的常见应用场景场景典型数据结构说明热点数据缓存String、Hash承担高频读请求降低数据库压力登录会话String、Hash保存会话状态并设置过期时间计数器、限流String、HashINCR等命令天然适合计数排行榜Sorted Set按分数排序、获取名次和区间数据标签、关系判断Set去重、交集、并集和差集队列或异步任务List、StreamList 适合简单队列Stream 更适合需要消费组和确认机制的场景分布式锁String 过期时间借助SET NX EX和 Lua 脚本实现基本互斥实时通知Pub/Sub、StreamPub/Sub 实时但离线消息会丢失可靠消费应使用 Stream选择 Redis 场景时不应只问“它能不能做”还要问数据丢失代价、单键规模、访问模式、过期策略以及是否需要跨多个键保持原子性。2. 启动、连接与基础操作2.1 Redis 的运行模型2.1.1 客户端与服务端Redis 通常由一个redis-server进程监听 TCP 端口默认端口是6379。客户端通过redis-cli、编程语言客户端或其他工具建立连接再发送命令并接收结果。redis-cli / 应用客户端 ↓ RESP 协议 redis-server:6379 ↓ 内存数据结构 持久化文件Redis 使用 RESP 协议交换数据协议本身简单便于快速解析。客户端和服务端可以部署在同一台机器也可以跨机器访问但跨机器访问会把网络延迟纳入总耗时。2.1.2 安装与启动Ubuntu/Debian 环境可以使用包管理器安装sudoaptupdatesudoaptinstallredis-serversudosystemctlenable--nowredis-serverRocky/CentOS 一类系统可以使用sudodnfinstallredissudosystemctlenable--nowredis也可以从源码编译并手动启动makesudomakeinstallredis-server /path/to/redis.conf课程实验首先要确认服务已经启动redis-cli-h127.0.0.1-p6379ping正常返回PONG这里的PING只证明网络连接和 Redis 命令处理正常不代表持久化配置、内存容量或安全策略都正确。2.2 配置文件中最需要关注的选项2.2.1 连接与进程配置常见配置项包括bind 127.0.0.1 port 6379 daemonize yes dir /var/lib/redis dbfilename dump.rdbbind决定监听哪些网卡地址。port是服务端口。daemonize控制是否以守护进程方式运行由 systemd 管理时通常不要手工再守护化。dir是持久化文件的工作目录。dbfilename是 RDB 文件名。2.2.2 不要把 Redis 直接暴露到公网Redis 保存的是应用状态误暴露端口可能造成数据泄露、删除甚至远程执行风险。至少要遵守以下原则默认只监听127.0.0.1或内网地址。通过防火墙限制来源网络。配置密码或 Redis 6 之后的 ACL。不把危险管理命令暴露给不可信客户端。跨公网访问时使用 TLS、VPN 或网关不直接开放默认端口。实验环境也应避免使用0.0.0.0加空密码的组合。2.3 基本连接与数据库编号默认配置通常会提供多个逻辑数据库redis-cli-h127.0.0.1-p6379-n0连接后可以执行PING SELECT 1 DBSIZESELECT只是切换同一个 Redis 实例内的逻辑数据库并不是切换一个独立服务器。不同逻辑数据库之间默认不能直接参与同一条多键命令Redis Cluster 只使用数据库 0。DBSIZE返回当前逻辑数据库的键数量通常比遍历全部键便宜。FLUSHDB会清空当前数据库FLUSHALL会清空所有逻辑数据库。它们是危险命令只应在明确的数据清理实验中执行。2.4 键的基本管理2.4.1 键命名建议推荐用有层次、可扫描、稳定的前缀例如user:1001:profile user:1001:session order:20261015:count rank:game:daily:20261015一个常用格式是业务:对象:标识:属性键名应表达业务含义但不要把不断变化的数据直接拼进键名否则会产生大量难以管理的键。2.4.2 判断和删除键EXISTS user:1001:profile TYPE user:1001:profile DEL user:1001:profile UNLINK user:1001:profileEXISTS返回键是否存在。TYPE返回值的数据类型。DEL同步删除键。UNLINK先从键空间解除引用再把内存释放放到后台完成适合删除大键时降低主线程阻塞。2.4.3 遍历键时不要使用KEYS *KEYS pattern会扫描整个键空间键很多时可能长时间阻塞命令执行。在线环境通常使用增量遍历SCAN 0 MATCH user:* COUNT 100SCAN返回一个游标需要反复调用直到游标回到0。它是弱一致遍历能降低阻塞风险但不保证一次完整快照。3. Redis 的核心数据类型3.1 数据类型的总体认识3.1.1 键统一值有多种结构Redis 的最外层始终是“键 → 值”不同数据类型改变的是值如何组织类型值的基本形态最适合的问题String字节串、数字或序列化数据单值缓存、计数、位操作Hash字段到值的映射对象属性、局部更新List有顺序、可重复的列表栈、队列、最近列表Set无序、去重的集合标签、关系、交并差Sorted Set带分数的去重集合排行榜、按分值范围查询Bitmap按位组织的字符串签到、布尔状态HyperLogLog基数估算结构大基数去重统计GEO带经纬度的有序集合附近地点、距离计算Stream追加式消息流消费组、消息确认初学者最容易出现的误区是“能用一个大的 String 解决就不考虑其他类型”。这通常会导致每次读取、修改和序列化整块数据增加网络传输与命令耗时。3.2 String最基础也最常用的类型3.2.1 基本读写SET user:1001:name Alice GET user:1001:name MSET user:1001:name Alice user:1001:city Harbin MGET user:1001:name user:1001:city STRLEN user:1001:nameGET读取不存在的键时返回空值客户端需要把“键不存在”和“键存在但值为空”区分开时应结合EXISTS或缓存空值策略。3.2.2 计数与条件写入SET article:100:views 0 INCR article:100:views INCRBY article:100:views 10 DECR article:100:views SETNX lock:job:1 owner-aINCR对数字字符串原子加一因此可用于计数和简单限流。SETNX只在键不存在时写入可用于表示“第一次占用”。设置值时同时指定过期时间可以避免“设置了键却忘记设置过期时间”SET session:abc token-123 EX 1800 SET lock:order:100 owner-a NX EX 10SET NX EX是多条语义组合成的一次原子操作比先SETNX再EXPIRE更可靠。3.2.3 String 常见使用场景缓存序列化后的用户信息。保存验证码和会话令牌。保存页面计数、访问次数和限流计数。存储 JSON、Protobuf 等应用层序列化结果。通过SETBIT、GETBIT和BITCOUNT保存签到或布尔状态。String 的缺点是局部更新能力弱。一个很大的 JSON 字符串即使只修改一个字段也可能需要读取全部内容再整体写回。3.3 Hash保存对象的字段3.3.1 常用命令HSET user:1001 name Alice age 20 city Harbin HGET user:1001 name HMGET user:1001 name age HGETALL user:1001 HEXISTS user:1001 email HDEL user:1001 city HINCRBY user:1001 age 1Hash 把多个字段放在同一个键下适合字段数量有限、需要频繁读取或修改部分字段的对象。3.3.2 Hash 与 String 的选择需求更合适的类型整体读写一个对象String频繁更新对象中的少量字段Hash需要分别设置字段过期时间通常拆成多个键对象很大且字段很多评估 Hash 规模必要时拆分需要跨对象聚合查询通常应由数据库承担Redis 的 Hash 不能像 JSON 那样任意嵌套。复杂嵌套结构通常仍需要应用层序列化或者按业务读取方式重新拆分键。3.4 List顺序、重复与队列3.4.1 常用命令RPUSH queue:mail mail-1 mail-2 LPUSH queue:mail mail-3 LPOP queue:mail RPOP queue:mail LRANGE queue:mail 0 -1 LLEN queue:mail从左侧写入、右侧读取可以形成先进先出队列从同一侧写入和读取则更像栈。阻塞读取适合作简单消费者BLPOP queue:mail 5它在列表为空时最多等待 5 秒有数据则取出。相比客户端不断轮询阻塞读取更节省资源。3.4.2 List 的边界列表允许重复元素。LRANGE适合读取区间不代表列表可以像数组一样随机 O(1) 访问。按值删除没有像 Set 那样直接的成员删除语义。简单队列可以依靠 List但如果需要消费组、消息确认、失败重试和消息回溯应使用 Stream。3.5 Set去重与集合运算3.5.1 常用命令SADD article:100:tags mysql redis database SISMEMBER article:100:tags redis SCARD article:100:tags SMEMBERS article:100:tags SREM article:100:tags database SINTER set:a set:b SUNION set:a set:b SDIFF set:a set:bSet 的成员无序且自动去重适合标签、点赞用户集合、共同关注和访问权限集合。3.5.2 不要把SMEMBERS当作大数据遍历集合很大时SMEMBERS会一次返回全部成员可能造成网络和内存压力。只关心成员是否存在时使用SISMEMBER需要遍历大集合时考虑SSCAN。3.6 Sorted Set排序、分数和名次3.6.1 常用命令ZADD rank:game 80 alice 95 bob 70 carol ZINCRBY rank:game 5 alice ZREVRANGE rank:game 0 9 WITHSCORES ZRANGE rank:game 0 -1 WITHSCORES ZREVRANK rank:game alice ZSCORE rank:game alice ZRANGEBYSCORE rank:game 80 100 ZREM rank:game carolSorted Set 中的成员不重复每个成员带一个分数。Redis 按分数排序因此非常适合游戏分数排行榜。热搜、销量和活跃度排名。按时间或权重筛选任务。延迟队列和滑动窗口的一部分实现。分数相同的时候还会按成员的字典序形成稳定次序。业务如果要求完全自定义并列规则需要把规则编码进分数或另行处理。3.7 其他常用高级类型3.7.1 BitmapBitmap 使用字符串中的每一位保存布尔状态SETBIT sign:user:1 15 1 GETBIT sign:user:1 15 BITCOUNT sign:user:1它可以高效保存签到、开关和活跃状态但前提是位编号有意义且数据稀疏程度不会造成大量空洞。3.7.2 HyperLogLogPFADD uv:20261015 user-a user-b user-c PFCOUNT uv:20261015HyperLogLog 用固定且较小的内存估算不同元素数量适合 UV 统计。它返回近似值不保存成员因此不能回答“某用户是否已经访问过”。3.7.3 GEORedis 的 GEO 能保存经纬度并计算距离、查询附近对象GEOADD shops 126.63 45.75 shop-a 126.64 45.76 shop-b GEODIST shops shop-a shop-b km GEOSEARCH shops FROMMEMBER shop-a BYRADIUS 5 km ASC它适合附近门店和位置检索的轻量需求不替代具备完整空间索引和复杂几何计算能力的 GIS 系统。3.7.4 StreamStream 是追加式消息流支持消费组和待确认消息XADD stream:orders * orderId 1001 status paid XREAD COUNT 10 STREAMS stream:orders 0 XGROUP CREATE stream:orders group-a 0 MKSTREAM XREADGROUP GROUP group-a consumer-1 COUNT 10 STREAMS stream:orders 相比 Pub/SubStream 能保存历史消息但消息保留、确认、重试和清理仍需要业务策略。4. 过期时间与内存淘汰4.1 TTL 的基本语义4.1.1 设置与查询过期时间SET code:13800000000 123456 EX 300 TTL code:13800000000 PTTL code:13800000000 EXPIRE code:13800000000 60 PERSIST code:13800000000EX以秒设置过期时间。PX以毫秒设置过期时间。TTL返回剩余秒数。PTTL返回剩余毫秒数。PERSIST移除过期时间让键长期存在。对于已存在的键TTL返回-1表示没有过期时间返回-2表示键不存在。4.1.2 过期不是精确倒计时Redis 主要通过两种方式清理过期键访问键时发现已经过期再删除称为惰性删除。后台周期性地抽样检查过期键并删除称为主动过期。因此“到达过期时间”和“物理内存立刻释放”不是同一瞬间。有效语义是过期后的键不应再被返回但内存回收可能稍后完成。4.2 淘汰策略4.2.1 区分过期与淘汰过期某个键达到了自己的 TTL。淘汰内存达到maxmemory后Redis 为了继续写入而删除某些键。没有设置 TTL 的键不会被volatile-*策略淘汰因为这些策略只从“有 TTL 的键”中选择。4.2.2 常见策略策略候选范围与行为noeviction不淘汰写命令可能返回内存不足错误allkeys-lru从所有键中优先淘汰最近最少使用的键volatile-lru只从有 TTL 的键中按 LRU 思路淘汰allkeys-lfu从所有键中优先淘汰访问频率低的键volatile-lfu只从有 TTL 的键中按 LFU 思路淘汰allkeys-random所有键中随机淘汰volatile-random有 TTL 的键中随机淘汰volatile-ttl有 TTL 的键中优先淘汰更早过期的键缓存通常使用合适的allkeys-*策略如果 Redis 中同时存放不能丢的关键状态则必须谨慎配置必要时把关键数据和缓存拆到不同实例。4.3 大键与内存风险一个包含几百万元素的 Hash、List、Set 或 Sorted Set即使单次命令看起来简单删除、复制、迁移或一次性读取都可能阻塞 Redis。设计时要关注单个值有多大。单个集合有多少成员。命令一次会返回多少数据。是否会在主线程中执行耗时删除。是否把无限增长的数据当成固定大小缓存。大集合应按业务维度拆分读取使用分页或SCAN删除可考虑UNLINK或按块清理。5. 持久化Redis 重启后如何恢复数据5.1 RDB 快照5.1.1 工作机制RDB 把某一时刻的数据压缩成快照文件。常见配置save 900 1 save 300 10 save 60 10000 dbfilename dump.rdb dir /var/lib/redis三个数字分别表示满足一定秒数和一定写次数后触发快照。Redis 通常通过 fork 子进程生成快照避免主线程直接长时间遍历全部数据。5.1.2 RDB 的优缺点优点缺点文件紧凑适合备份和传输两次快照之间的新写入可能丢失恢复时加载速度快数据量大时 fork 和快照有资源开销适合灾难恢复和迁移快照周期决定恢复点粒度RDB 不能保证最后一次写入立即落盘。如果业务不能接受数分钟级别的数据丢失只配置 RDB 是不够的。5.2 AOF 追加日志5.2.1 工作机制AOF 把写命令记录下来重启时通过重放命令恢复状态appendonly yes appendfilename appendonly.aof appendfsync everysecappendfsync的常见选择always每次写入都同步持久性更强性能代价更大。everysec通常每秒同步一次是持久性和性能之间的常见平衡但仍可能丢失约一秒数据。no由操作系统决定何时刷盘性能优先丢数据风险更高。AOF 会随着写命令累积而变大因此需要重写。重写的目标是用更少的命令表达等价的数据状态。5.2.2 AOF 的优缺点优点缺点记录粒度更细通常丢数据更少文件通常更大便于理解最近发生的写操作恢复时需要重放命令everysec兼顾性能与持久性仍不是“绝不丢数据”5.3 RDB 与 AOF 如何配合生产环境通常可以根据恢复目标组合 RDB 与 AOF只要快速备份和较大时间粒度的恢复可使用 RDB。需要尽量减少数据丢失应启用 AOF。两者同时启用时Redis 重启会优先利用 AOF 恢复更完整的状态。较新版本还支持混合持久化和多部分 AOF降低重写时的资源压力。无论采用哪种持久化都必须实际备份持久化文件并验证恢复流程。复制到另一台 Redis 实例不等于独立备份因为误删除等逻辑错误也会被复制。6. 事务、原子操作与 Lua6.1 Redis 事务的命令Redis 事务的基本命令是MULTI SET account:1:balance 100 SET account:2:balance 200 EXEC执行过程MULTI开始收集命令。后续命令先进入队列不立即执行。EXEC按顺序执行队列中的命令。DISCARD取消事务。WATCH可以监视键若键在执行前被其他客户端修改事务执行会失败或返回空结果用于乐观并发控制。6.2 容易误解的“事务”Redis 事务保证队列中的命令连续执行不被其他客户端的命令插入但它不是关系型数据库中那种完整回滚事务。例如命令本身在运行时才发现类型错误已经执行成功的其他命令通常不会因为这条错误而自动回滚。因此 Redis 更适合把它理解为“命令批量顺序执行”复杂业务约束仍需应用层、Lua 或数据库配合。6.3 用 Lua 完成条件原子操作分布式锁释放必须“确认锁的持有者后删除”不能直接删除ifredis.call(GET,KEYS[1])ARGV[1]thenreturnredis.call(DEL,KEYS[1])elsereturn0end这段脚本读取锁值并与客户端标识比较只有匹配时才删除从而避免误删其他客户端后来获得的锁。更一般的原子逻辑——例如“库存大于零才扣减”——也可以放进 Lua但脚本应短小、结果确定、避免长时间循环并在集群环境中注意所有键应落在同一槽位。7. 缓存使用模式与常见问题7.1 Cache Aside最常用的旁路缓存7.1.1 读流程GET key ├─ 命中返回 Redis 数据 └─ 未命中 查询数据库 命中数据库后写回 Redis并设置 TTL 返回数据库结果示例命令GET user:1001:profile SET user:1001:profile serialized-profile EX 6007.1.2 写流程常见做法是“先更新数据库再删除缓存”更新 MySQL DEL user:1001:profile下一次读取未命中时会重新加载最新数据。相比直接SET新值删除缓存让后续读取以数据库为准也能减少并发写入覆盖新值的概率。即使如此数据库更新和缓存删除之间仍有短暂窗口缓存通常采用最终一致模型强一致要求不能只靠 TTL 和删除缓存自然获得。7.2 缓存穿透7.2.1 现象大量请求查询数据库中根本不存在的键缓存永远无法命中数据库不断承受无效查询。攻击者刻意查询不存在的用户 ID 时尤其明显。7.2.2 常用处理对“不存在”的结果写入短 TTL 的空值标记。使用布隆过滤器提前判断对象是否可能存在。对接口做参数合法性校验和限流。对明显异常的高频查询进行风控。缓存空值可以快速实现但需要短过期时间避免真实数据后来创建后仍然被错误判为不存在。7.3 缓存击穿7.3.1 现象一个热点键过期或暂时失效大量并发请求同时发现未命中再一起查询数据库。问题核心是“热点数据 同时重建”。7.3.2 常用处理使用互斥锁只让一个请求重建缓存其余请求等待或返回旧值。热点数据不设固定短 TTL或使用逻辑过期由后台异步刷新。配合请求合并和限流降低数据库瞬时压力。7.4 缓存雪崩7.4.1 现象大量键在同一时间过期或者 Redis 整体不可用导致请求同时涌向数据库。7.4.2 常用处理给 TTL 增加随机抖动避免批量同时过期。使用高可用部署和合理的内存容量。对数据库查询做限流、降级和熔断。对关键数据准备多级缓存并确保故障恢复后不会瞬间全量回源。7.5 缓存一致性缓存一致性的目标不是简单让两个存储永远同时变化而是根据业务明确可接受的新旧程度和延迟一般展示类数据允许短时间最终一致。金额、库存等关键数据需要明确事务边界和补偿机制。缓存只负责加速不应成为唯一事实来源。通过版本号、消息队列或数据库日志同步时必须处理消息重复、乱序和失败重试。只给缓存设置 TTL 并不能自动解决所有一致性问题它只是限制了不一致状态最长可能持续多久。8. 分布式锁、会话与消息通信8.1 用SET NX EX实现基本锁SET lock:order:100 owner-a NX EX 10含义是NX键不存在时才设置。EX 10锁 10 秒后自动过期。值owner-a标识锁的持有者。释放时执行前文的比较后删除 Lua 脚本不能只执行普通DEL。还需要考虑业务执行时间可能超过锁租期。服务暂停、主从切换和网络延迟可能导致锁状态变化。短租期降低故障后长期死锁风险但增加业务未完成就失锁的概率。对严格互斥要求应评估 Redlock 的争议、部署拓扑和业务补偿机制而不是把SET NX EX当成万能事务。8.2 会话存储登录成功后可以把会话信息写入 RedisHSET session:abc userId 1001 role user EXPIRE session:abc 1800后续请求携带令牌或会话 ID服务端从 Redis 取出对应用户信息。相比把状态全部放在单机内存集中式 Redis 更容易支持多台应用服务器。需要注意清空 Redis 可能让所有用户退出登录。会话键应设置明确的过期时间。敏感信息应加密或只保存最小必要字段。Redis 故障时应用需要有降级、重新登录或短期本地校验策略。8.3 Pub/Sub 与 Stream 的区别8.3.1 Pub/Sub发布者向频道发送消息在线订阅者立即收到SUBSCRIBE notice:system PUBLISH notice:system deploy startedPub/Sub 的优点是实时、命令简单缺点是默认不保存历史订阅者离线期间的发布消息会错过也没有消费组确认语义。8.3.2 StreamStream 把消息追加保存可以有多个消费组、多个消费者和待确认列表适合订单事件、异步任务和需要重试的轻量消息流。Stream 仍需要设计消息保留长度、消费失败重试、死信处理和幂等。它不是完整的 Kafka 替代品选型应看吞吐、保留策略、有序性和运维能力。9. 简单实战与排错9.1 一组可直接练习的命令9.1.1 保存用户资料与过期会话HSET user:1001 name Alice age 20 city Harbin HGETALL user:1001 EXPIRE user:1001 3600 TTL user:10019.1.2 计数器SET article:100:views 0 INCRBY article:100:views 10 GET article:100:views9.1.3 排行榜ZADD rank:game 80 alice 95 bob 70 carol ZREVRANGE rank:game 0 2 WITHSCORES ZINCRBY rank:game 10 alice ZREVRANK rank:game alice9.1.4 标签集合SADD article:100:tags mysql redis database SADD article:101:tags redis cache SINTER article:100:tags article:101:tags9.2 查看运行状态INFO server INFO memory INFO persistence INFO stats CONFIG GET maxmemory CONFIG GET maxmemory-policy SLOWLOG GET 10常见观察指标包括used_memoryRedis 当前分配和使用的内存。used_memory_human便于阅读的内存大小。maxmemory配置的内存上限。evicted_keys因淘汰被删除的键数量。keyspace_hits/keyspace_misses缓存命中与未命中。connected_clients当前客户端连接数。rdb_last_bgsave_status、aof_last_write_status持久化状态。slowlog执行时间超过阈值的命令。排错时不要只看“Redis 是否 PING 得通”还要检查内存是否达到上限、是否存在大键、是否发生淘汰、持久化是否失败和网络是否出现超时。9.3 常见错误清单9.3.1 用KEYS *排查线上数据键数量很大时会阻塞服务。使用SCAN并控制返回数量。9.3.2 只设置键不设置过期时间缓存、验证码、会话和临时锁如果没有 TTL长期运行后会不断堆积最终触发内存压力或误删关键键。9.3.3 把 Redis 当成完全不会丢数据的主数据库Redis 可以持久化但 RDB 快照周期、AOFeverysec、节点故障和主从切换都可能产生数据窗口。关键数据必须有数据库、日志和恢复策略。9.3.4 锁释放不校验持有者业务执行超时后锁可能已被其他客户端获得直接DEL会误删新锁。释放锁必须比较持有者标识并通过原子脚本删除。9.3.5 把 Pub/Sub 当作可靠队列离线期间的 Pub/Sub 消息默认会丢失也不支持消费确认。可靠消息场景应评估 Stream 或专用消息系统。9.3.6 所有对象都序列化成一个巨大 JSON如果业务只修改一个字段却反复读取和写回整个大对象会产生不必要的网络和 CPU 开销。应根据访问模式选择 Hash 或拆分键。10. 本课总结与复习10.1 一张图串起 Redis客户端 ↓ RESP 命令 Redis 服务端 ↓ 内存中的键值数据结构 ├─ String / Hash / List / Set / ZSet ├─ Bitmap / HyperLogLog / GEO / Stream ├─ TTL 与内存淘汰 └─ RDB / AOF 持久化 ↓ 缓存、会话、计数、排行、锁、消息通信10.2 自测题10.2.1 Redis 为什么不能简单理解为“内存中的 MySQL”因为 Redis 的核心模型是键值和多种数据结构常用命令围绕键定位与结构操作展开MySQL 的核心是关系表、约束、复杂查询和事务。两者可以配合但不能直接画等号。10.2.2 什么场景应选择 Hash而不是 String对象字段数量有限、需要频繁读取或修改部分字段时Hash 可以避免反复读取、序列化和写回整个对象。10.2.3TTL返回-1和-2分别表示什么对已存在的键-1表示没有设置过期时间-2表示键不存在。10.2.4 为什么缓存写入通常采用“更新数据库后删除缓存”删除缓存后后续读取会从数据库重新加载减少并发写时直接把旧值写回缓存的风险。但数据库更新与缓存删除之间仍有短暂不一致窗口。10.2.5 Redis 事务会像 MySQL 一样在部分命令失败时完整回滚吗通常不会。Redis 事务保证命令连续执行但运行期错误不会自动撤销已经成功执行的命令因此不能把它当成完整的关系型事务。10.2.6 为什么不能把 Pub/Sub 当作可靠消息队列Pub/Sub 默认不保存离线期间的消息也没有消费组确认与重试机制。需要可靠消费时应评估 Stream 或专用消息中间件。#Redis #数据库 #缓存 #键值数据库 #数据结构 #持久化

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑