Redis 详解:Redis 与 MySQL 的区别、数据类型与缓存三大问题

一、什么是 Redis?

Redis 是一个开源的、基于内存的 Key-Value 数据库 ,全称是 Remote Dictionary Server

与传统的 MySQL 不同,Redis 的数据主要存储在内存中,因此具有非常高的读写性能,常被用于:

  • 缓存

  • Session 存储

  • 排行榜

  • 计数器

  • 分布式锁

  • 消息队列

  • 热点数据存储

在实际项目中,Redis 通常不会完全替代 MySQL,而是和 MySQL 配合使用。

一个比较典型的架构是:

复制代码
          用户请求
              ↓
          后端服务器
              ↓
         ┌─────────┐
         │  Redis  │
         └─────────┘
           ↓     ↓
        命中     未命中
         ↓        ↓
      返回数据   MySQL
                  ↓
              查询数据
                  ↓
              写入 Redis
                  ↓
                返回

也就是说:

MySQL 负责持久化存储,Redis 负责高速缓存。


二、Redis 与 MySQL 的区别

Redis 和 MySQL 都可以存储数据,但是它们的设计目标完全不同。

2.1 存储方式不同

Redis 是基于内存进行数据存储的。

MySQL 主要是基于磁盘进行持久化存储。

例如:

复制代码
Redis
内存
 ↓
快速读取
 ↓
高性能

而 MySQL:

复制代码
MySQL
磁盘
 ↓
持久化存储
 ↓
数据可靠

Redis 虽然也提供 RDB、AOF 等持久化机制,但它的核心优势依然是内存中的高速访问。


2.2 数据结构不同

MySQL 是典型的关系型数据库。

数据通常以:

复制代码
数据库
 ↓
表
 ↓
行
 ↓
字段

的形式组织。

例如:

复制代码
user

id    name    age
1     张三     20
2     李四     22

Redis 则是 Key-Value 模型:

复制代码
key                value

user:1001          张三
user:1002          李四

并且 Redis 的 Value 并不只是简单的字符串,还可以是:

  • String

  • List

  • Set

  • Hash

  • Sorted Set

等多种数据结构。


2.3 性能不同

Redis 数据主要在内存中操作,因此读写速度非常快。

MySQL 查询通常涉及:

复制代码
应用程序
   ↓
MySQL
   ↓
磁盘 / Buffer Pool
   ↓
查询

而 Redis:

复制代码
应用程序
   ↓
Redis
   ↓
内存

因此对于大量频繁读取的数据,Redis 通常比 MySQL 更适合作为缓存。


2.4 使用场景不同

MySQL 更适合:

  • 用户信息

  • 商品信息

  • 订单

  • 支付记录

  • 交易数据

  • 财务数据

  • 需要长期保存的数据

Redis 更适合:

  • 热点数据

  • 登录 Session

  • 验证码

  • 排行榜

  • 计数器

  • 分布式锁

  • 高频访问数据

例如电商网站:

复制代码
商品详细信息
      ↓
     MySQL
      ↓
持久化保存

热门商品
      ↓
     Redis
      ↓
快速访问

2.5 Redis 和 MySQL 对比

对比项 Redis MySQL
类型 Key-Value 数据库 关系型数据库
主要存储 内存 磁盘
查询速度 非常快 相对较慢
数据结构 丰富 表结构
持久化 支持 支持
事务能力 相对简单
数据可靠性 相对较弱 较强
主要用途 缓存、高性能读写 核心业务数据
数据量 受内存限制 通常更大
典型场景 缓存、排行榜、Session 用户、订单、商品

所以面试中可以总结为:

MySQL 更擅长数据的持久化和复杂查询,Redis 更擅长高性能的数据读写和缓存。实际项目中通常采用 Redis + MySQL 的组合,通过 Redis 减少 MySQL 的访问压力,提高系统整体性能。


三、Redis 的数据类型

Redis 最常见的五种基础数据类型:

  1. String

  2. Hash

  3. List

  4. Set

  5. Sorted Set(ZSet)


四、String

