4.1.1 Redis相关命令详解及其原理
文章目录
- 1. Redis是什么
- 1. Redis 的核心特性
- **数据存储在内存中**
- **KV(键值)存储 + 多种数据结构**
- 2. 工作模式:请求-响应模型
- 3. 和 MySQL 的区别
- 2. 应用
- 3. 安装编译及启动
- 4. redis是怎么组织数据的
- 1. redis的存储结构是什么:
- 2. 为什么redis中字符串选择64个字节为分界线
- 5. redis的value编码
- 1. string 类型(最常见)
- 2. list 类型
- 3. hash 类型
- 4. set 类型
- 5. zset(有序集合)
- 6. string
- 1. 基础命令
- 2. 存储结构
- 3. 应用
- 1. 对象存储
- 2. 累加器
- 4. 分布式锁
- 5. 位运算
- 7. list
- 1. 基础命令
- 2. 存储结构
- 3. 应用
- 1. 栈
- 2. 队列
- 3. 阻塞队列
- 4. 异步消息队列
- 5. 获取固定窗口记录
- 记录最近 N 次登录行为
- 6. 总结一下
- 8. hash
- 1. 基础命令
- 2. 存储结构
- 3. 应用
- 9. set
- 1. 基础命令
- 2. 存储结构
- 3. 应用
1. Redis是什么
Redis(Remote Dictionary Server) 是一个开源的、基于内存的 键值型 NoSQL 数据库,支持丰富的数据结构和高性能的操作。
1. Redis 的核心特性
数据存储在内存中
- 所有数据保存在内存中,访问速度非常快(微秒级)。
- 可选持久化机制(RDB 快照、AOF 日志)可以将数据写入磁盘以防丢失。
KV(键值)存储 + 多种数据结构
- Redis 不只是传统的 key → string,它还支持:list,hash,set,zset等
2. 工作模式:请求-响应模型
Redis 基于 客户端-服务器模型:
客户端发送请求(如 GET、SET)
→ Redis 处理请求(在内存中)
→ Redis 立即返回响应(低延迟)
3. 和 MySQL 的区别
项目 | Redis | MySQL |
---|---|---|
存储介质 | 内存为主(可持久化) | 磁盘 |
数据模型 | 键值+多结构 | 表格+关系型 |
性能 | 高速,适合缓存 | 较慢,适合存储 |
使用场景 | 缓存、排行榜、消息队列 | 持久化存储、复杂查询 |
支持事务 | 基础事务支持 | 完整事务机制(ACID) |
2. 应用
Redis 的常见数据结构 & 用途对照表
数据结构 | 说明 | 常见使用场景 |
---|---|---|
String | 最基本的数据类型,最大512MB | 缓存单个值、计数器、锁标记 |
List | 链表结构,可从两端 push/pop | 消息队列(先进先出)、任务列表 |
Set | 无序不重复元素集合 | 标签系统、好友列表、去重 |
Sorted Set(ZSet) | 带权重的集合,可排序 | 排行榜、优先队列、打分系统 |
3. 安装编译及启动
#下载源码
wget http://download.redis.io/releases/redis-7.2.4.tar.gz
tar -xzf redis-7.2.4.tar.gz
cd redis-7.2.4
#编译
make -j4 # -j4 表示用4线程并行编译# 默认安装在 /usr/local/bin
# redis-server 是服务端程序
# redis-cli 是客户端程序#启动
mkdir redis-data
# 把redis文件夹下 redis.conf 拷贝到 redis-data
# 修改 redis.conf
vim redis.conf
requirepass 123456
./src/redis-server redis.conf
#用这个配置文件启动
# daemonize yescd redis-data
redis-server ./redis.conf
# 通过 redis-cli 访问 redis-server
redis-cli -h 127.0.0.1 -a 123456#断开就输入
exit
4. redis是怎么组织数据的
1. redis的存储结构是什么:
v-数据结构的选择,特性,典型应用
k-设计有意义的字段,方便查询
Redis 是典型的 键值对(Key-Value)数据库,支持丰富的数据结构,不再是简单的字符串键值
每一个键值对的本质是:
dict<key, redisObject* value>
key
:通常是字符串(SDS)value
:是一个redisObject
指针,内部根据实际类型存储数据
比如:
2. 为什么redis中字符串选择64个字节为分界线
原因 | 说明 |
---|---|
内存分配优化 | 小于64字节的字符串能映射到更小的内存块,避免浪费 |
CPU缓存优化 | 64字节正好是cache line大小,提高访问效率 |
SDS优化策略 | Redis会针对短字符串启用更激进的性能优化策略 |
内存碎片控制 | 避免频繁内存分配、释放引起的碎片化 |
5. redis的value编码
Redis 会根据 数据的类型 + 内容大小 + 特性 来动态选择最优的编码方式,既省内存又加快速度
1. string 类型(最常见)
编码方式 | 触发条件 | 特性 |
---|---|---|
int | 值是整型,且可以转成 long | 最省内存(直接用 long 存) |
embstr | 字符串长度 ≤ 44 字节 | 分配一块连续内存,CPU cache 友好,性能极高 |
raw | 字符串长度 > 44 字节 | 普通字符串编码(sds + object 分开) |
备注:Redis 的 embstr 就是为了让短字符串更高效
2. list 类型
编码方式 | 触发条件 | 特性 |
---|---|---|
quicklist(默认) | Redis 3.2 之后统一使用 quicklist | 底层是 ziplist + 双向链表压缩组合 |
ziplist(已淘汰) | 旧版本才有 | 紧凑结构,节省空间,O(n) 访问 |
3. hash 类型
编码方式 | 触发条件 | 特性 |
---|---|---|
ziplist | 元素个数 < 512 且 field/value 长度都 < 64 字节 | 紧凑,省空间 |
hashtable | 超过阈值 | 标准哈希表,支持 O(1) 操作 |
4. set 类型
编码方式 | 触发条件 | 特性 |
---|---|---|
intset | 所有元素都是整数,数量 < 512 个 | 紧凑的整数集合,支持二分查找 |
hashtable | 含有非整数 或 数量多 | 哈希表实现,查找更快 |
5. zset(有序集合)
编码方式 | 触发条件 | 特性 |
---|---|---|
ziplist | 元素个数 ≤ 128 且每个元素 < 64 字节 | 空间紧凑,适合小集合 |
skiplist(跳表) | 超过阈值 | 支持范围查询,有序插入,查找快 |
其实上面说的这些东西我完全不知道在干什么
6. string
1. 基础命令
命令 | 功能说明 |
---|---|
SET key value | 设置键的值 |
GET key | 获取键的值 |
SETEX key seconds value | 设置键并指定过期时间 |
INCR key / DECR key | 数值型累加 / 累减 |
INCRBY key n / DECRBY key n | 按指定数值增减 |
APPEND key value | 追加内容到原字符串 |
STRLEN key | 获取字符串长度 |
GETRANGE key start end | 获取指定范围的子串 |
SETRANGE key offset value | 替换子串 |
2. 存储结构
SDS(Simple Dynamic String)结构实现的,支持二进制安全
3. 应用
1. 对象存储
SET user:1001:name "Alice"
SET user:1001:email "alice@example.com"
2. 累加器
#每次访问首页,PV +1。Redis 的原子性保证不会丢数据
INCR page:view:index#视频 123 的点赞数累加。结合用户状态防止重复点赞
INCR video:123:likes
4. 分布式锁
#某个后台任务抢占锁执行,保证同一任务在同一时间只被一个节点执行
SET lock:task:sendEmail "UUID-xyz" NX EX 30
5. 位运算
#第 0 位表示 4月15日是否签到,1 表示已签;可以每天一个 key,也可以一人一个 key
SETBIT sign:20250415:user:1001 0 1 # 表示今天已签到#统计某月有多少用户签到过,即位为 1 的总数
BITCOUNT sign:202504:user
7. list
1. 基础命令
命令 | 功能说明 |
---|---|
LPUSH key value | 从左侧插入(头插) |
RPUSH key value | 从右侧插入(尾插) |
LPOP key | 弹出左边第一个元素 |
RPOP key | 弹出右边第一个元素 |
LRANGE key start stop | 获取指定范围内的元素 |
LLEN key | 获取列表长度 |
LREM key count value | 删除指定值的元素(count 控制次数) |
LTRIM key start stop | 截取指定范围,保留该范围 |
LSET key index value | 设置索引位置的值 |
LINDEX key index | 获取指定索引的元素 |
BLPOP key [key2...] timeout | 阻塞式左弹出(多个 key) |
BRPOP key [key2...] timeout | 阻塞式右弹出 |
2. 存储结构
使用 quicklist
(多个 ziplist + 双向链表组合)更高效
3. 应用
1. 栈
后进先出
#LPUSH 插入最新访问记录,LPOP 弹出最近的页面,模拟栈行为
LPUSH history:user:1001 "pageA"
LPUSH history:user:1001 "pageB"
LPOP history:user:1001
2. 队列
先进先出
#RPUSH 添加任务,LPOP 从左边取任务,实现先进先出逻辑
RPUSH queue:email "task1"
RPUSH queue:email "task2"
LPOP queue:email
3. 阻塞队列
#如果队列为空,阻塞最多 30 秒,适合高并发任务消费者等待模式
BLPOP queue:email 30
4. 异步消息队列
#结合生产/消费模型,通过 List 实现轻量级消息队列,支持异步处理和消费速度差异
# 生产者写入日志消息
RPUSH logs:system "log1"
RPUSH logs:system "log2"# 消费者阻塞式读取
BLPOP logs:system 0
5. 获取固定窗口记录
记录最近 N 次登录行为
#每次登录都插入新记录,只保留前 N 条,模拟滑动窗口效果
LPUSH login:user:1001 "2025-04-15T10:00"
LTRIM login:user:1001 0 4 # 保留最近5条
6. 总结一下
类别 | 案例 | 命令 | 描述 |
---|---|---|---|
栈 | 浏览历史 | LPUSH + LPOP | 后进先出 |
队列 | 邮件任务 | RPUSH + LPOP | 先进先出 |
阻塞队列 | 消费任务 | BLPOP | 无任务阻塞等待 |
异步消息队列 | 日志系统 | RPUSH + BLPOP | 解耦生产与消费 |
滑动窗口 | 登录记录 | LPUSH + LTRIM | 只保留最近N条数据 |
8. hash
1. 基础命令
命令 | 功能说明 |
---|---|
HSET key field value | 设置哈希表字段的值(新增或更新) |
HGET key field | 获取哈希表字段的值 |
HDEL key field | 删除一个或多个字段 |
HEXISTS key field | 判断字段是否存在 |
HGETALL key | 获取哈希表中所有字段和值 |
HKEYS key | 获取所有字段名 |
HVALS key | 获取所有字段值 |
HMSET key field1 value1 field2 value2 | 批量设置字段值(新版已推荐用 HSET ) |
HMGET key field1 field2 ... | 批量获取字段值 |
HLEN key | 获取字段数量 |
HINCRBY key field increment | 整数值自增 |
HINCRBYFLOAT key field increment | 浮点数值自增 |
2. 存储结构
条件 | 使用结构 |
---|---|
字段数少且字段值较短(<64 字节) | 压缩列表(ziplist) |
超过一定阈值(默认512个字段或任意值超过64字节) | 转为 hashtable |
3. 应用
#一个 key 代表一个对象,多个 field 对应字段名,模拟关系型数据库中一行记录
HSET user:1001 name "Alice"
HSET user:1001 age "24"
HSET user:1001 email "alice@example.com"
HGETALL user:1001
可以把 Redis 的 Hash 结构理解为:
Redis Key(外键): user:1001||--> field1: name → value1: "Alice"|--> field2: age → value2: "24"|--> field3: email → value3: "alice@example.com"
我感觉这么看field更好理解
9. set
1. 基础命令
命令 | 作用 |
---|---|
SADD key member [member ...] | 添加一个或多个元素到集合中 |
SREM key member [member ...] | 移除一个或多个元素 |
SISMEMBER key member | 判断元素是否存在 |
SCARD key | 获取集合元素数量 |
SMEMBERS key | 返回集合中所有元素 |
SRANDMEMBER key [count] | 随机返回一个或多个元素(不删除) |
SPOP key [count] | 随机弹出元素(删除) |
SMOVE source destination member | 将元素从一个集合移动到另一个集合 |
SDIFF key1 key2 | 返回 key1 有但 key2 没有的元素 |
SINTER key1 key2 | 返回 key1 和 key2 的交集 |
SUNION key1 key2 | 返回两个集合的并集 |
2. 存储结构
元素都为整数且节点数量小于等于 512(set-max-intset-entries),则使用整数数组存储;
元素当中有一个不是整数或者节点数量大于 512,则使用字典存储
无序,不重复
3. 应用
#使用 SINTER 获取共同兴趣,推荐内容等
SADD user:1001:tags "旅行" "美食" "摄影"
SADD user:1002:tags "摄影" "跑步"SINTER user:1001:tags user:1002:tags#自动去重,不会重复存储同一个用户 ID
SADD active_users:20250415 1001 1002 1003 1001
SCARD active_users:20250415