文章目录
- Redis基础入门
-
- [一、 Redis 基础特性与架构认知](#一、 Redis 基础特性与架构认知)
-
- [1. NoSQL 数据库分类及特点](#1. NoSQL 数据库分类及特点)
- [2. Redis 核心高性能密码](#2. Redis 核心高性能密码)
- [3. 全局通用基础命令与帮助系统](#3. 全局通用基础命令与帮助系统)
- [二、 核心数据类型详解与底层原理](#二、 核心数据类型详解与底层原理)
-
- [(一) String 字符串结构](#(一) String 字符串结构)
-
- [1. 底层原理:SDS (Simple Dynamic String)](#1. 底层原理:SDS (Simple Dynamic String))
- [2. 常用基础命令全集](#2. 常用基础命令全集)
- [3. 生产环境应用场景深度解析](#3. 生产环境应用场景深度解析)
- [(二) Hash 哈希结构](#(二) Hash 哈希结构)
-
- [1. 底层原理:ziplist (压缩列表) / listpack → \rightarrow → hashtable (哈希表)](#1. 底层原理:ziplist (压缩列表) / listpack → \rightarrow → hashtable (哈希表))
- [2. 常用基础命令全集](#2. 常用基础命令全集)
- [3. 购物车场景深化与优缺点](#3. 购物车场景深化与优缺点)
- [(三) List 列表类型](#(三) List 列表类型)
-
- [1. 底层原理:quicklist (快速列表)](#1. 底层原理:quicklist (快速列表))
- [2. 常用基础命令全集](#2. 常用基础命令全集)
- [3. List 模拟常见数据结构与缺陷](#3. List 模拟常见数据结构与缺陷)
- [(四) Set 集合类型](#(四) Set 集合类型)
-
- [1. 特性与底层原理](#1. 特性与底层原理)
- [2. 常用基础命令全集](#2. 常用基础命令全集)
- [3. 生产环境大 key 警告](#3. 生产环境大 key 警告)
- [(五) ZSet 有序集合类型](#(五) ZSet 有序集合类型)
-
- [1. 特性与底层原理](#1. 特性与底层原理)
- [2. 常用基础命令全集](#2. 常用基础命令全集)
- [3. 经典排行榜场景深度设计](#3. 经典排行榜场景深度设计)
Redis基础入门
一、 Redis 基础特性与架构认知
1. NoSQL 数据库分类及特点
- 键值型 (Key-Value): Redis。极高的读写性能,常用于缓存、分布式锁。
- 列族跨度 (Column-Family): HBase。基于 Google Bigtable,适合海量数据存储与实时随机读写。
- 图形数据库 (Graph): Neo4j。专注于社交网络、风控等复杂关系网络的图遍历。
- 文档型 (Document): MongoDB 、Elasticsearch。
- MongoDB: 灵活的 JSON 文档结构,适合 Schema 经常变动的业务。
- Elasticsearch : 基于倒排索引 (Inverted Index),专为全文检索和大数据分析而生。
2. Redis 核心高性能密码
-
纯内存操作: 所有数据存放在内存中,内存响应时间约为 100 纳秒,这是 Redis 极高的根本原因。
-
单线程模型 (核心机制): Redis 的核心网络 I/O 和键值对读写是由单个线程完成的。
-
优势: 避免了不必要的上下文切换和锁竞争。
-
注意 : Redis 6.0 之后引入了 多线程 I/O,但它只用来处理网络数据的读写和协议解析,执行命令的核心依然是单线程。
-
I/O 多路复用 (Multiplexing): 采用 epoll 机制,使单个线程能够高效监听数万个客户端连接,不阻塞在某一个特定的网络连接上。
3. 全局通用基础命令与帮助系统
bash
# 查看当前数据库中的所有 Key(线上生产环境严禁使用,会造成单线程卡死)
KEYS *
# 检查指定 Key 是否存在。返回 1 表示存在,0 表示不存在
EXISTS key
# 返回 Key 所存储的数据类型(如 string, hash, list, set, zset)
TYPE key
# 删除一个或多个指定 Key。返回成功删除的个数
DEL key [key ...]
# 清空当前数据库中的所有 key
FLUSHDB
# 清空所有数据库的所有 key(全删,生产环境高危命令)
FLUSHALL
# 退出当前客户端连接
QUIT
万能帮助系统 (help)
bash
# 查看某个分组下的所有命令(例如 help @string, help @hash)
help @<group>
# 查看具体某个命令的详细语法帮助(例如 help set)
help <command>
# 在命令行连续按 Tab 键,可循环切换查看可用的帮助主题
help <tab>
二、 核心数据类型详解与底层原理
(一) String 字符串结构
1. 底层原理:SDS (Simple Dynamic String)
Redis 没有直接使用 C 语言的传统字符串(以 \0 结尾的字符数组),而是自己构建了简单动态字符串 (SDS)。
为什么用 SDS?
- 常数复杂度获取长度: C 字符串需要 O ( n ) O(n) O(n) 遍历,SDS 内部维护了
len属性,获取长度只需 O ( 1 ) O(1) O(1)。- 杜绝缓冲区溢出: SDS 在拼接字符串时会先检查空间是否足够,不足则自动扩容。
- 减少内存重分配次数: 采用空间预分配和惰性空间释放机制。
- 二进制安全: 允许存储包含空字符
\0的图片、音频等二进制数据。
2. 常用基础命令全集
bash
# 存储一个键值对。EX/PX:设置秒级/毫秒级过期时间;NX:键不存在才设置;XX:键存在才设置
SET key value [EX seconds|PX milliseconds] [NX|XX]
# 获取指定 Key 的 Value。若不存在返回 nil
GET key
# 批量存储多个键值对(原子操作)
MSET key value [key value ...]
# 批量获取多个 Key 的 Value
MGET key [key ...]
# 存入一个不存在的字符串键值对。存在则什么都不做(成功返回 1,失败返回 0)
SETNX key value
# 设置一个新键值对,并直接指定过期时间(秒)
SETEX key seconds value
# 给一个现有的 Key 设置过期时间(秒)
EXPIRE key seconds
# 查看 Key 的剩余生存时间(秒)。返回 -1 表示永不过期,-2 表示 Key 不存在
TTL key
# 【原子加减命令】将 Key 储存的数字值加 1。如果 Key 不存在,会先初始化为 0 再加 1
INCR key
# 将 Key 储存的数字值减 1
DECR key
# 将 Key 储存的数字值加上指定的整型增量值
INCRBY key increment
# 将 Key 储存的数字值减去指定的整型减量值
DECRBY key decrement
# 对浮点数进行原子增加(String 也能存浮点数)
INCRBYFLOAT key increment
3. 生产环境应用场景深度解析
-
单值缓存:
SET key value、GET key。 -
对象缓存(两种主流设计):
-
方式一(整存整取 JSON) :
SET user:1 '{"name":"roy","balance":1888}' -
方式二(高频更新字段) :
MSET user:1:name roy user:1:balance 1888→ \rightarrow → 获取时MGET user:1:name user:1:balance -
分布式锁的完整闭环:
-
加锁(带超时防死锁) :
SET lock:product:10001 random_value EX 10 NX -
高阶注意点 : 释放锁时不能直接
DEL。如果 A 业务超时,锁自动释放,B 拿到了锁;此时 A 执行完去DEL,会把 B 的锁删掉。正确做法: 比较random_value是否一致,一致再删除,这个复合操作必须使用 Lua 脚本 保证原子性。 -
大值拆分 (BigKey 规避): String 的 Value 最大为 512MB ,但生产环境建议控制在 10KB 以内,否则会引发网络阻塞和 Redis 变慢。
(二) Hash 哈希结构
1. 底层原理:ziplist (压缩列表) / listpack → \rightarrow → hashtable (哈希表)
- 当 Hash 的字段少且值小时,为了极端节省内存,底层使用
ziplist(新版本为listpack),它是一块连续的内存。 - 当元素个数超过
hash-max-ziplist-entries(默认 512)或某个 Value 大于hash-max-ziplist-value(默认 64 字节)时,自动转为hashtable(类似于 Java 的 HashMap,具有 O ( 1 ) O(1) O(1) 复杂度)。
2. 常用基础命令全集
bash
# 存储哈希表单个字段的键值对
HSET key field value
# 获取哈希表中指定字段的值
HGET key field
# 仅当哈希表中该字段不存在时才存储
HSETNX key field value
# 批量存储哈希表的多个字段(注:新版 HSET 已支持批量,等同于 HMSET)
HMSET key field value [field value ...]
# 批量获取哈希表多个字段的值
HMGET key field [field ...]
# 删除哈希表中的一个或多个指定字段
HDEL key field [field ...]
# 返回哈希表中字段(field)的数量
HLEN key
# 返回哈希表中所有的键值对(生产环境严禁在大 Key 上执行,若 field 太多会阻塞单线程)
HGETALL key
# 获取哈希表中的所有字段名(field)
HKEYS key
# 获取哈希表中的所有值(value)
HVALS key
# 给哈希表指定字段的数值增加一个整型增量
HINCRBY key field increment
# 增量式迭代获取哈希表内容,生产环境用来代替 HGETALL 的安全命令
HSCAN key cursor [MATCH pattern] [COUNT count]
3. 购物车场景深化与优缺点
-
用户购物车高级设计:
-
Key:cart:user:1001(用户ID) -
Field:10088(商品 SkuID) → \rightarrow →Value:1(数量) -
添加/增加数量 :
HINCRBY cart:1001 10088 1 -
统计商品总数 :
HLEN cart:1001 -
删除商品 :
HDEL cart:1001 10088 -
获取全车商品 :
HGETALL cart:1001 -
优点: 同类数据归类整合,方便管理;相比 String,CPU、内存消耗更小,存储空间更节省。
-
缺点: 过期时间只能作用在大 key 上,不能给 field 单独设置过期时间;在 Redis 集群架构下不适合大规模使用(容易导致数据倾斜)。
(三) List 列表类型
1. 底层原理:quicklist (快速列表)
- 老版本底层为
ziplist和linkedlist(双向链表),支持正负索引(正数从 0 开始,负数从 -1 倒序)。 - 现行版本统一采用
quicklist。quicklist是一个双向链表,但链表中的每个节点都是一个ziplist。既有链表两端操作快的优势,又避免了普通链表节点前后指针过度占用内存的问题(双端操作性能极高,中间索引操作性能低)。
2. 常用基础命令全集
bash
# 从列表表头(左端)插入一个或多个元素
LPUSH key value [value ...]
# 从列表表尾(右端)插入一个或多个元素
RPUSH key value [value ...]
# 移除并返回列表的表头(左端)元素
LPOP key
# 移除并返回列表的表尾(右端)元素
RPOP key
# 获取指定索引区间内的元素(例如 LRANGE list 0 -1 代表获取全部元素)
LRANGE key start stop
# 获取列表的长度
LLEN key
# 【阻塞式命令】表头阻塞弹出。如果队列无元素则进入阻塞等待,timeout 为最大等待时间(秒),设为 0 表示永久阻塞
BLPOP key [key ...] timeout
# 表尾阻塞弹出。长轮询机制,数据一到立刻感知,几乎零延迟
BRPOP key [key ...] timeout
3. List 模拟常见数据结构与缺陷
-
数据结构组合拳:
-
栈 (Stack) =
LPUSH+LPOP -
队列 (Queue) =
LPUSH+RPOP -
阻塞队列 (MQ) =
LPUSH+BRPOP -
致命缺陷:
- 没有 ACK 机制: 一旦消息通过
RPOP/BRPOP弹出,如果消费者在处理过程中崩溃,消息就彻底丢失了。 - 不支持一条消息多方消费: 一个消息只能被一个消费者 Pop 走。
- 注意点: 列表最大容量为 2 32 − 1 2^{32}-1 232−1(约 40 亿元素),在实际开发中需要警惕大 Key 问题。
(四) Set 集合类型
1. 特性与底层原理
- 特性: 元素无序、不可重复。
- 底层原理(intset → \rightarrow → hashtable): 如果集合内元素都是整数,且数量较少,底层使用
intset(一块连续且高度紧凑的内存)。一旦存入字符串,或者元素数量超标,立刻转为hashtable(Value 均为 null 的散列表)。
2. 常用基础命令全集
bash
# 向集合内存入元素,重复的元素会自动被忽略
SADD key member [member ...]
# 从集合中删除一个或多个元素
SREM key member [member ...]
# 获取集合中的所有元素(无序)
SMEMBERS key
# 获取集合中元素的总个数
SCARD key
# 判断某个元素是否在集合中(返回 1 在,0 不在)
SISMEMBER key member
# 随机从集合中获取指定个数的元素,不删除原集合元素(常用于抽奖不剔除资格)
SRANDMEMBER key [count]
# 随机从集合中弹出指定个数的元素(常用于抽奖且中奖人不能重复中奖)
SPOP key [count]
# 【集合运算命令-交集】计算多个集合的交集
SINTER key [key ...]
# 计算交集并将结果存入新集合 destination 中
SINTERSTORE destination key [key ...]
# 【集合运算命令-并集】计算多个集合的并集
SUNION key [key ...]
# 计算并集并将结果存入新集合
SUNIONSTORE destination key [key ...]
# 【集合运算命令-差集】计算多个集合的差集(注意顺序:以第一个 key 集合为主体)
SDIFF key [key ...]
# 计算差集并将结果存入新集合
SDIFFSTORE destination key [key ...]
3. 生产环境大 key 警告
- 避坑指南: 集合计算的时间复杂度较高(如交集为 O ( N × M ) O(N \times M) O(N×M))。若集合内元素达到千万级,直接执行交并集运算会导致 Redis 瞬间卡死。
- 正确实践: 将数据带回客户端(Java/Go)在业务层计算,或者使用
SINTERSTORE将结果异步存入新集合。
(五) ZSet 有序集合类型
1. 特性与底层原理
- 特性: 元素不可重复,每个元素关联一个
score(分值),按分值从小到大自动排序。 - 底层原理(ziplist/listpack → \rightarrow → skiplist + dict):
dict(哈希表): 用来建立member -> score的映射,保证根据元素找分数达到 O ( 1 ) O(1) O(1)。skiplist(跳跃表): 用于根据分数排序。它通过在普通链表上建立多层索引,实现类似二分查找的效果,检索复杂度为 O ( log N ) O(\log N) O(logN)。
2. 常用基础命令全集
bash
# 添加一个或多个带分值的元素。如果元素已存在,则更新其分数
ZADD key score member [[score member] ...]
# 从有序集合中删除一个或多个元素
ZREM key member [member ...]
# 获取指定元素的分值
ZSCORE key member
# 给指定元素的分值增加一个增量值(可为负数)
ZINCRBY key increment member
# 获取有序集合中元素的总个数
ZCARD key
# 获取索引区间内的元素。WITHSCORES 连同分数一起返回;REV 代表倒排(从大到小)
ZRANGE key start stop [WITHSCORES] [REV]
# 【集合运算-并集】计算多个有序集合的并集并存入新 Key。numkeys 指定参与计算的 Key 数量
ZUNIONSTORE destkey numkeys key [key ...] [WEIGHTS weight ...] [AGGREGATE SUM|MIN|MAX]
# 【集合运算-交集】计算交集并存入新 Key
ZINTERSTORE destkey numkeys key [key ...] [WEIGHTS weight ...] [AGGREGATE SUM|MIN|MAX]
参数解释:
WEIGHTS可以设置各个集合的乘法权重比;AGGREGATE可以设置当成员分值重复时,最终分值是求和(SUM)、取最小值(MIN)还是最大值(MAX)。
3. 经典排行榜场景深度设计
- 多维权重聚合(如:7日榜单合并):
redis
# 合并 7 天的每日热点数据,分值求和
ZUNIONSTORE hotNews:7day 7 hotNews:day1 hotNews:day2 hotNews:day3 hotNews:day4 hotNews:day5 hotNews:day6 hotNews:day7 WEIGHTS 1 1 1 1 1 1 1 AGGREGATE SUM
# 合并后展示前十名
ZRANGE hotNews:7day 0 9 WITHSCORES REV