什么是Redis
开源的非关系型数据库(NoSQL),它使用内存作为储存介质,C语言实现,Key—Value数据库;Redis(远程字典服务)
缓存、消息队列
Redis是NoSQL中的一种存储工具,他是一个key-value存储系统。默认有16个数据库从0到15来进行表示。Redis的存储类型:包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。在此基础上,Redis支持各种不同方式的排序。
redis的安装方式
Redis缓存的作用
提升查询访问的速度,减轻关系型数据(MySQL)的并发压力;
本地缓存
客户端:例如浏览器缓存
服务端:Nginx缓存,MySQL本地缓存
远程缓存
Redis/Memcached
CDN(内容分发网络)
🚀 加速读请求,提升用户体验
这是最直接的作用。当应用需要频繁读取某些数据(如用户信息、商品详情)时,第一次从磁盘数据库(如 MySQL)读取后,将其存入 Redis。
之后:所有读请求直接走 Redis 内存,响应时间从 毫秒级(磁盘IO) 降到 微秒级。
效果:页面加载更快,用户体验更流畅。
🛡️ 减轻后端数据库压力(防止雪崩)
数据库的连接数和并发处理能力是有限的。如果没有缓存,高并发下所有请求都直接打到数据库,很容易导致数据库 CPU 飙升甚至宕机。
作用:Redis 扛住了 80%-90% 的读流量,数据库只需处理少量的写请求和缓存未命中的请求,大大降低了被“打死”的风险。
🧮 承担复杂计算结果的复用
有些数据不是直接从 DB 查出来的,而是需要经过大量计算(比如排行榜、统计报表、用户画像)。
作用:将耗时几分钟的计算结果提前算好存进 Redis,后续请求直接拿结果。用空间换时间,避免重复计算浪费 CPU。
🔗 作为分布式系统的“共享存储”
在微服务或多服务器集群环境下,用户登录后产生的 Session(会话)默认只存在单台机器内存里。
作用:把 Session 存到 Redis,所有服务器都去 Redis 里读,用户就不会因为请求被转发到不同机器而需要反复登录(这就是单点登录的基础)。
🧩 辅助实现业务功能(不只是缓存)
虽然你问的是缓存作用,但顺带一提,Redis 的数据结构和原子操作让它能做更多事,而这些通常也部署在缓存层:
计数器:利用
INCR命令实现高并发下的点赞数、浏览数,每秒处理万级请求。分布式锁:利用
SETNX防止多台机器同时处理同一笔订单(重复下单)。限流器:利用
EXPIRE时间窗口限制用户每分钟的访问次数。
⚠️ 需要注意:缓存不是万能的
引入缓存后,也会带来三个经典的“坑”:
针对这三个问题,业界有布隆过滤器、随机过期时间、互斥锁等成熟的解决方案
Redis能抗高并发
QPS = 每秒钟的访问量;
关系型数据库 (1000QPS)
Redis (十万QPS)
机械硬盘100MB/S
内存100GB/S
内存的I/O要远高于磁盘;
单线程架构,避免了多线程带来的线程间切换的消耗;
I/O多路复用,异步非阻塞的架构;
1. 数据全在内存,这是根本原因
这是Redis快的基础。内存的读写速度是纳秒级的,而磁盘(如MySQL)是毫秒级的。内存比磁盘快了几个数量级(约10万倍)。
请求链路对比:
MySQL:查磁盘 → 寻道 → 旋转 → 读数据,CPU大部分时间在等待IO。
Redis:直接从内存哈希表取指针,瞬间返回数据,CPU几乎一直在干活,没有等待。
2. 单线程模型 + 非阻塞IO(核心武器)
很多人觉得“单线程”是瓶颈,但在Redis这里,单线程反而是它能抗高并发的原因。
没有锁竞争开销:多线程虽然能利用多核,但需要加锁(如互斥锁、读写锁),这会导致上下文切换和死锁风险。Redis单线程处理,天然线程安全,省去了锁的损耗。
IO多路复用机制:这是Redis的核心技术。它通过
epoll(Linux)机制,让一个线程同时监听成千上万个客户端连接。当某个连接有数据来了,才去处理,没数据时线程就休眠等待,不会空转。通俗理解:就像一个“万事通”服务员,一个人同时接待100桌客人,哪桌有人举手(有请求),他就去哪桌处理,动作极快。他不会因为某桌客人点菜慢就在那干等着。
3. 高效的数据结构
Redis内部的数据结构是专门为速度设计的,操作复杂度多为O(1)。
比如跳表,它在有序链表上加了多级索引,查找一个元素能跳过大量节点,保证了高并发下的快速响应。
4. 纯内存操作 + 管道技术(Pipeline)
批量处理:Redis支持管道(Pipeline),允许客户端一次发送多个命令,无需等待每个命令的回复。这大幅减少了网络往返时间(RTT),在批量写入场景下,QPS(每秒查询数)可以轻松破10万。
极短的操作时间:每个请求处理时间极短(微秒级),单线程也能在1秒内处理完大量请求。
5. 渐进式Rehash + 多路复用,保证稳定
Redis在扩容字典(rehash)时不是一次性完成,而是分步、渐进式迁移数据,避免了大卡顿。同时,它不会阻塞主线程去做磁盘IO(如持久化由子进程完成),从而保证了对外服务的稳定性。
⚠️ 单线程也有局限
基于以上设计,Redis单节点QPS可以达到10万+。但它也有短板:
耗时操作会阻塞所有请求:比如执行
KEYS *、FLUSHALL或大key删除,如果这些操作耗时1秒,那这一秒内所有其他请求都会排队等待。解决方案:生产环境禁用危险命令,或使用
SCAN、UNLINK等替代。
这个问题问得很到位,Redis 和 MySQL 的区别,本质上就是内存数据库和磁盘数据库,以及键值存储和关系型存储的根本差异。
我用一个对比表格先给你一个全景图,然后再针对几个核心点展开聊聊。
Redis和MySQL的区别
Reids是内存型的非关系型数据库,速度快不安全;
MySQL是使用磁盘存储的关系型数据库 ,速度慢安全;
Redis替MySQL抗高并发,节省成本
全景对比:一张表看懂核心区别
核心差异深入解读
上面表格是总览,下面这四个点是它们最根本的不同:
快慢的根本原因:内存 vs. 磁盘
Redis:数据常驻内存。内存的随机读写速度是 纳秒级 (ns),几乎等同于 CPU 处理速度。这就是它为什么能抗住 10 万级并发的物理基础。
MySQL:数据在磁盘。即便有 Buffer Pool 缓存,一旦涉及
fsync落盘或磁盘寻道,速度就是 毫秒级 (ms)。两者速度差距在 1000 倍以上。
数据结构:万能瑞士军刀 vs. 严谨的 Excel 表格
Redis:它不只是存字符串。List 可以做最新消息队列,Hash 存对象,Zset 做排行榜。这些结构在内存中都是指针操作,时间复杂度 O(1),即取即用,无需像 MySQL 那样建索引。
MySQL:数据必须规整为行和列。要查数据得先建 B+ 树索引,即使命中索引,也要在磁盘上寻址,复杂度相对较高。
安全与一致性:闪电速度 vs. 绝对可靠 这是选型时的核心权衡:
Redis:为了快,它牺牲了安全性。默认异步持久化,如果服务器突然断电,最近几秒(取决于
save策略)的数据可能就永久丢失了。MySQL:银行转账、订单扣库存这类场景,钱不能丢,必须用 Redo Log 和 Binlog 保证事务持久化(ACID 中的 D)。
查询能力的差异:精准Key查询 vs. 灵活SQL
Redis:查询严重依赖 Key。如果你想知道“年龄 25 岁且城市在北京的用户”,在 Redis 里几乎无法直接查,除非你专门维护一个 Set 集合。
MySQL:可以用一条
SELECT * FROM user WHERE age=25 AND city='beijing'轻松搞定,利用 SQL 引擎进行复杂运算。
实际开发中的经典组合
在生产环境中,它们是对好搭档,而不是对手。最经典的架构是:
MySQL 负责“写”和绝对数据存储,Redis 负责“读”和高速访问。
当用户请求一个商品详情:
先查 Redis 缓存,如果有就直接返回(极速)。
如果 Redis 没有(缓存未命中),再去查 MySQL 磁盘(较慢)。
将 MySQL 查出的结果写入 Redis,下一次用户再查就直接命中缓存了。
这就是 “缓存旁路模式 (Cache-Aside Pattern)”,也是目前绝大多数互联网高并发系统的标准解法。
Redis常用命令
. 通用命令(所有类型通用)
2. String(字符串)——最常用
适合存缓存对象(JSON)、计数器、分布式锁。
3. Hash(哈希)——适合存对象/记录
适合存用户信息、商品详情、配置项。
4. List(列表)——适合消息队列/最新动态
有序,可重复,适合做最新消息、简单队列。
5. Set(集合)——适合去重/交集/抽奖
无序,不重复,适合共同好友、标签、抽奖池。
6. ZSet(有序集合)——排行榜首选
每个元素带分数,按分数自动排序。
7. 管理与维护命令
🔥 开发中最常用的命令组合
⚠️ 两个必须牢记的禁忌
绝对不要在生产用
KEYS \*:会阻塞Redis数秒甚至分钟,导致所有请求超时。用SCAN替代。不要用
HGETALL或SMEMBERS取大key:如果一个Hash有百万字段,这个命令会把整个内存数据一次性传输,导致网络阻塞。用HSCAN或SSCAN分批取。
Redis数据类型与作用
接下来,我来详细拆解每个类型的核心作用和需要注意的“坑”。
1. String (字符串) —— 万能的基石
String 不只是存字符串,它还能存整数、浮点数,甚至图片或序列化对象的二进制数据(值最大支持 512MB)。
核心作用:
缓存对象:将用户信息、商品详情等对象序列化成 JSON 字符串存储,减轻数据库压力。
计数器:利用
INCR和DECR命令,实现原子性的点赞数、阅读数、库存扣减。分布式锁:利用
SETNX命令,实现分布式环境下的互斥访问。Session 共享:在微服务架构中,将用户会话集中存储,解决多服务器间的登录状态同步问题。
⚠️ 注意:单个 String 类型的 Key 不宜过大(建议控制在 10KB 以内),否则在网络传输和内存分配时会产生性能瓶颈(即“大 Key”问题)。
2. Hash (哈希) —— 对象存储专家
Hash 特别适合存储一个对象的多个属性,它可以像一个微型数据库表一样,独立地存取、修改对象的某个字段。
核心作用:
存储对象信息:比如用户信息(ID、姓名、年龄)、商品详情(价格、库存、描述)。相比于 String 存 JSON,Hash 可以只更新某个字段,无需整体覆盖,更加高效。
购物车:以用户 ID 为 Key,商品 ID 为 Field,商品数量为 Value,可以非常方便地增减商品数量。
⚠️ 注意:Hash 虽好,但不要在一个 Key 中存过多 Field(建议控制在 1000 个以内)。否则使用
HGETALL时,会一次性拉取大量数据,造成网络拥堵和 Redis 阻塞。
3. List (列表) —— 消息队列与时间轴
List 是一个有序的字符串列表,底层是一个双向链表,所以在头尾插入或删除元素的速度极快(时间复杂度 O(1))。
核心作用:
消息队列:生产者使用
LPUSH将消息塞入队头,消费者使用BRPOP阻塞式地从队尾取消息,实现一个简单的“生产者-消费者”模型。最新动态列表:比如将最新的 100 条评论 ID 存入 List,用
LRANGE命令就能轻松实现分页和倒序展示。
⚠️ 注意:List 不支持元素去重,也不适合做随机读写(中间位置的元素访问速度慢)。
4. Set (集合) —— 关系运算大师
Set 会自动去重,并且支持在多个集合之间进行交、并、差运算。这是它的王牌功能。
核心作用:
标签系统:为一篇文章打上“Redis”、“Java”等多个标签,既能去重,也能通过集合运算找到所有带“Java”和“Redis”标签的文章。
抽奖/抢购:利用
SPOP(随机弹出)或SRANDMEMBER(随机返回)实现公平抽奖。共同好友/关注:将两个用户的好友 ID 分别存入两个 Set,用
SINTER取交集,就能瞬间算出共同好友。
⚠️ 注意:Set 的元素数量较大时(如超过万级),
SINTER这类集合运算命令的开销会很高,要注意执行频率。
5. ZSet (有序集合) —— 排行榜之王
ZSet 在 Set 的基础上,为每个元素关联了一个“分数”,元素按分数自动从小到大排序。这个特性使其成为排行榜功能的不二之选。
核心作用:
各类排行榜:如游戏积分榜、商品销量榜、视频热度榜。用
ZINCRBY增加分数,用ZREVRANGE取 Top N。延迟队列:将任务执行时间戳作为分数,多个消费者轮询
ZRANGEBYSCORE,取出到时间需要执行的任务。带权重的消息队列:为不同优先级的消息设置不同分数,让高优先级消息被优先处理。
⚠️ 注意:ZSet 的内存开销相对较大(底层是跳表和哈希表的组合),如果数据量巨大且对排序精度要求不高,需要评估内存成本。
一个特别的补充:Bitmaps 与 HyperLogLog
除了以上 5 种,Redis 还提供了两种基于 String 的“特殊”类型,它们非常节省空间,在特定场景下效果拔群:
Bitmaps (位图):不是独立类型,而是 String 的二进制位操作。适合做海量数据的布尔型统计,比如记录用户每日签到(1 表示签到,0 表示未签)、在线用户状态等。几亿用户的状态也只需要几十 MB 内存。
HyperLogLog:一种用于基数统计的概率算法,极其节省空间(每个 Key 约 12KB)。比如统计一个巨大网站的独立访客数(UV),它允许有微小的误差(约 0.81%),但内存消耗是 Set 的万分之一。
总结一下:如何选型?
存个简单的值、数字、Token → String
存一个对象,需要单独修改其中一个字段 → Hash
做一个先进先出的队列,或存最新列表 → List
需要去重、取交集/并集(如共同好友)→ Set
需要排序、做排行榜、延迟队列 → ZSet
海量数据做签到、布隆过滤 → Bitmaps
海量数据做 UV 统计、允许小误差 → HyperLogLog
Redis了解
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法