Redis 基础与原理
Redis 是什么
Redis 是一个基于内存的高性能 Key-Value 数据库,常用于缓存、计数器、排行榜、分布式锁、限流、消息队列和会话存储。
它的核心特点是:数据主要放在内存里,读写很快;支持 String、Hash、List、Set、ZSet、Bitmap、HyperLogLog、Geo、Stream 等丰富数据结构;支持 RDB / AOF 持久化、主从复制、哨兵和 Cluster 高可用方案。
Redis 和 MySQL 有什么区别
MySQL 是关系型数据库,核心目标是可靠存储和复杂查询;Redis 是内存型 NoSQL 数据库,核心目标是高性能读写和灵活的数据结构。
| 对比项 | Redis | MySQL |
|---|---|---|
| 数据模型 | Key-Value,多种内置结构 | 表、行、列、关系模型 |
| 主要存储 | 内存为主,可持久化到磁盘 | 磁盘为主,Buffer Pool 缓存热点页 |
| 查询能力 | 按 key 访问,复杂查询弱 | SQL、JOIN、事务、索引优化 |
| 性能特点 | 单 key 读写非常快 | 更重视一致性、事务和复杂查询 |
| 典型场景 | 缓存、锁、计数、排行榜、限流 | 订单、用户、交易等核心业务数据 |
项目里通常是 MySQL 存最终数据,Redis 存热点副本、临时状态或高并发访问数据。Redis 不能直接替代 MySQL,因为它缺少完整关系模型、复杂查询能力和强事务能力。
项目中一般 Redis 用来做什么?什么业务场景会选择使用 Redis?为什么选择 Redis 而不是其他缓存
常见用途:
- 缓存热点数据:例如用户信息、商品详情、配置字典,降低 MySQL 压力。
- 分布式锁:例如防止重复提交、库存扣减串行化。
- 计数器:例如浏览量、点赞数、接口调用次数。
- 排行榜:用 ZSet 按 score 排序。
- 限流:用计数器、滑动窗口或 Lua 脚本保证原子性。
- 消息队列 / 延迟队列:List、Stream、ZSet 都可以做不同形态的队列。
- 会话共享:多实例服务共享登录态或临时状态。
选择 Redis 的原因主要是性能高、数据结构丰富、生态成熟、支持持久化和高可用。相比本地缓存,Redis 能跨服务共享;相比 Memcached,Redis 数据结构更多,还支持持久化、复制、Lua 和更完整的集群方案。
Redis 是单线程,为什么还这么快
Redis 的“单线程”主要指命令执行线程是单线程,不代表所有工作都只有一个线程。它快的原因有四个:
- 基于内存:绝大多数操作不需要磁盘随机 IO。
- 单线程执行命令:避免多线程锁竞争和上下文切换。
- I/O 多路复用:一个线程可以同时处理大量客户端连接。
- 数据结构高效:SDS、dict、quicklist、skiplist 等结构针对常见场景做了优化。
不过 Redis 不适合执行耗时命令。比如大 key 的 hgetall、smembers、keys 都可能阻塞事件循环,导致其他请求排队。
Redis 的 I/O 多路复用原理是什么
Redis 使用 I/O 多路复用同时监听多个 socket。当某个连接可读或可写时,事件循环才处理对应事件,不需要为每个连接创建一个线程。
在 Linux 上常见实现是 epoll。它的思路是:Redis 把多个客户端连接注册给内核,内核发现某些连接有事件后通知 Redis,Redis 再依次读取请求、执行命令、写回响应。
这套模型的好处是连接数很多时也不需要大量线程,资源开销低。真正要注意的是命令执行本身仍然要快,否则一个慢命令会拖住后面的请求。
Redis 6.0 之后引入了多线程?一定比单线程快吗
Redis 6.0 引入的是网络 I/O 多线程,主要用于并行处理读写 socket、协议解析等网络相关工作。命令执行默认仍然是单线程,避免并发修改数据结构带来的锁复杂度。
它不一定比单线程快。只有在网络 I/O 成为瓶颈、实例 CPU 还有空闲、请求量足够大时,多线程才明显有收益。如果瓶颈在慢命令、大 key、持久化 fork、内存或业务访问模式,多线程 I/O 不能根治问题。