Redis知识梳理(1)

作者:没有四次元口袋的蓝胖

日期:2026-10-11

标签:Redis, 数据类型, 高并发

Redis知识梳理(1)

写在前面

Redis(REmote DIctionary Server)是目前使用最广泛的内存数据库 。在 Java 后端面试中,Redis 几乎是必考的中间件,出场率比 MySQL 还高。不管你是菜鸟还是资深,都会被问。

为什么 Redis 这么重要?因为现代互联网应用几乎都离不开它------接口性能优化、分布式锁、缓存、排行榜、限流、消息队列......处处都是 Redis 的身影。


一、Redis 是什么?

1.1 官方定义

Redis 是一个开源的、基于内存的、支持多种数据结构的 NoSQL 键值存储数据库。

拆解一下关键词:

关键词 含义
开源 免费,社区活跃
基于内存 数据默认存储在内存中,读写极快
多种数据结构 不只是 K-V,还支持 String/List/Hash/Set/ZSet 等
NoSQL 非关系型数据库,和传统关系型数据库(MySQL)不同
键值存储 通过 Key 存取 Value

1.2 Redis 的历史

Redis 由意大利人 Salvatore Sanfilippo(网名 antirez)在 2009 年开发。最初只是他想解决自己公司网站的实时访问量统计问题,没想到后来成为全球最流行的内存数据库。

2015 年成立 Redis Labs(现名 Redis Inc.),提供商业化的 Redis Enterprise 版本。

1.3 Redis 能做什么?

应用场景 说明
缓存 最核心场景,减少数据库压力
分布式锁 高并发下保证任务唯一执行
排行榜 ZSet 天然适合
计数器 点赞、访问量、库存
消息队列 List 发布/订阅
限流 滑动窗口、令牌桶
会话存储 分布式 Session 共享
地理信息 GEO 数据类型

二、为什么 Redis 快?(面试必问)

这是 Redis 面试第一题,必须背熟。 一般会问"Redis 为什么这么快?"

2.1 六大原因

1. 纯内存操作

这是最核心的原因。Redis 数据存储在内存中,读取内存速度是纳秒级别(~100ns),而磁盘 IO 是毫秒级别(~10ms),相差 10 万倍。

复制代码
内存访问:约 50-100 ns
SSD 磁盘:约 100-200 μs
机械硬盘:约 5-10 ms

2. 单线程模型,避免上下文切换和锁竞争

Redis 使用单线程处理网络请求。这听起来像缺点,其实是优点:

  • 没有线程切换开销
  • 不需要加锁(天然线程安全)
  • 不存在死锁、锁竞争问题

💡 注意:Redis 6.0 之后引入多线程来处理网络 IO (读socket、写socket),但命令执行仍然是单线程。也就是"网络IO多线程,命令执行单线程"。

3. I/O 多路复用

Redis 利用 Linux 的 epoll 机制,一个线程同时监控多个 socket 连接,哪个 socket 有数据就处理哪个,不用像传统 BIO 那样一个连接一个线程。

复制代码
传统 BIO:  一个连接 → 一个线程(连接多了就耗尽资源)
Redis:     一个线程 → 监控所有连接(epoll 多路复用)

4. 高效的数据结构

Redis 每种数据类型底层都用了精心设计的数据结构(后面会细讲),比如:

  • SDS(简单动态字符串)代替 C 字符串,避免缓冲区溢出
  • 跳表(SkipList)实现有序集合,查找效率 O(log n)
  • 压缩列表(ziplist)和快速列表(quicklist)节省内存

5. 自己实现了事件模型

Redis 自己实现了基于事件驱动的 Reactor 模型,所有命令在事件循环中串行处理,避免了多线程的复杂性。

6. 单次命令操作是原子性的

因为单线程,单个命令的执行是原子的,不会被打断。这也是 Redis 能实现分布式锁的基础之一。

2.2 为什么 Redis 6.0 要引入多线程?

单线程也有瓶颈------网络 IO 处理慢(要频繁读写 socket,涉及系统调用和上下文切换)。

Redis 6.0 的做法:

  • 读取请求、写回响应用多线程(IO 线程池,默认关闭,可配置)
  • 命令执行仍然是单线程

这样既享受了多线程处理 IO 的吞吐提升,又保持了命令执行的原子性和简单性。

🎯 面试高频:为什么 Redis 用单线程还这么快?

核心四句话:纯内存、单线程无锁开销、IO多路复用(epoll)、数据结构高效。


三、官方性能基准数据

Redis 官方给出的基准(单节点,2.6GHz CPU):

  • 读性能:约 100,000 次/秒(QPS)
  • 写性能:约 80,000 次/秒
  • 延迟:P99 在 1ms 以内

这是单节点的超高性能,也是 Redis 能成为缓存之王的原因。


四、Redis 与数据库:多服务共享(为什么需要 Redis)

4.1 没有 Redis 的痛点

假设一个电商系统,只有 MySQL,没有缓存:

复制代码
用户 A 请求商品详情  →  每次都查 MySQL  ←  用户 B 也请求
用户 C 查看库存     →  MySQL            ←  用户 D 也查看

当用户量上来后:

  • 数据库压力过大:所有请求直接打到 MySQL,连接耗尽、慢查询、卡死
  • 响应慢:磁盘 IO 慢,每次都要查数据库
  • 无法支撑高并发:MySQL 一般能支撑几千 QPS,但大促时可能几十万 QPS

4.2 Redis 作为"多服务共享缓存"

引入 Redis 后,多个服务共享同一份内存缓存:

复制代码
                  ┌─────────────┐
服务A ──────┐     │   Redis     │
服务B ──────┼────▶│  (共享缓存)  │
服务C ──────┘     │  内存,超快  │
                  └──────┬──────┘
                         │ 未命中时才查
                         ▼
                       MySQL

多服务共享的意义:

  1. 多个微服务共享一份缓存:如果两个服务都要读用户信息,不需要各查各的数据库,一起从 Redis 读,数据库只被弱访问
  2. 热点数据只加载一次:高并发下,热点数据只需从 MySQL 读一次进缓存,之后全部走内存
  3. 跨服务一致:A 服务更新了数据写 Redis,B 服务能立刻读到最新值

4.3 经典的 Cache-Aside 缓存模式

这是最常用的缓存读写模式(旁路缓存):

读流程(读缓存):

复制代码
1. 请求来了,先查 Redis
2. 命中 → 直接返回(快)
3. 未命中 → 查 MySQL
4. 把结果写入 Redis
5. 返回给客户端

写流程(更新缓存):

复制代码
1. 更新数据库 MySQL
2. 删除 Redis 中对应的缓存
(下次读取时再重建缓存)

⚠️ 面试常问:为什么不直接更新 Redis 缓存,而是删除?

因为更新缓存有竞态问题(稍后讲缓存一致性时细说)。业界更多采用"先更新数据库,再删除缓存"策略,配合延迟双删解决并发问题。

4.4 Redis vs MySQL 对比

对比维度 Redis MySQL
存储介质 内存(默认) 磁盘
读写速度 纳秒级 毫秒级
数据容量 受内存限制(通常几GB~几十GB) 大(TB级别)
数据结构 丰富(List/Hash/Set等) 表、行、列(结构化)
事务 弱事务(后续讲) 强事务(ACID)
持久化 支持(RDB/AOF) 天然持久化
适用场景 缓存、实时数据、高并发 业务数据存储、复杂查询

结论:MySQL 存数据,Redis 提速度。 两者是协作关系,不是替代关系。


五、五种核心数据类型(概览)

Redis 之所以强大,不只是因为它快,更因为它的数据类型丰富。这是 Redis 区别于 Memcached(只能存字符串)的最大优势。

5.1 总览表

类型 英文名 底层结构 最大存储 典型场景
String 字符串 SDS + int 512MB 缓存、计数器、分布式锁
Hash 哈希 ziplist/hashtable 2^32-1 字段 对象存储、购物车
List 列表 quicklist 2^32-1 元素 消息队列、最新列表
Set 集合 intset/hashtable 2^32-1 成员 去重、共同好友、抽奖
ZSet 有序集合 ziplist/skiplist 2^32-1 成员 排行榜、延时队列

5.2 每种类型一句话理解

复制代码
String   → 一个键对应一个字符串值(最简单、最常用)
Hash     → 一个键对应一个"类似Java对象"的字段集合
List     → 一个有序的字符串列表(可以从两头操作)
Set      → 一个无序的不重复集合(天然去重)
ZSet     → 一个有序集合,每个元素带一个分数,按分数排序

5.3 通俗类比

Redis 类型 类比 Java 类比生活
String String 一条便利贴
Hash HashMap 一张填写了多个字段的表格
List LinkedList 一条排队购物的队伍
Set HashSet 一个装了不同水果的篮子(不能重复)
ZSet TreeSet + 分数 一个按分数排名的成绩单

5.4 如何选择?

复制代码
要存简单值/计数/锁 → String
要存对象/多个字段 → Hash
要存有序列表(最新/队列) → List
要去重/集合运算 → Set
要排序/排行榜 → ZSet

六、五种数据类型底层结构简介

6.1 String 底层:SDS

Redis 没有直接用 C 语言的字符串,而是自己实现了一个 SDS(Simple Dynamic String,简单动态字符串):

c 复制代码
struct sdshdr {
    int len;      // 已经使用的长度
    int alloc;    // 分配的总容量
    char buf[];   // 实际存储字符串的字节数组
};

为什么不用 C 字符串?

问题 C 字符串 SDS
获取长度 O(n) 需遍历 O(1) 直接读 len
缓冲区溢出 会溢出 自动扩容
二进制安全 遇 \0 截断 按 len 存取,安全
修改字符串 需重新分配内存 预分配,减少内存分配次数

6.2 Hash 底层

