什么是Redis

开源的非关系型数据库(NoSQL),它使用内存作为储存介质,C语言实现,Key—Value数据库;Redis(远程字典服务)

  • 缓存、消息队列

Redis是NoSQL中的一种存储工具,他是一个key-value存储系统。默认有16个数据库从0到15来进行表示。Redis的存储类型:包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。在此基础上,Redis支持各种不同方式的排序。

redis的安装方式

安装方式

适用场景

优点

缺点

YUM 安装

生产环境快速部署

安装快,自动做系统服务,方便更新升级

版本通常偏旧,除非添加第三方仓库

RPM 包安装

内网离线环境

无需编译,保留二进制包方便批量部署

需要提前找好对应系统的 RPM 包,找包比较麻烦

源码编译

追求最新特性、定制编译参数

版本最新,编译选项可定制(如 TLS)

编译耗时长,缺少自动化的系统服务管理

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 时间窗口限制用户每分钟的访问次数。


⚠️ 需要注意:缓存不是万能的

引入缓存后,也会带来三个经典的“坑”:

问题

简单解释

缓存穿透

查询一个根本不存在的数据(如 id=-1),缓存查不到,每次都会打到 DB,可能压垮数据库。

缓存雪崩

大量缓存在同一时间过期,导致瞬间请求全部涌入 DB。

缓存击穿

某个热点数据(如爆款商品)刚好过期,此时大量并发请求直接打到 DB。

针对这三个问题,业界有布隆过滤器、随机过期时间、互斥锁等成熟的解决方案

Redis能抗高并发

QPS = 每秒钟的访问量;

关系型数据库 (1000QPS)

Redis (十万QPS)

机械硬盘100MB/S

内存100GB/S

  1. 内存的I/O要远高于磁盘;

  2. 单线程架构,避免了多线程带来的线程间切换的消耗;

  3. I/O多路复用,异步非阻塞的架构;

1. 数据全在内存,这是根本原因

这是Redis快的基础。内存的读写速度是纳秒级的,而磁盘(如MySQL)是毫秒级的。内存比磁盘快了几个数量级(约10万倍)。

  • 请求链路对比

    • MySQL:查磁盘 → 寻道 → 旋转 → 读数据,CPU大部分时间在等待IO。

    • Redis:直接从内存哈希表取指针,瞬间返回数据,CPU几乎一直在干活,没有等待。

2. 单线程模型 + 非阻塞IO(核心武器)

很多人觉得“单线程”是瓶颈,但在Redis这里,单线程反而是它能抗高并发的原因

  • 没有锁竞争开销:多线程虽然能利用多核,但需要加锁(如互斥锁、读写锁),这会导致上下文切换和死锁风险。Redis单线程处理,天然线程安全,省去了锁的损耗。

  • IO多路复用机制:这是Redis的核心技术。它通过epoll(Linux)机制,让一个线程同时监听成千上万个客户端连接。当某个连接有数据来了,才去处理,没数据时线程就休眠等待,不会空转。

    通俗理解:就像一个“万事通”服务员,一个人同时接待100桌客人,哪桌有人举手(有请求),他就去哪桌处理,动作极快。他不会因为某桌客人点菜慢就在那干等着。

3. 高效的数据结构

Redis内部的数据结构是专门为速度设计的,操作复杂度多为O(1)。

数据类型

底层实现

查询复杂度

String

SDS(简单动态字符串)

O(1)

Hash

字典(渐进式rehash)

O(1)

Zset

跳表(Skip List)

O(logN)

比如跳表,它在有序链表上加了多级索引,查找一个元素能跳过大量节点,保证了高并发下的快速响应。

4. 纯内存操作 + 管道技术(Pipeline)

  • 批量处理:Redis支持管道(Pipeline),允许客户端一次发送多个命令,无需等待每个命令的回复。这大幅减少了网络往返时间(RTT),在批量写入场景下,QPS(每秒查询数)可以轻松破10万。

  • 极短的操作时间:每个请求处理时间极短(微秒级),单线程也能在1秒内处理完大量请求。