String 是 Redis 最基本的数据类型。

格式:

复制代码
key → value

例如:

复制代码
name → 张三

Redis 命令:

复制代码
SET name 张三
GET name

结果:

复制代码
张三

4.1 String 的应用场景

缓存对象

例如:

复制代码
user:1001 → {"id":1001,"name":"张三","age":20}

可以将 JSON 字符串直接存储到 Redis。


计数器

例如文章阅读量:

复制代码
article:view:1001 → 100

每访问一次:

复制代码
INCR article:view:1001

变成:

复制代码
101

所以 Redis 的 String 非常适合做:

  • 阅读量

  • 点赞数

  • 访问次数

  • 库存数量

等计数。


分布式锁

String 还可以配合:

复制代码
SET key value NX EX

实现简单的分布式锁。


五、Hash

Hash 可以理解成:

Redis 中的一个对象。

例如用户:

复制代码
user:1001

name → 张三
age → 20
gender → 男

Redis:

复制代码
HSET user:1001 name 张三
HSET user:1001 age 20
HSET user:1001 gender 男

查询:

复制代码
HGET user:1001 name

得到:

复制代码
张三

Hash 的应用场景

Hash 非常适合保存对象。

例如:

复制代码
user:1001
    ↓
name = 张三
age = 20
phone = 138xxxx

相比于直接使用 String 保存完整 JSON,Hash 可以单独修改某一个字段。

例如只修改年龄:

复制代码
HSET user:1001 age 21

六、List

List 是一个有序的字符串列表。

可以理解为:

复制代码
List

A
B
C
D

Redis 支持从左边或者右边插入数据。

例如:

复制代码
LPUSH message A
LPUSH message B
LPUSH message C

可以形成:

复制代码
C B A

List 的应用场景

List 可以用于:

  • 消息队列

  • 最新消息列表

  • 时间线

  • 简单队列

例如:

复制代码
消息队列

Redis List
----------------
消息1
消息2
消息3
消息4
----------------

生产者负责添加:

复制代码
LPUSH

消费者负责获取:

复制代码
RPOP

从而实现简单的消息队列。


七、Set

Set 是一个无序且元素唯一的集合。

例如:

复制代码
set:

Java
Redis
MySQL
JavaScript

如果重复添加:

复制代码
Java
Java
Redis

最终只会保存:

复制代码
Java
Redis

Set 的应用场景

共同好友

例如:

复制代码
张三好友:
A B C D

李四好友:
B C E F

使用 Set 可以求交集:

复制代码
B C

也就是两个人的共同好友。


标签

例如一个用户拥有:

复制代码
Java
Redis
MySQL
Spring Boot

可以使用 Set 存储用户标签。


八、Sorted Set(ZSet)

Sorted Set,也叫 ZSet。

它和 Set 最大的区别是:

ZSet 中每个元素都有一个 Score,并且会根据 Score 排序。

例如:

复制代码
张三  100
李四  80
王五  90

Redis 会按照 Score 进行排序。

可以表示:

复制代码
张三 100
王五 90
李四 80

ZSet 的应用场景

ZSet 最经典的场景就是:

排行榜。

例如游戏排行榜:

复制代码
玩家        分数

张三        1000
李四        950
王五        900
赵六        850

Redis:

复制代码
ZADD ranking 1000 张三
ZADD ranking 950 李四
ZADD ranking 900 王五

然后可以按照分数进行排序。

因此:

排行榜是 Redis ZSet 最经典的应用场景之一。


九、Redis 五种数据类型总结

类型 特点 常见应用
String 字符串、数字 缓存、计数器、分布式锁
Hash Key-Value 对象 用户信息、对象
List 有序列表 消息队列、时间线
Set 无序、唯一 标签、共同好友
ZSet 有序、唯一、带 Score 排行榜

面试可以直接回答:

Redis 常见的数据类型有 String、Hash、List、Set 和 Sorted Set。String 常用于缓存和计数器,Hash 常用于存储对象,List 可以实现简单消息队列,Set 适合去重和集合运算,ZSet 最经典的应用场景是排行榜。