小数据量 (元素少且值短)时用 ziplist(压缩列表) ,节省内存;

大数据量 时升级为 hashtable(哈希表)。

6.3 List 底层:quicklist

使用 quicklist(快速列表),本质是多个 ziplist 用双向链表串起来,兼顾了内存紧凑和两端操作高效。

6.4 Set 底层

全整数 且元素少时用 intset(整数集合) ;

否则用 hashtable(value 为 null 的哈希表,利用 key 去重)。

6.5 ZSet 底层

元素少 时用 ziplist ;

元素多 时用 skiplist(跳表)+ hashtable 组合:

  • 跳表负责有序遍历和范围查询
  • 哈希表负责 O(1) 查分数

💡 深入了解这些底层结构是加分项,后面讲到各类型时再细挖。先有个整体概念。


七、安装 Redis 快速上手

7.1 安装

bash 复制代码
# Ubuntu / Debian
sudo apt install redis-server

# CentOS
sudo yum install redis

# Docker(推荐,干净)
docker run -d --name redis -p 6379:6379 redis:7

7.2 启动与连接

bash 复制代码
# 启动服务
redis-server redis.conf

# 连接客户端
redis-cli
redis-cli -h 127.0.0.1 -p 6379

# 验证
127.0.0.1:6379> ping
PONG

7.3 常用全局命令

bash 复制代码
# 查看所有 Key
KEYS *

# 判断 Key 是否存在
EXISTS key

# 设置过期时间(秒)
EXPIRE key 60

# 删除 Key
DEL key

# 查看数据类型
TYPE key

# 清空当前库
FLUSHDB

# 切换数据库(默认0-15)
SELECT 1

八、Redis 基础配置

conf 复制代码
# redis.conf 常用配置

# 绑定地址(默认只能本机访问)
bind 0.0.0.0

# 端口
port 6379

# 设置密码
requirepass yourpassword

# 最大内存(达到后触发淘汰策略)
maxmemory 2gb

# 持久化相关(后续章节细讲)
save 900 1
appendonly yes

# 保护模式
protected-mode yes

思维导图速览

复制代码
Redis 初识 + 五种数据类型
│
├── Redis 是什么
│   ├── 开源 / 内存 / NoSQL / 键值存储
│   └── 场景:缓存/锁/排行榜/计数/队列/限流
│
├── 为什么快(面试必问)
│   ├── 纯内存操作(纳秒级)
│   ├── 单线程无锁竞争
│   ├── IO 多路复用(epoll)
│   ├── 高效数据结构
│   ├── 事件驱动模型
│   └── 命令原子性
│   └── 注:6.0网络IO多线程,命令执行仍单线程
│
├── 多服务共享(缓存作用)
│   ├── 多个微服务共享一份缓存
│   ├── 热点数据只加载一次
│   ├── Cache-Aside 模式(缓存旁路)
│   └── Redis 存速度,MySQL 存数据
│
├── 五种数据类型
│   ├── String(SDS底层)
│   ├── Hash(ziplist/hashtable)
│   ├── List(quicklist)
│   ├── Set(intset/hashtable)
│   └── ZSet(ziplist/skiplist+hashtable)
│
└── 安装与快速上手
    ├── 安装(apt/yum/docker)
    ├── redis-cli 连接
    ├── 全局命令(KEYS/EXISTS/EXPIRE/DEL/TYPE)
    └── 基础配置(bind/port/pass/maxmemory)

写在最后

本篇是 Redis 系列的地基。三个核心认知一定要牢牢建立:

  1. Redis 为什么快------纯内存 + 单线程 + IO多路复用,这四句话随时能被问到。
  2. Redis 解决什么问题------核心是"多服务共享 + 极速访问",给数据库减负。
  3. 五种数据类型------每个类型的语义和典型场景要清楚,后面每一篇都会围绕具体类型展开。
相关推荐
夜雪一千1 小时前
MySQL 数据加密实战:从传输、存储到字段级加密,分清场景不踩坑
数据库·mysql
wefg12 小时前
【Redis】C++ 自定义客户端
数据库·redis·缓存
这个DBA有点耶2 小时前
为什么UPDATE比SELECT危险得多?锁范围等于扫描行数
数据库·架构·代码规范
天国梦2 小时前
国密门禁品牌怎么选?2026年最新3个避坑要点
运维·服务器·数据库·python
DB哥讲数据库2 小时前
【达梦数据库安装教程】超详细图文讲解-附达梦安装包
数据库·oracle
Hoxy.R3 小时前
【金仓数据库产品体验官】KingbaseES V9R2C16 坏块检测与修复完整测试流程
数据库
太理摆烂哥5 小时前
MySQL数据库基础
数据库·mysql
wuhuhuan5 小时前
JMeter 连接数据库并取值(JDBC 实战)
数据库·jmeter
一个有温度的技术博主5 小时前
两级缓存一致性实战:Redis + 本地缓存,如何不让数据“分裂”?
redis·spring·缓存