5. 渐进式Rehash + 多路复用,保证稳定

Redis在扩容字典(rehash)时不是一次性完成,而是分步、渐进式迁移数据,避免了大卡顿。同时,它不会阻塞主线程去做磁盘IO(如持久化由子进程完成),从而保证了对外服务的稳定性。

⚠️ 单线程也有局限

基于以上设计,Redis单节点QPS可以达到10万+。但它也有短板:

  • 耗时操作会阻塞所有请求:比如执行KEYS *FLUSHALL或大key删除,如果这些操作耗时1秒,那这一秒内所有其他请求都会排队等待。

  • 解决方案:生产环境禁用危险命令,或使用SCANUNLINK等替代。

这个问题问得很到位,Redis 和 MySQL 的区别,本质上就是内存数据库磁盘数据库,以及键值存储关系型存储的根本差异。

我用一个对比表格先给你一个全景图,然后再针对几个核心点展开聊聊。

Redis和MySQL的区别

Reids是内存型的非关系型数据库,速度快不安全;

MySQL是使用磁盘存储的关系型数据库 ,速度慢安全;

Redis替MySQL抗高并发,节省成本

全景对比:一张表看懂核心区别

对比维度

Redis

MySQL

存储介质

内存 (为主) + 磁盘(持久化备份)

磁盘 (为主) + 内存(buffer)

读写速度

极快 (微秒级,约 10万+ QPS)

较慢 (毫秒级,约 1-2k QPS)

数据模型

Key-Value,支持 5 种以上复杂结构 (String/List/Hash/Set/ZSet)

二维表 (Table),严格的行与列,通过 SQL 操作

事务支持

弱事务 (仅保证单个命令原子性,不支持回滚)

强事务 (支持 ACID,严格回滚)

数据安全

易丢失 (宕机可能丢数秒数据,依赖持久化配置)

持久化 (写入即落盘,数据极其安全)

扩展性

水平扩展 (主从、集群模式)

垂直扩展为主 (读写分离、分库分表较复杂)

查询能力

依赖 Key 查询,不支持复杂条件筛选 (除非用 Scan)

SQL 引擎,支持多表 JOIN、聚合、子查询、条件过滤

主要用途

缓存、高性能计数器、分布式锁、消息队列

业务数据存储 (订单、用户、商品等核心元数据)

核心差异深入解读

上面表格是总览,下面这四个点是它们最根本的不同:

  1. 快慢的根本原因:内存 vs. 磁盘

    • Redis:数据常驻内存。内存的随机读写速度是 纳秒级 (ns),几乎等同于 CPU 处理速度。这就是它为什么能抗住 10 万级并发的物理基础。

    • MySQL:数据在磁盘。即便有 Buffer Pool 缓存,一旦涉及 fsync 落盘或磁盘寻道,速度就是 毫秒级 (ms)两者速度差距在 1000 倍以上

  2. 数据结构:万能瑞士军刀 vs. 严谨的 Excel 表格

    • Redis:它不只是存字符串。List 可以做最新消息队列,Hash 存对象,Zset 做排行榜。这些结构在内存中都是指针操作,时间复杂度 O(1),即取即用,无需像 MySQL 那样建索引。

    • MySQL:数据必须规整为行和列。要查数据得先建 B+ 树索引,即使命中索引,也要在磁盘上寻址,复杂度相对较高。

  3. 安全与一致性:闪电速度 vs. 绝对可靠 这是选型时的核心权衡:

    • Redis:为了快,它牺牲了安全性。默认异步持久化,如果服务器突然断电,最近几秒(取决于 save 策略)的数据可能就永久丢失了。

    • MySQL:银行转账、订单扣库存这类场景,钱不能丢,必须用 Redo Log 和 Binlog 保证事务持久化(ACID 中的 D)。

  4. 查询能力的差异:精准Key查询 vs. 灵活SQL

    • Redis:查询严重依赖 Key。如果你想知道“年龄 25 岁且城市在北京的用户”,在 Redis 里几乎无法直接查,除非你专门维护一个 Set 集合。

    • MySQL:可以用一条 SELECT * FROM user WHERE age=25 AND city='beijing' 轻松搞定,利用 SQL 引擎进行复杂运算。