十、什么是 Redis 缓存?

在实际项目中,我们经常会遇到一个问题:

如果每一次用户请求都查询 MySQL,那么当用户数量非常大的时候:

复制代码
100万请求
      ↓
100万次 MySQL 查询
      ↓
MySQL 压力巨大

因此我们可以加入 Redis:

复制代码
用户
 ↓
Redis
 ↓
命中?
 ↓
 ├── 是 → 直接返回
 │
 └── 否
      ↓
    MySQL
      ↓
    查询数据
      ↓
  写入 Redis
      ↓
    返回数据

这样就可以减少 MySQL 的访问压力。

但是,使用 Redis 作为缓存以后,会出现三个非常经典的问题:

  1. 缓存穿透

  2. 缓存击穿

  3. 缓存雪崩

这三个问题也是 Redis 面试中的高频考点。


十一、缓存穿透

11.1 什么是缓存穿透?

缓存穿透指的是:

请求查询一个 Redis 和 MySQL 中都不存在的数据,导致请求每次都绕过 Redis,直接访问 MySQL。

例如:

复制代码
用户请求:

id = 999999999

Redis:

复制代码
没有

继续查询 MySQL:

复制代码
没有

然后返回:

复制代码
不存在

如果攻击者不断请求不存在的 ID:

复制代码
999999
888888
777777
666666
...

每次都会:

复制代码
Redis → 没有
      ↓
MySQL → 没有

最终大量无效请求会直接打到 MySQL。

这就是:

缓存穿透。


十二、缓存穿透的解决方法

常见有两种方法。

方法一:缓存空对象

当 MySQL 查询不到数据时,也把这个结果缓存起来。

例如:

复制代码
查询:

user:999999

MySQL:

复制代码
不存在

Redis:

复制代码
user:999999 → null

下一次请求:

复制代码
user:999999

直接从 Redis 读取:

复制代码
null

就不会继续访问 MySQL。

一般会给空值设置一个较短的过期时间,例如:

复制代码
60秒

避免大量不存在的数据长期占用 Redis。


方法二:布隆过滤器

布隆过滤器是一种:

空间效率非常高的概率型数据结构。

可以在访问 Redis 和 MySQL 之前先判断:

复制代码
请求
 ↓
布隆过滤器
 ↓
这个数据可能存在吗?
 ↓
 ├── 一定不存在 → 直接返回
 │
 └── 可能存在
       ↓
      Redis
       ↓
      MySQL

例如数据库中只有:

复制代码
1
2
3
4
5

用户请求:

复制代码
999999

布隆过滤器可以判断:

复制代码
一定不存在

那么就可以直接拒绝请求。


需要注意

布隆过滤器存在一个特点:

可能误判存在,但不会把存在判断成不存在。

所以它适合用来判断:

复制代码
一定不存在

然后直接拦截。


十三、缓存击穿

13.1 什么是缓存击穿?

缓存击穿和缓存穿透很容易混淆。

缓存击穿指的是:

一个热点数据突然过期,在同一时间大量请求访问这个热点数据,导致大量请求同时访问 MySQL。

例如:

复制代码
Redis:

hot:user:1001

这是一个非常热门的数据。

假设:

复制代码
10000 个用户

同时访问这个数据。

正常情况下:

复制代码
10000 请求
      ↓
    Redis
      ↓
   命中
      ↓
直接返回

但是如果这个热点数据突然过期:

复制代码
Redis
 ↓
缓存失效

此时:

复制代码
10000 请求
 ↓ ↓ ↓ ↓ ↓
同时访问 MySQL

MySQL 瞬间承受巨大的压力。

这就是:

缓存击穿。


十四、缓存击穿的解决方法

方法一:互斥锁

当发现缓存不存在时,不让所有请求同时查询 MySQL,而是只允许一个请求去查询。

例如:

复制代码
请求A
请求B
请求C
请求D
   ↓
发现 Redis 没有数据
   ↓
   加锁
   ↓
请求A获得锁
   ↓
