Redis基础入门

一、 Redis 基础特性与架构认知

1. NoSQL 数据库分类及特点

  • 键值型 (Key-Value): Redis。极高的读写性能,常用于缓存、分布式锁。
  • 列族跨度 (Column-Family): HBase。基于 Google Bigtable,适合海量数据存储与实时随机读写。
  • 图形数据库 (Graph): Neo4j。专注于社交网络、风控等复杂关系网络的图遍历。
  • 文档型 (Document): MongoDBElasticsearch
  • MongoDB: 灵活的 JSON 文档结构,适合 Schema 经常变动的业务。
  • Elasticsearch: 基于倒排索引 (Inverted Index),专为全文检索和大数据分析而生。

2. Redis 核心高性能密码

  • 纯内存操作: 所有数据存放在内存中,内存响应时间约为 100 纳秒,这是 Redis 极高的根本原因。

  • 单线程模型 (核心机制): Redis 的核心网络 I/O 和键值对读写是由单个线程完成的。

  • 优势: 避免了不必要的上下文切换和锁竞争。

  • 注意: Redis 6.0 之后引入了 多线程 I/O,但它只用来处理网络数据的读写和协议解析,执行命令的核心依然是单线程。

  • I/O 多路复用 (Multiplexing): 采用 epoll 机制,使单个线程能够高效监听数万个客户端连接,不阻塞在某一个特定的网络连接上。

3. 全局通用基础命令与帮助系统

# 查看当前数据库中的所有 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)
# 查看某个分组下的所有命令(例如 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. 常用基础命令全集
# 存储一个键值对。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 valueGET 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. 常用基础命令全集
# 存储哈希表单个字段的键值对
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 (快速列表)
  • 老版本底层为 ziplistlinkedlist(双向链表),支持正负索引(正数从 0 开始,负数从 -1 倒序)。
  • 现行版本统一采用 quicklistquicklist 是一个双向链表,但链表中的每个节点都是一个 ziplist。既有链表两端操作快的优势,又避免了普通链表节点前后指针过度占用内存的问题(双端操作性能极高,中间索引操作性能低)。
2. 常用基础命令全集
# 从列表表头(左端)插入一个或多个元素
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

  • 致命缺陷:

  1. 没有 ACK 机制: 一旦消息通过 RPOP/BRPOP 弹出,如果消费者在处理过程中崩溃,消息就彻底丢失了。
  2. 不支持一条消息多方消费: 一个消息只能被一个消费者 Pop 走。
  • 注意点: 列表最大容量为 2 32 − 1 2^{32}-1 2321(约 40 亿元素),在实际开发中需要警惕大 Key 问题。

(四) Set 集合类型

1. 特性与底层原理
  • 特性: 元素无序、不可重复。
  • 底层原理(intset → \rightarrow hashtable): 如果集合内元素都是整数,且数量较少,底层使用 intset(一块连续且高度紧凑的内存)。一旦存入字符串,或者元素数量超标,立刻转为 hashtable(Value 均为 null 的散列表)。
2. 常用基础命令全集
# 向集合内存入元素,重复的元素会自动被忽略
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. 常用基础命令全集
# 添加一个或多个带分值的元素。如果元素已存在,则更新其分数
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日榜单合并):
# 合并 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

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