实际开发中的经典组合

在生产环境中,它们是对好搭档,而不是对手。最经典的架构是:

MySQL 负责“写”和绝对数据存储,Redis 负责“读”和高速访问。

当用户请求一个商品详情:

  1. 先查 Redis 缓存,如果有就直接返回(极速)。

  2. 如果 Redis 没有(缓存未命中),再去查 MySQL 磁盘(较慢)。

  3. 将 MySQL 查出的结果写入 Redis,下一次用户再查就直接命中缓存了。

这就是 “缓存旁路模式 (Cache-Aside Pattern)”,也是目前绝大多数互联网高并发系统的标准解法。

Redis常用命令

. 通用命令(所有类型通用)

命令

作用

示例

PING

测试连接是否正常

PING → 返回 PONG

SELECT

切换数据库(默认16个,索引0-15)

SELECT 1

KEYS

查看所有key(生产禁用的危险命令

KEYS user:*

SCAN

安全的游标遍历key(替代KEYS)

SCAN 0 MATCH user:* COUNT 100

EXISTS

判断key是否存在

EXISTS user:1001

DEL

删除key

DEL user:1001

UNLINK

异步删除(不阻塞主线程,推荐)

UNLINK large:key

EXPIRE

设置过期时间(秒)

EXPIRE session:abc 3600

TTL

查看剩余存活时间(-1永久,-2不存在)

TTL session:abc

TYPE

查看key的数据类型

TYPE user:1001

2. String(字符串)——最常用

适合存缓存对象(JSON)、计数器、分布式锁。

命令

作用

示例

SET

设置值(可带过期时间)

SET user:1001 '{"name":"张三"}' EX 600

GET

获取值

GET user:1001

SETNX

键不存在时才设置(实现分布式锁

SETNX lock:order 1

INCR

自增1(原子操作)

INCR view:article:888

DECR

自减1

DECR stock:iphone

MSET

批量设置(减少网络开销)

MSET a 1 b 2 c 3

MGET

批量获取

MGET a b c

3. Hash(哈希)——适合存对象/记录

适合存用户信息、商品详情、配置项。

命令

作用

示例

HSET

设置字段值

HSET user:1001 name "张三" age 25

HGET

获取单个字段

HGET user:1001 name

HGETALL

获取所有字段和值(字段多时慎用

HGETALL user:1001

HMGET

获取多个字段

HMGET user:1001 name age

HINCRBY

字段值自增

HINCRBY user:1001 score 5

HEXISTS

判断字段是否存在

HEXISTS user:1001 email

HDEL

删除字段

HDEL user:1001 email

4. List(列表)——适合消息队列/最新动态

有序,可重复,适合做最新消息、简单队列。

命令

作用

示例

LPUSH

从左侧插入(头部)

LPUSH msgs "hello"

RPUSH

从右侧插入(尾部)

RPUSH msgs "world"

LPOP

从左侧弹出

LPOP msgs

RPOP

从右侧弹出

RPOP msgs

LRANGE

获取指定范围元素

LRANGE msgs 0 -1 (获取全部)

LLEN

获取列表长度

LLEN msgs

BRPOP

阻塞弹出(队列为空时等待,实现生产者-消费者)

BRPOP taskQueue 5 (等5秒)

5. Set(集合)——适合去重/交集/抽奖

无序,不重复,适合共同好友、标签、抽奖池。

命令

作用

示例

SADD

添加元素

SADD tags:article:1 "Redis" "Java"

SREM

删除元素

SREM tags:article:1 "Java"

SMEMBERS

获取所有元素(元素多时慎用

SMEMBERS tags:article:1

SISMEMBER

判断元素是否存在

SISMEMBER tags:article:1 "Redis"

SCARD

获取集合大小

SCARD tags:article:1

SINTER

取多个集合的交集(如共同好友)

SINTER friends:A friends:B

SPOP

随机弹出元素(如抽奖)

SPOP luckyPool 1

6. ZSet(有序集合)——排行榜首选

每个元素带分数,按分数自动排序。

命令

作用

示例

ZADD

添加元素并指定分数

ZADD ranking 1000 "user:张三"

ZINCRBY

增加元素分数

ZINCRBY ranking 10 "user:张三"

ZRANGE

按分数从小到大取元素(带分数)

ZRANGE ranking 0 9 WITHSCORES

ZREVRANGE

按分数从大到小取元素(排行榜常用

ZREVRANGE ranking 0 9 WITHSCORES

ZRANK

获取元素排名(从小到大)

ZRANK ranking "user:张三"

ZREVRANK

获取元素排名(从大到小)

ZREVRANK ranking "user:张三"

ZREM

删除元素

ZREM ranking "user:张三"

ZCOUNT

统计分数在区间内的元素数量

ZCOUNT ranking 80 100

7. 管理与维护命令

命令

作用

示例

INFO

查看服务器统计信息(内存、连接、命中率等)

INFO stats

DBSIZE

查看当前数据库key数量

DBSIZE

FLUSHDB

清空当前数据库(危险

FLUSHDB

FLUSHALL

清空所有数据库(极其危险

FLUSHALL

CONFIG GET

获取配置参数

CONFIG GET maxmemory

MONITOR

实时监控所有命令(调试用,生产慎用

MONITOR

SLOWLOG

查看慢查询日志

SLOWLOG GET 10

🔥 开发中最常用的命令组合

场景

推荐命令组合

缓存对象

SET key JSON EX 600 + GET key

分布式锁

SETNX lock:xxx 1 + DEL lock:xxx(配合过期时间)

排行榜

ZINCRBY rank 1 "user" + ZREVRANGE rank 0 9

消息队列

LPUSH queue msg + BRPOP queue 0

去重统计

SADD view:article:888 uid + SCARD view:article:888

计数器

INCR visitCount + GET visitCount

⚠️ 两个必须牢记的禁忌

  1. 绝对不要在生产用 KEYS \*:会阻塞Redis数秒甚至分钟,导致所有请求超时。用 SCAN 替代。

  2. 不要用 HGETALLSMEMBERS 取大key:如果一个Hash有百万字段,这个命令会把整个内存数据一次性传输,导致网络阻塞。用 HSCANSSCAN 分批取。

Redis数据类型与作用

类型

底层数据结构

一句话作用

最典型业务场景

String (字符串)

SDS (简单动态字符串)

存储单个值,如文本、数字、二进制流

缓存对象、计数器、分布式锁、Session 共享

Hash (哈希)

压缩列表或哈希表

存储一个对象的多个属性,像是一张微型数据表

用户信息、购物车、商品详情页

List (列表)

压缩列表或双向链表

存储有序的字符串列表,支持两端操作

消息队列、最新动态列表(如评论)、日志收集

Set (集合)

哈希表或整数集合

存储无序且唯一的字符串集合

标签系统、去重统计、抽奖、共同好友/关注关系

ZSet (有序集合)

压缩列表或跳表

存储带分数(权重)的有序集合,按分数排序

排行榜(如销量榜、热度榜)、延迟队列、带权重的任务调度

接下来,我来详细拆解每个类型的核心作用和需要注意的“坑”。

1. String (字符串) —— 万能的基石

String 不只是存字符串,它还能存整数、浮点数,甚至图片或序列化对象的二进制数据(值最大支持 512MB)。

  • 核心作用

    • 缓存对象:将用户信息、商品详情等对象序列化成 JSON 字符串存储,减轻数据库压力。

    • 计数器:利用 INCRDECR 命令,实现原子性的点赞数、阅读数、库存扣减。

    • 分布式锁:利用 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