Redis知识整理一

一、Redis为什么快

Redis 之所以极快,核心是纯内存操作 + 高效 IO 模型 + 极简高效的数据结构与指令,主要有这几点:

  • **完全基于内存操作。**数据直接存在内存,避免了磁盘I/O瓶颈。
  • 单线程设计。线程处理所有网络 IO 和命令执行,无锁竞争、无线程切换损耗 。Redis 6.0+ 只是网络 IO 多线程,命令执行依然单线程
  • IO 多路复用。 使用 epoll/kqueue/select 等机制,单线程同时监听大量连接
  • 高效数据结构**。**底层使用 SDS、压缩列表、跳表、哈希表等优化结构。大部分命令都是 O (1) 或 O (logN) 时间复杂度。简单指令(如 GET/SET)几乎一步到位。
  • 协议简单、序列化开销极低

注意:Redis 单线程指网络 IO + 命令执行,持久化、异步删除是后台线程。

二、5种基本数据结构

1. String(字符串)

  • 最简单的 key-value 结构
  • 可存:字符串、数字、二进制
  • 常用命令:SETGETINCRDECR
  • 使用场景:缓存、计数器、分布式锁

2. Hash(哈希)

  • 类似 Java 的 HashMap,一个 key 对应多个 field-value
  • 结构:key → {field1:value1, field2:value2...}
  • 常用命令:HSETHGETHMGETHGETALL
  • 使用场景:存储对象(用户信息、商品详情)

3. List(列表)

  • 有序可重复的字符串链表
  • 支持两头操作:LPUSHRPUSHLPOPRPOP
  • 可做简单队列、栈
  • 使用场景:消息队列、时间线、最新列表

4. Set(集合)

  • 无序、不可重复的字符串集合
  • 支持交集、并集、差集
  • 常用命令:SADDSREMSMEMBERSSINTER
  • 场景场景:去重、共同好友、抽奖、点赞

5. ZSet(有序集合)

  • 每个元素带 score(分数),按 score 排序
  • 元素唯一,score 可重复
  • 底层用跳表实现,查询高效
  • 常用:ZADDZRANGEZSCOREZRANK
  • 场景:排行榜、热度排序、延时队列

三、5种高级数据结构

1. HyperLogLog(基数统计)

  • 作用:做海量数据的去重计数(UV(Unique Visitor)独立访客、日活)
  • 特点:
    • 占用内存极小
    • 有微小误差(约 0.81%)
    • 不保存具体数据,只计数
  • 常用命令:PFADDPFCOUNTPFMERGE
  • 使用场景:统计网站 UV、独立访客数

2. Bitmap(位图)

  • 本质:String 类型的位操作扩展
  • 特点:
    • 极省空间,1 个 key 可存 512M 位
    • 按 bit 位 0/1 表示状态
  • 常用命令:SETBITGETBITBITCOUNTBITOP
  • 使用场景:用户签到、在线状态、活跃统计、布隆过滤器基础
  • 使用位图统计的原理:Bitmap 利用 String 二进制位存储状态 ,1bit 代表一个用户 / 事件,通过 BITCOUNT、BITOP 实现高效统计,内存占用极低、速度极快
  • Bitmap VS HyperLogLog
维度 Bitmap HyperLogLog
精准度 100% 精准 不精准,标准误差 ≈0.81%
内存占用 用户 ID 最大值 相关1 亿用户 ≈ 12MB 固定 12KB 左右无论多少数据都不变
能否查单个用户 可以:判断某个用户是否存在 不可以,只存统计信息
能否做交并差 支持:BITOP 做多天活跃、留存 不支持,只能合并计数
底层结构 String 二进制位 概率算法 + 字节数组
统计上限 理论 2^32,受 String 512MB 限制 2^64,几乎无上限
适用场景 精准签到、留存、在线状态 海量 UV、日活、访客统计

总结:

  • Bitmap:精准、占空间、支持位运算、适合签到留存。
  • HyperLogLog:不精准、超省内存、只计数、适合海量 UV。
  • 一句话:要精准用 Bitmap,要省空间用 HLL。

3. Geospatial(GEO 地理位置)

  • 作用:存储经纬度,计算距离、附近的人
  • 底层:ZSet 封装
  • 常用命令:GEOADDGEORADIUSGEODIST
  • 使用场景:附近的人、外卖配送距离、滴滴打车

4. Stream(消息流)

  • 作用:持久化消息队列,支持多消费者、消费组
  • 特点:
    • 真正意义上的 MQ 结构
    • 支持回溯、ACK、堆积
  • 常用命令:XADDXREADXGROUPXACK
  • 使用场景:异步任务、日志采集、高可靠消息

5. Bloom Filter(布隆过滤器)

  • 作用:快速判断一个元素是否存在,防缓存穿透
  • 原理:用多个哈希函数算出多个位置,全部置 1;判断时只要有一个是 0,就一定不存在;全是 1,可能存在
  • 特点:
    • 空间极省、速度极快
    • 有一定误判率:存在可能不存在,不存在一定不存在
  • 常用命令:Redis 官方无内置命令,一般通过 Redisson / 自定义模块 实现
  • 业务场景:防止缓存穿透(查询不存在的 key 不打数据库)、爬虫去重、黑名单过滤

四、过期策略