查询MySQL
   ↓
写入Redis
   ↓
释放锁

其他请求:

复制代码
请求B
请求C
请求D
   ↓
等待
   ↓
Redis重新查询
   ↓
获得数据

最终:

复制代码
只有一个请求访问 MySQL

从而避免大量请求同时击穿数据库。


方法二:逻辑过期

另一种方式是:

缓存本身不设置真正的过期时间,而是在数据内部保存一个逻辑过期时间。

例如:

复制代码
{
    "data": "商品信息",
    "expireTime": "10:00:00"
}

当请求发现:

复制代码
当前时间 > expireTime

说明数据逻辑上已经过期。

但是:

仍然可以先返回旧数据。

然后后台异步更新缓存。

流程:

复制代码
请求
 ↓
Redis
 ↓
发现逻辑过期
 ↓
返回旧数据
 ↓
后台线程更新
 ↓
MySQL
 ↓
重新写入 Redis

这样用户不会因为缓存更新而大量等待 MySQL。


十五、缓存雪崩

15.1 什么是缓存雪崩?

缓存雪崩指的是:

大量缓存数据在同一时间失效,导致大量请求直接访问数据库,从而造成数据库压力瞬间暴增。

例如:

系统缓存了:

复制代码
商品1
商品2
商品3
商品4
...
商品10000

如果这些数据都是:

复制代码
10:00

同时过期。

那么:

复制代码
10:00
 ↓
大量 Redis Key 同时失效
 ↓
大量请求无法命中 Redis
 ↓
大量请求访问 MySQL
 ↓
MySQL 压力暴增
 ↓
甚至数据库宕机

这就是:

缓存雪崩。


十六、缓存击穿和缓存雪崩的区别

这是面试中非常容易问的问题。

缓存击穿

重点:

一个热点 Key 过期。

例如:

复制代码
热门商品
 ↓
缓存过期
 ↓
大量请求同时访问 MySQL

缓存雪崩

重点:

大量 Key 同时过期。

例如:

复制代码
商品1
商品2
商品3
...
商品10000

同时过期
 ↓
大量请求访问 MySQL

可以记忆为:

复制代码
穿透:不存在

击穿:一个热点 Key

雪崩:大量 Key

十七、缓存雪崩的解决方法

方法一:设置随机过期时间

不要让所有缓存同时过期。

例如原本:

复制代码
所有缓存:
TTL = 30分钟

可以改成:

复制代码
TTL = 30分钟 + 随机时间

例如:

复制代码
商品A:30分钟
商品B:32分钟
商品C:35分钟
商品D:38分钟

这样缓存会逐渐失效,而不是在同一时间大量失效。


方法二:热点数据永不过期

对于非常重要的热点数据,可以不设置 Redis 的物理过期时间。

通过:

复制代码
逻辑过期

或者后台定时任务主动更新。

例如:

复制代码
热门商品
热门排行榜
热门文章

这些数据可以提前刷新。


方法三:Redis 集群

如果单个 Redis 节点出现问题,可以使用 Redis Cluster 等方案进行分布式部署。

例如:

复制代码
             Redis Cluster
           /       |       \
       Node1     Node2     Node3

通过集群提高:

  • 可用性

  • 承载能力

  • 数据分布能力


方法四:服务降级

当 Redis 或 MySQL 出现异常时,可以进行服务降级。

例如:

复制代码
正常:

Redis
 ↓
MySQL
 ↓
返回完整数据

异常情况下:

复制代码
Redis异常
 ↓
返回默认数据

或者:

复制代码
暂时关闭非核心功能

从而保证核心业务继续运行。


十八、缓存三大问题总结

问题 原因 典型情况 解决方案
缓存穿透 查询不存在的数据 Redis没有,MySQL也没有 布隆过滤器、缓存空值
缓存击穿 热点Key突然过期 一个热点Key大量请求 互斥锁、逻辑过期
缓存雪崩 大量Key同时过期 大量缓存同时失效 随机TTL、逻辑过期、集群、降级

可以用一句话记忆:

复制代码
缓存穿透:
查不存在的数据

缓存击穿:
一个热点Key失效

缓存雪崩:
大量Key同时失效

十九、Redis + MySQL 的经典缓存架构

实际项目中经常使用:

复制代码
                用户请求
                   ↓
                后端服务
                   ↓
              查询 Redis
                   ↓
              ┌────┴────┐
              ↓         ↓
            命中       未命中
              ↓         ↓
           返回数据    查询 MySQL
                         ↓
                       获取数据
                         ↓
                    写入 Redis
                         ↓
                       返回

代码逻辑可以简单理解为:

复制代码
String data = redis.get(key);

if (data != null) {
    return data;
}

data = mysql.query(key);

if (data != null) {
    redis.set(key, data);
}

return data;

实际项目还需要进一步考虑:

复制代码
缓存穿透
缓存击穿
缓存雪崩
缓存与数据库数据一致性
缓存过期时间
Redis 高可用
Redis 持久化

二十、面试总结

如果面试官问:

"你了解 Redis 吗?"

可以这样回答:

Redis 是一个基于内存的 Key-Value 数据库,主要特点是读写速度快、支持丰富的数据结构,因此在实际项目中经常作为缓存使用。Redis 常见的数据类型包括 String、Hash、List、Set 和 Sorted Set。

Redis 通常和 MySQL 配合使用,MySQL 主要负责核心业务数据的持久化存储,而 Redis 主要负责热点数据缓存,从而减少 MySQL 的访问压力,提高系统性能。

使用 Redis 做缓存时,需要重点考虑缓存穿透、缓存击穿和缓存雪崩三个问题。缓存穿透是查询不存在的数据,可以通过缓存空值或者布隆过滤器解决;缓存击穿是热点 Key 失效导致大量请求同时访问数据库,可以通过互斥锁或者逻辑过期解决;缓存雪崩是大量缓存 Key 同时失效,可以通过设置随机过期时间、逻辑过期、Redis 集群和服务降级等方式解决。


二十一、最终记忆图

复制代码
                       Redis
                         │
          ┌──────────────┼──────────────┐
          │              │              │
        数据类型        Redis缓存       MySQL
          │              │              │
     ┌────┼────┐         │          持久化存储
     │    │    │         │
 String Hash List        │
     │    │    │         │
    Set  ZSet            │
                         │
             ┌───────────┼───────────┐
             │           │           │
           穿透         击穿         雪崩
             │           │           │
         不存在数据     热点Key       大量Key
             │           │           │
        布隆过滤器     互斥锁       随机TTL
        缓存空值       逻辑过期     逻辑过期
                                  集群/降级

一句话总结

Redis 的核心价值就是利用内存和丰富的数据结构提供高性能的数据访问能力;MySQL 负责可靠持久化,Redis 负责高速缓存。使用 Redis 时重点掌握五种数据类型,以及缓存穿透、缓存击穿、缓存雪崩三个经典问题和对应的解决方案。

相关推荐
qetfw1 小时前
Debian 配置 AIDE 文件完整性检测:基线初始化、变更检查与数据库更新
linux·网络·数据库·debian
Elastic 中国社区官方博客2 小时前
Elasticsearch:搜索教程 - 语义搜索(三)
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
随风M记忆s3 小时前
Redis支持事务吗?了解Redis的持久化机制吗?
数据库·redis·bootstrap
花青泽5 小时前
5-数据库-SQL注入-联合查询-关键字绕过-day13
数据库·sql
天桥下的卖艺者11 小时前
使用scitable包,两步生成逆概率删失权重(IPCW)
数据库·r语言
隔窗听雨眠11 小时前
AI原生数据库浪潮:国产数据库的架构重构与路径之争
数据库
数据库小学妹11 小时前
数据库选型实战:从数据类型到TCO成本,五维决策框架+九款产品横评
数据库·信创·国产数据库·数据库选型·oracle迁移
神龙天舞200112 小时前
MySQL 备库为什么会延迟好几个小时
android·数据库·mysql
丙氨酸長鏈14 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库