Redis入门到实战教程,深度透析redis
一、基础篇--redis基础知识入门
SQL和NoSQL数据库的对比
方面 | SQL数据库 | NoSQL数据库 |
---|---|---|
数据模型 | 关系型数据模型,基于表(行和列)组织数据 | 非关系型,多样化数据模型(文档、键值、列族、图等) |
结构 | 结构化数据,严格的模式(schema),表结构固定 | 灵活模式或无模式(schema-less),支持半结构化和非结构化数据 |
查询语言 | 使用结构化查询语言SQL,支持复杂的多表联结查询 | 各有不同查询方式,不一定支持SQL,灵活性高但复杂查询较弱 |
事务支持 | 完整支持ACID事务,保证数据一致性和完整性 | 事务支持有限,通常强调最终一致性,更适合高并发和分布式环境 |
扩展方式 | 垂直扩展(升级硬件如CPU、内存)为主 | 水平扩展(增加更多节点)为主,更易扩展到大规模分布式系统 |
性能 | 适合复杂查询和事务,单机性能强 | 适合海量数据和高并发访问,读写速度快,灵活性高 |
典型应用 | 银行、财务、ERP系统等需要强一致性的业务系统 | 大数据分析、社交网络、内容管理、缓存系统等 |
代表数据库 | MySQL、PostgreSQL、Oracle、SQL Server | MongoDB(文档)、Redis(键值)、Cassandra(列族)、Neo4j(图) |
什么是redis缓存?
Redis缓存是指利用Redis这个高性能的内存数据库来做数据缓存的技术。
简单来说,缓存就是把频繁访问的数据临时存放在一个速度非常快的存储区域里(这里就是Redis的内存),这样当系统需要这些数据时,可以直接从缓存里读,速度比从传统数据库或者磁盘读快很多,从而提升系统响应速度和吞吐量。
具体来说,Redis缓存的特点包括:
基于内存:Redis把数据存放在内存中,读写非常快,适合做缓存。
支持多种数据结构:除了简单的键值对,还支持字符串、哈希、列表、集合、有序集合等,方便存储各种复杂数据。
持久化机制:虽然是内存数据库,但Redis支持持久化到磁盘,防止数据丢失。
支持过期时间:可以给缓存设置过期时间,数据过期后自动删除,避免缓存雪崩和过期脏数据问题。
应用场景:常用于存储热点数据、用户会话、计数器、排行榜、限流等场景。
redis的通用命令
redis的常见数据类型
添加redis缓存?
缓存更新一致性
更新流程:数据库和 Redis 都需要更新,但操作顺序与方式会影响一致性
例如,两个线程并发同时操作数据:
T1 先删除缓存,准备更新数据库
T2 查询缓存未命中 → 查询数据库(此时数据库还未更新) → 回写旧数据到缓存
T1 再更新数据库 → 数据库新了,但缓存是旧的
先删缓存后更新数据库:
正常情况vs异常情况
VS
先更新数据库后删缓存:
正常情况vs异常情况
VS
延迟双删策略
为避免并发写入旧数据:
更新数据库 删除缓存 延迟一段时间(如500ms~1s)再次删除缓存
原因:第二次删除可以覆盖 更新数据库前其他线程写入的旧缓存。
缺点:延迟时间要根据业务耗时调优。
缓存穿透及解决思路