1. 惰性删除(Lazy Expiration)

  • 用到 key 时才检查是否过期
  • 过期就删,返回不存在
  • 优点:省 CPU
  • 缺点:占内存,过期 key 不用就一直占着

2. 定期删除(Periodic Expiration)

  • 后台定时随机抽查一批 key
  • 发现过期就删除
  • 控制频率和数量,避免卡顿
  • 平衡 CPU 和内存

五、淘汰策略

配置项:maxmemory-policy

1. 不淘汰(默认)

  • noeviction
  • 内存满了,新写入直接报错

2. 只针对设置了过期时间的 key

  • volatile-lru: 淘汰最近最少使用的过期 key(最常用)
  • volatile-lfu: 淘汰使用频率最少的过期 key
  • **volatile-random:**随机淘汰过期 key
  • volatile-ttl: 淘汰即将过期的 key(TTL 越小越先删)

3. 针对所有 key

  • **allkeys-lru:**所有 key 里,淘汰最近最少使用(非常常用)
  • **allkeys-lfu:**所有 key 里,淘汰使用频率最少
  • **allkeys-random:**随机淘汰

注:LRU vs LFU 区别

  • LRU:看最后一次使用时间
  • LFU:看使用次数,更适合热点数据

六、数据与缓存一致性

Redis 是缓存,不是数据库,无法做到强一致 。所有方案目标都是:业务可接受的最终一致性,尽量减少不一致时间窗口。

1. 先更新数据库,再删除缓存(标准方案)

流程:

(1) 更新 DB

(2) 删除 Redis 缓存

(3) 下次查询时,自动从 DB 加载并回种缓存

为什么是删除,不是更新?

  • 更新缓存浪费性能(可能根本没人读)
  • 高并发下更容易不一致
  • 懒加载更安全、更简单

为什么不推荐:先删缓存,再更新 DB?

容易出现脏数据:

① 线程 A 删缓存

② 线程 B 查询,缓存未命中,读旧 DB

③ 线程 A 更新 DB

④ 线程 B 把旧数据写回缓存→ 缓存脏数据,一直不一致

所以禁止使用

高并发下,"先更 DB 再删缓存" 也会短暂不一致

场景:

① 线程 A 查询,缓存未命中,读 DB 旧值

② 线程 B 更新 DB,删除缓存

③ 线程 A 把旧值写入缓存→ 短暂不一致,但只会发生一次,下一次就正常

这种情况:

  • 概率极低
  • 时间窗口极短
  • 属于最终一致性,业务可接受

2. 延迟双删(解决上面问题)

步骤:

① 删缓存

② 更新 DB

③ 延迟几百 ms(等并发读完成)

④ 再删一次缓存

优点:

  • 极大降低不一致概率缺点:
  • 引入延迟,耦合业务

3. 最可靠方案:异步更新缓存(订阅 binlog)

也就是 Canal + RabbitMQ/Kafka 机制:

① 业务只操作 DB

② Canal 监听 MySQL binlog

③ 解析后异步删除 / 更新 Redis

④ 保证顺序执行,最终一致

优点:

  • 与业务解耦
  • 一致性极高
  • 高并发下最稳定

企业通用方案:缓存最终一致 + 兜底熔断

七、缓存3大问题

缓存最大、最核心的问题,是缓存与数据库的数据不一致 ,以及由此引发的缓存穿透、击穿、雪崩三大高可用问题**。**

1. 缓存穿透

  • 现象:查根本不存在的数据
  • 原因:查不存在的数据,请求直达数据库。数据库压力巨大,容易被打崩
  • 解决:缓存空值、**布隆过滤器、**接口层参数校验

2. 缓存击穿

  • 现象:某个热点 Key 过期
  • 原因:热点 key 过期,高并发下大量请求同时穿透到数据库
  • 解决:互斥锁(redlock/setnx)、热点 key 永不过期、后台定时刷新

3. 缓存雪崩

  • 现象:大量 Key 同时过期 / Redis 节点宕机
  • 原因:全部流量压到数据库,直接宕库
  • 解决:
    • 过期时间加随机值
    • 集群高可用
    • 多级缓存
    • 服务降级、熔断限流
相关推荐
21439652 小时前
SQL注入防御技术方案_基于正则表达式的输入清洗
jvm·数据库·python
2401_832365522 小时前
SQL窗口函数与递归查询的区别_如何根据场景选择
jvm·数据库·python
u0109147602 小时前
c++如何处理文件路径中由于不规范的连续斜杠导致的路径解析错误【避坑】
jvm·数据库·python
2301_796588502 小时前
PHP源码开发用二手硬件划算吗_性价比与稳定性权衡【操作】
jvm·数据库·python
2301_775148152 小时前
如何通过C#读取Oracle数据库中的图片显示到WinForm_BLOB转Byte[]与流处理
jvm·数据库·python
ERBU DISH2 小时前
修改表字段属性,SQL总结
java·数据库·sql
treesforest2 小时前
IP 反欺诈查询怎么落地更稳?Ipdatacloud 适用场景与实战决策闭环
网络·数据库·网络协议·tcp/ip·网络安全
weixin_568996062 小时前
mysql如何配置大页内存_mysql large-pages开启方法
jvm·数据库·python
HHHHH1010HHHHH2 小时前
HTML怎么创建评论区域_HTML嵌套评论语义结构【详解】
jvm·数据库·python