缓存穿透的原因
非法参数或恶意攻击
用户或攻击者不断请求不存在的 key。
缓存策略不完善
对不存在的数据没有缓存逻辑,每次请求都查数据库。
缓存穿透的解决方法
布隆过滤器(Bloom Filter)
在缓存之前加一层布隆过滤器,判断 key 是否可能存在。
特点:
如果布隆过滤器返回不存在,直接拒绝请求,不访问数据库。
可能出现误判(说存在其实不存在),但不会漏掉真实存在的数据。
流程示意:
请求到来 → 先查布隆过滤器 → 不存在 → 拒绝/返回空 → 不查数据库 可能存在 → 查询缓存 → 缓存未命中 → 查询数据库 → 更新缓存
布隆过滤器的作用及原理
- 布隆过滤器主要用于判断某个元素是否 可能存在 于一个集合中,这里的“集合”可以是缓存里存的 key 或者数据库里存在的数据 key。
- 如果布隆过滤器返回“不存在” → 这个元素肯定不在集合中,可以直接拦截请求,不访问缓存或数据库。
- 如果布隆过滤器返回“存在” → 这个元素可能存在(存在误判概率),还需要继续去缓存或数据库验证。
也就是说,布隆过滤器只做 快速预判,防止大量无效请求打到数据库,它不能保证“肯定存在”。
布隆过滤器判断元素是否存在,是通过**哈希函数和位数组(Bit Array)**来实现的,不会像普通集合那样逐个比对,而是用一种“压缩且允许误判”的方式。下面详细讲原理:
1. 核心结构
位数组(Bit Array)
假设长度为
m
的数组,每个元素初始化为 0。
多组哈希函数
一般使用
k
个不同的哈希函数,每个函数把输入 key 映射到[0, m-1]
之间的一个位置。
2. 添加元素
把某个 key 添加到布隆过滤器:
用
k
个哈希函数分别计算 key 的哈希值对应位数组的位置置为 1
示意:
key = "user123"
哈希函数 h1 → 位置 5 → 置为 1
哈希函数 h2 → 位置 12 → 置为 1
哈希函数 h3 → 位置 27 → 置为 1
多个 key 可以共享位数组的位置(可能会重叠)。
3. 查询元素
查询某个 key 是否存在:
用相同的
k
个哈希函数计算 key 的哈希值检查位数组对应位置是否都为 1
如果有任何一位是 0 → key 一定不存在
如果所有位都是 1 → key 可能存在(有误判概率)
示意:
查询 key = "user456"
h1 → 位置 5 (是1)
h2 → 位置 12 (是1)
h3 → 位置 27 (是1) → 所有为1 → 可能存在
缓存空对象
对数据库中不存在的 key,缓存一个空对象或特殊标记(如 null、空字符串)并设置短 TTL。
下次请求命中缓存,不再访问数据库。
接口参数校验
对用户请求参数做严格校验,防止非法 key 请求打到数据库。
限流/熔断
对短时间内大量请求同一个不存在 key 做限流,保护数据库。
缓存雪崩及解决思路
缓存雪崩指的是缓存系统在短时间内大面积失效或不可用,导致大量请求直接打到后端数据库或服务上,从而可能引起数据库压力过大甚至宕机的现象。(如果大量缓存的 TTL 相同,到期时间集中,就可能触发 缓存雪崩)
常见解决方案
缓存过期时间加随机值
给每个缓存加上随机的 TTL(Time To Live),避免同一时间大量缓存同时失效。
例:原 TTL = 1 小时 → TTL = 1 小时 + 随机 0~10 分钟。
使用互斥锁/分布式锁防止缓存击穿
当缓存失效时,只有一个请求去访问数据库并更新缓存,其他请求等待。
Redis 可用
SETNX
或 Redisson 实现分布式锁。
缓存预热
系统启动或高峰期前提前加载热点数据到缓存。
避免冷启动导致数据库瞬时压力过大。
多级缓存或降级处理
一级缓存:本地缓存
二级缓存:Redis
缓存失效时可返回上次数据或默认值,降低数据库压力。
使用限流/熔断
高并发时对请求进行限流,保护数据库不被压垮。
可以结合 Hystrix、Sentinel 等。
缓存击穿及解决思路
缓存击穿指的是某个热点数据在缓存中失效的瞬间,有大量请求同时访问这个数据,全部穿透到数据库的情况。
特点:
仅发生在热点数据上(比如高并发访问的秒杀商品、热门文章等)。
数据本身存在于数据库中,但缓存失效导致大量请求直接打到数据库。
与缓存雪崩的区别:雪崩是大面积缓存失效;击穿通常是单个热点 key 失效。
缓存击穿的原因
热点数据过期
高并发访问的 key TTL 到期,缓存失效,瞬间大量请求穿透。
数据库查询慢
当缓存失效,数据库查询耗时长,排队请求不断堆积。
缓存击穿的解决方法
互斥锁(分布式锁)
当缓存失效时,只有一个请求去查询数据库并更新缓存,其他请求等待。
Redis 可用
SETNX
或 Redisson 实现锁机制。流程示意:
请求到来 → 缓存未命中 → 获取锁 → 查询数据库 → 更新缓存 → 释放锁 → 获取锁失败 → 等待/轮询 → 读取缓存
热点数据永不过期或长期缓存
对高并发热点数据,TTL 设置很长或者不设置,让缓存始终存在。
定期异步更新数据(定时刷新)而不是依赖自然过期。
提前预热缓存(Cache Preload)
系统启动或高峰前,把热点数据加载到缓存中。
避免冷启动或缓存过期瞬间击穿。
使用逻辑过期
缓存不直接删除,而是加一个逻辑过期时间(仍返回旧数据),后台异步刷新。
优点:高并发下数据库压力被分散,不会瞬间被打爆。
请求排队/限流
对热点 key 做请求排队或者限流,保护数据库。
可以结合信号量、队列或者 Hystrix/Sentinel 等熔断机制。
分布式锁的基本原理与实现方式
基本原理
在分布式系统中,多个节点可能会同时访问和修改同一份数据(比如多个服务同时更新库存),为了避免数据不一致,需要加锁。
分布式锁的目标是:
互斥性:同一时间只有一个客户端能获得锁。
可重入性(可选):同一个客户端多次获取同一把锁不被阻塞。
防死锁:锁必须有超时机制,避免因节点宕机而无法释放。
高可用性:锁服务本身要可靠,不因单点故障影响业务。
常见实现方式对比(MySQL、Redis、ZooKeeper)
1)基于 Redis
原理:
使用
SET key value NX PX expireTime
(Redis 里一个常用的原子加锁命令格式,仅在 key 不存在时设置,并带过期时间)来加锁。value 通常设置为唯一 ID(如 UUID)标识客户端,以便解锁时验证是自己加的锁。(以此来解决redis分布式锁互删的问题)
解锁时用 Lua 脚本保证“判断 + 删除”是原子操作。(可以一次性执行多条命令,原子操作指的是 不可被中断、不可分割的操作。一旦开始执行,它要么执行完成,要么完全不执行,中途不会被其他线程或进程打断。也是解决redis分布式锁互删的问题)
优点:性能高,简单易实现。
缺点:需要注意 Redis 主从复制延迟带来的锁不一致问题(可用 Redlock 算法优化)。
2)基于 Zookeeper
原理:
利用 Zookeeper 的临时顺序节点特性:
客户端在指定目录下创建临时顺序节点。
判断自己是不是所有子节点中序号最小的,如果是,则获得锁。
不是则监听前一个节点的删除事件,收到通知后重试。
优点:强一致性,适合需要严格顺序和可靠性的场景。
缺点:性能不如 Redis,高并发时节点创建/删除成本较高。
3)基于Mysql数据库
原理:
利用数据库的唯一索引或行锁实现:
通过
INSERT
一条唯一键记录实现加锁,失败说明锁已被占用。或
SELECT ... FOR UPDATE
行锁来阻塞其他事务。
优点:实现简单,不需要额外引入组件。
缺点:性能低,容易造成数据库压力。
阻塞队列(Blocking Queue) 是一种线程安全的队列,它在获取或插入元素时,如果条件不满足,会阻塞当前线程,直到条件满足为止。
线程池 是一种预先创建好多个线程并重复利用的技术,用来执行大量短时间任务,避免频繁创建和销毁线程的开销。
Redis 消息队列
Redis 消息队列是利用 Redis 的数据结构和特性实现的消息传递机制,用来在不同服务或线程之间异步通信,常用于解耦、削峰、异步处理等场景。
1. 为什么用 Redis 做消息队列?
Redis 是内存型数据库,读写非常快(毫秒/微秒级)。
提供了多种数据结构(List、Stream、Pub/Sub)适合做队列。
支持阻塞等待、持久化、防止消息丢失(可配合 ack 机制)。
2. 常见实现方式
① 基于 List(阻塞队列模式)
使用
LPUSH
/RPUSH
生产消息使用
BLPOP
/BRPOP
消费消息(阻塞式)优点:简单,支持阻塞,实时性好
缺点:不支持多消费者间消息确认(消费一次就没了)
② 基于 Pub/Sub(发布订阅模式)
使用
PUBLISH
发布消息使用
SUBSCRIBE
订阅频道优点:实时推送,多订阅者可同时收到消息
缺点:无持久化,订阅者离线就收不到消息
③ 基于 Stream(消息队列增强版)
Redis 5.0 引入,类似 Kafka
支持消息持久化、消费者组、确认机制(ack)
适合多消费者、消息追溯场景
3. 使用场景
异步任务处理
用户下单 → 先写 Redis 队列 → 后台异步扣库存、发货削峰填谷
高峰期先把请求放到 Redis 队列,后台慢慢处理服务解耦
生产者和消费者不直接通信,减少耦合
二、Redis分布式缓存
Redis持久化
1,RDB持久化
2,AOF持久化
3,总结对比
Redis主从集群
定义:
主从复制是指将一个Redis节点(主节点,Master)的数据实时同步到多个从节点(Slave),形成“一主多从”的架构,实现数据冗余备份和读写分离。
1,核心作用
- 数据备份:从节点复制主节点数据,避免单点数据丢失风险。
- 读写分离:主节点负责写操作,从节点负责读操作,分担主节点读压力(主从默认只读,可配置为可写但不推荐,易被主节点同步覆盖)。
- 故障恢复基础:主节点故障时,从节点可升级为新主节点(需手动或哨兵自动操作)。
2,工作流程
- 全量同步(首次连接或断开重连后数据差异过大):
- 从节点向主节点发送
SYNC
命令请求同步。 - 主节点执行
bgsave
生成RDB快照文件,并缓存期间的写命令。 - 主节点发送RDB文件给从节点,从节点载入RDB恢复数据。
- 主节点将缓存的写命令发送给从节点,从节点执行后完成数据对齐。
- 从节点向主节点发送
- 增量同步(主从正常连接时):
- 主节点每执行一次写命令,会异步将命令发送到从节点,从节点实时执行,保持数据一致。
- Redis 2.8+优化:主从断开重连后,通过偏移量(offset)和复制积压缓冲区(repl_backlog)实现增量同步,仅传输断线期间的命令,减少带宽消耗。
Redis哨兵集群
Redis分片集群
散列插槽、集群伸缩、故障转移..............后面有空在学
三、多级缓存(亿级流量的缓存)
多级缓存是一种在系统架构的多个层级部署缓存的策略,通过在数据流转路径上设置多层缓存节点,减少对底层数据库或服务的直接访问,从而显著提升系统性能、降低延迟并提高并发处理能力。其核心思想是**“数据离用户越近,访问速度越快”**,常见于高并发场景(如电商秒杀、社交平台、行情系统等)。
1,多级缓存的典型层级
根据数据流转路径,多级缓存通常包含以下层级(从用户端到服务端依次递进):
1. 浏览器或者app客户端缓存
- 位置:用户设备本地(如浏览器、移动端App)。
- 作用:存储静态资源(图片、CSS、JS)或频繁访问的API响应数据,减少对服务端的请求次数。
- 实现方式:
- 浏览器通过
Cache-Control
、Expires
等HTTP头缓存静态资源; - App通过本地数据库(如SQLite)或内存缓存(如HashMap)存储用户配置、商品列表等。
- 浏览器通过
- 特点:访问速度最快(毫秒级),但存储容量有限,且数据一致性难保证(需通过过期时间或主动刷新更新)。
2. 接入层缓存(Nginx本地缓存)
- 位置:反向代理服务器(如Nginx)本地内存或磁盘。
- 作用:缓存热点动态数据(如商品详情、用户会话),直接在接入层响应请求,避免请求穿透到后端服务。
- 实现方式:
- Nginx通过
proxy_cache
缓存后端响应; - 结合OpenResty+Lua脚本实现复杂业务逻辑(如查询Redis未命中后缓存结果)。
- Nginx通过
- 特点:高并发支持(单机Nginx可抗10万+ QPS),减少后端Tomcat/应用服务器压力。
3. Redis分布式缓存
- 位置:独立的分布式缓存集群(如Redis)。
- 作用:存储全量热点数据(如用户购物车、商品库存、会话信息),支持集群共享和横向扩展。
- 实现方式:
- Redis通过主从复制+哨兵保证高可用,通过Cluster实现数据分片;
- 结合一致性哈希算法分配缓存节点,避免单点故障和数据倾斜。
- 特点:容量大(支持TB级)、可靠性高,适合跨服务共享数据,但存在网络访问开销(微秒级延迟)。
4. 应用层缓存(进程缓存)
- 位置:应用服务器进程内(如JVM进程缓存、Go进程缓存)。
- 作用:缓存高频访问的小量数据(如配置信息、权限列表、热点商品),避免分布式缓存的网络开销。
- 实现方式:
- Java使用Caffeine、Guava Cache;
- Go使用sync.Map或第三方库(如groupcache)。
- 特点:访问速度极快(纳秒级),无网络开销,但存储容量受限于单机内存,且集群环境下数据一致性难保证(需通过广播或事件通知同步)。
5. 数据库缓存
位置:数据库内置缓存(如MySQL InnoDB Buffer Pool)或ORM框架缓存(如MyBatis一级缓存)。
作用:缓存查询频繁的SQL结果或行数据,减少磁盘IO。
特点:数据库层最后一道缓存,依赖数据库自身优化,通常不单独作为多级缓存的核心层级。
2、多级缓存的工作流程
请求从客户端到服务端,按以下顺序查询缓存,命中则直接返回,未命中则向下一级请求,最终查询数据库后逐级回写缓存:
用户请求 → 客户端缓存 →Nginx本地缓存 → 分布式缓存(Redis) → 应用层缓存(JVM进程) → 数据库
3,redis缓存预热
4,缓存同步策略
redis原理篇以后有时间在学......................
四、Redis经典面试题
1,本地缓存?
2,redis为什么块?
答:Redis之所以性能出色核心源于其内存存储、高效数据结构、单线程模型及I/O多路复用等设计优化。
1,Redis将所有数据存储在内存中,内存读写速度远高于磁盘I/O相比MySQL等磁盘数据库需频繁进行磁盘随机访问,Redis直接操作内存数据,省去了磁盘I/O的性能开销,这是其高性能的基础前提。
2,Redis内置多种经过优化的底层数据结构,针对不同场景选择最优编码,确保操作的时间复杂度接近O(1)
3,Redis采用单线程处理客户端请求避免了多线程切换的CPU上下文切换开销;通过I/O多路复用模型让单线程高效处理多个客户端连接实现高吞吐量
3,Redis 有哪些常用的数据结构?
上面有
4,Redis RDB 和 AOF 持久化的区别,如何选择?
Redis的RDB和AOF是两种核心持久化机制,用于将内存数据持久化到磁盘,保障服务重启后的数据恢复。二者在工作原理、优缺点和适用场景上有显著差异,具体区别及选择策略如下:
一、RDB与AOF的核心区别
维度 | RDB(Redis Database) | AOF(Append Only File) |
---|---|---|
工作原理 | 定时生成数据集的时间点快照(如每5分钟生成一次全量数据快照),以二进制压缩存储。 | 记录服务器执行的所有写操作命令(如SET、DEL),以Redis协议格式追加到日志文件末尾,重启时重放命令恢复数据。 |
数据完整性 | 可能丢失快照间隔内的数据(如5分钟快照,故障时丢失最后5分钟数据)。 | 支持三种同步策略: - always :每条命令同步刷盘,零数据丢失(性能差);- everysec :每秒同步,最多丢失1秒数据(默认,平衡性能与安全);- no :操作系统控制刷盘,可能丢失较多数据。 |
文件体积 | 二进制压缩存储,文件体积小(如1GB内存数据约生成100MB RDB文件)。 | 文本格式记录命令,文件体积大(相同数据约为RDB的2.5倍,随数据增长基本不变)。 |
恢复速度 | 直接加载快照文件,恢复速度快(大数据集场景下比AOF快2-3倍)。 | 需逐条重放命令,恢复速度慢(尤其文件较大时)。 |
性能影响 | 写操作不阻塞,仅在bgsave 时fork子进程(耗时,数据集大时可能阻塞主线程数百毫秒)。 | 写命令需追加到文件,everysec 策略下性能比RDB低25%-80%(大规模数据接近25%差距),读性能无差异。 |
文件可读性 | 二进制文件,不可直接阅读。 | 文本文件,可直接查看命令(如SET user:1001 "Alice" ),支持手动编辑修复(如删除误操作的FLUSHALL命令)。 |
重写机制 | 无内置重写,需手动触发save 或配置定时快照。 | 支持自动/手动重写(BGREWRITEAOF ),合并重复命令(如100次INCR合并为1次SET),减小文件体积。 |
二、如何选择持久化方案?
根据业务对数据安全性、性能和运维复杂度的需求,选择策略如下:
1. 仅用RDB:适合性能优先、可容忍数据丢失的场景
适用场景:
- 数据可丢失数分钟(如缓存热点数据,丢失后可从数据库重建);
- 追求极致写性能(如高并发写入场景,RDB避免AOF的追加开销);
- 需频繁备份或灾难恢复(RDB文件小,便于压缩传输)。
2. 仅用AOF:适合数据安全性要求高,但不推荐单独使用
- 适用场景:
- 数据不允许丢失(如金融交易记录,需
always
同步策略); - 需手动编辑修复数据(如误操作后删除AOF文件末尾命令)。
- 数据不允许丢失(如金融交易记录,需
3,大部分生产场景推荐同时使用
- 同时启用RDB和AOF,重启时优先加载AOF文件(数据更完整);
- RDB作为“兜底快照”,AOF补充实时命令,兼顾数据安全与恢复效率。
5,如何解决缓存击穿、缓存穿透、雪崩问题?
上面有
6,如何用 Redis 实现点赞功能,怎么设计 Key / Value?
使用 Redis 实现点赞功能时,需结合其 Set(集合)、Hash(哈希)和 Counter(计数器) 数据结构,设计高效的 Key/Value 存储方案。
根据点赞功能的核心需求,Redis 需存储三类数据:用户点赞状态、点赞数量、点赞内容索引,具体 Key 命名规范及 Value 结构如下:
1. 用户点赞状态(防止重复点赞)
数据结构:Set
(集合)
- Key:
like:{content_type}:{content_id}
content_type
:内容类型(如post
文章、comment
评论,避免不同类型内容 ID 冲突)。content_id
:内容唯一 ID(如文章 ID、评论 ID)。
- Value:存储点赞该内容的 用户 ID 集合(Set 天然去重,确保一个用户只能点赞一次)。
2. 点赞数量统计(计数器)
数据结构:String
(字符串,用于计数器)
- Key:
like_count:{content_type}:{content_id}
- Value:点赞数量(整数,通过
INCR
/DECR
原子操作更新)。
3. 用户点赞内容索引(用户中心“我的点赞”)
数据结构:Set
(集合)
- Key:
user_like:{user_id}:{content_type}
user_id
:用户唯一 ID。content_type
:内容类型(可选,如需区分点赞的是文章还是评论)。
- Value:存储用户点赞的 内容 ID 集合,用于快速查询用户的点赞历史。
4. 点赞时间排序(可选,如“最新点赞”)
数据结构:Sorted Set
(有序集合)
- Key:
like_sorted:{content_type}:{content_id}
- Value:
member
为用户 ID,score
为点赞时间戳(毫秒级),按时间戳排序。
7,其他
redis是NoSQL数据库的一种,一般是作为缓存数据库辅助持久化的数据库