当前位置: 首页 > news >正文

浅谈 Redis 数据类型

浅谈 Redis 数据类型

(一)String 类型

Redis 的 String 类型 是二进制安全的,可以用来存储 文本字符串、int 类型数据和 bitmap 位图 等数据。

1. 字符串操作

  • 适用于存储 文本、JSON、序列化数据 等任意二进制安全的内容

    命令作用示例
    SET设置键值SET name "Alice"
    GET获取值GET name"Alice"
    APPEND追加内容APPEND name " Smith""Alice Smith"
    STRLEN获取字节长度STRLEN name11
    GETRANGE截取子串GETRANGE name 0 4"Alice"
    SETRANGE覆盖部分内容SETRANGE name 6 "Taylor""Alice Taylor"
    MSET/MGET批量操作MSET k1 "v1" k2 "v2"
  • 二进制安全:可存储图片、序列化对象等任意数据

  • 自动编码:短字符串用 embstr 编码(内存连续),长字符串用 raw 编码

SETNX 操作实现分布式锁

SETNX key value
  • key 不存在 时,设置其值为 value,并返回 OK(成功);若 key 已存在,则不做任何操作,返回 nil(失败)

  • 为防止锁持有者崩溃后锁无法释放,需设置超时(通过 EXPIRE

  • 任务完成后,主动删除键以释放锁(通过 DEL

  • **【风险1】**若 SETNX 成功,但 EXPIRE 未执行(如客户端崩溃),锁会永久占用

    【解决方案】使用 ​SET 命令的 NXEX 选项​​ 原子性加锁和设置过期时间

    SET key value NX EX 10      # 原子操作:仅当不存在时设置,并过期时间为 10 秒
    
  • **【风险2】**任务未在过期时间内完成,锁被提前释放

    **【解决方案】**看门狗机制:启动后台线程定期续期

    EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('EXPIRE', KEYS[1], ARGV[2]) else return 0 end" 1 key value 10         # 每 10 秒执行一次该 LUA 脚本以续期 
    

2. 数值操作

  • 当 String 的值是 整数或浮点数 时,Redis 提供专用命令进行原子增减
命令作用示例
INCR原子 +1INCR counter1
INCRBY原子 +NINCRBY counter 56
DECR原子 -1DECR counter5
DECRBY原子 -NDECRBY counter 32
INCRBYFLOAT原子 +浮点数INCRBYFLOAT price 1.5"3.5"
  • 编码优化:数值用 int 编码(固定 8 字节),浮点数用 raw
  • 原子性:无需事务即可避免并发冲突。

3. bitmap 位图操作

  • Bitmap 是 String 的扩展,通过 位(bit)操作 实现布尔统计,可用于布隆过滤器、用户状态统计等场景
命令作用示例
SETBIT设置某位为 0/1SETBIT login:2023 100 1(用户 100 登录)
GETBIT获取某位的值GETBIT login:2023 1001
BITCOUNT统计 1 的数量BITCOUNT login:202350(50 人登录)
BITOP位运算(AND/OR/XOR)BITOP AND result login:day1 login:day2
BITPOS查找第一个 0/1 位BITPOS login:2023 1100
  • 内存高效:1 亿用户登录状态仅需约 12MB
  • 高性能:位运算复杂度 O(n),适合批量处理

4. 二进制安全与 Encoding 加速机制

  • Redis 的 String 类型基于简单动态字符串实现,数据按字节数组存储,不预设编码格式,读写时不会做任何转换
  • Redis 为 String 类型设计了多种编码格式(encoding),根据数据内容动态选择最优编码以节省内存和提高性能。通过 OBJECT ENCODING key 可查看编码类型
编码类型适用场景优化原理
int存储 64 位有符号整数(如 123直接使用整数存储,避免字符串转换。
embstr短字符串(≤44 字节,Redis 7+)内存连续分配,减少碎片,CPU 缓存友好。
raw长字符串(>44 字节)或二进制数据标准 SDS 动态分配,支持大容量数据。

(二) List 类型

Redis 的 List 类型 是一个双向链表数据结构,支持在头部和尾部高效插入、删除元素,因此可以灵活实现 栈(Stack)、队列(Queue)、数组(Array)阻塞队列(Blocking Queue) 的语义。

  • LPUSH + LPOP
  • 队列RPUSH + LPOP
  • 数组LINDEX + LSET
  • 阻塞队列RPUSH + BRPOP

以下是详细用法解析:

1. List 作为栈(Stack)

特点:后进先出(LIFO),通过 LPUSH + LPOP 实现
​适用场景​​:函数调用栈、撤销操作(Undo)记录
​操作命令​​:

# 入栈(左侧插入)
LPUSH stack "task1"
LPUSH stack "task2"  # 栈内顺序: ["task2", "task1"]# 出栈(左侧弹出)
LPOP stack  # 返回 "task2",栈剩余: ["task1"]# 查看栈顶元素(不弹出)
LINDEX stack 0  # 返回 "task1"

2. List 作为队列(Queue)

特点:先进先出(FIFO),通过 RPUSH + LPOP 实现
​适用场景​​:任务队列、消息缓冲
​操作命令​​:

# 入队(尾部插入)
RPUSH queue "msg1"
RPUSH queue "msg2"  # 队列顺序: ["msg1", "msg2"]# 出队(头部弹出)
LPOP queue  # 返回 "msg1",队列剩余: ["msg2"]# 查看队列长度
LLEN queue  # 返回 1

3. List 作为数组(Array)

特点:支持按索引访问和修改,通过 LINDEX + LSET 实现
​适用场景​​:随机访问列表元素、动态数组
​操作命令​​:

# 初始化数组
RPUSH array "a" "b" "c"  # 数组: ["a", "b", "c"]# 按索引读取(索引从0开始)
LINDEX array 1  # 返回 "b"# 按索引修改
LSET array 1 "B"  # 数组变为: ["a", "B", "c"]# 获取全部元素
LRANGE array 0 -1  # 返回 ["a", "B", "c"]

4. List 作为阻塞队列(Blocking Queue)

特点:消费者阻塞等待新元素,通过 BRPOP/BLPOP 实现
​适用场景​​:实时消息系统、任务调度(避免轮询)
​操作命令​​:

# 生产者入队(尾部插入)
RPUSH bqueue "job1" "job2"# 消费者阻塞出队(从头部获取,超时时间5秒)
BRPOP bqueue 5  
# 1) 如果队列不为空,立即返回元素(如 "job1")
# 2) 如果队列为空,阻塞 5 秒后返回nil(若期间有新元素插入则立即返回)

(三)Hash 类型

Redis 的 Hash 类型 是一个 键值对集合,适合存储对象。它比 String 类型更节省内存,且支持 字段级操作(单独读写某个字段而无需序列化整个对象)。

1. Hash 的底层结构

  • ziplist(压缩列表):当字段数和字段值较小时使用,内存连续,节省空间
  • hashtable(哈希表):字段较多或值较大时自动转换,查询效率 O(1)

2. 核心操作命令

(1)设置与获取字段值

命令作用示例
HSET设置字段值HSET user:1 name "Alice" age 30
HGET获取字段值HGET user:1 name"Alice"
HMSET批量设置字段HMSET user:1 name "Alice" age 30
HMGET批量获取字段HMGET user:1 name age["Alice", "30"]
HGETALL获取所有字段和值HGETALL user:1["name", "Alice", "age", "30"]
  • 示例
HSET product:1001 name "iPhone" price 999 stock 50
HGET product:1001 price  # 返回 "999"
HGETALL product:1001     # 返回所有字段和值

(2)字段增减与删除

命令作用示例
HINCRBY字段值整数增减HINCRBY user:1 age 1
HINCRBYFLOAT字段值浮点数增减HINCRBYFLOAT account:1 balance 50.5
HDEL删除字段HDEL user:1 age
HEXISTS判断字段是否存在HEXISTS user:1 name1(存在)
  • 示例
HINCRBY product:1001 stock -1  # 库存减1
HDEL product:1001 price        # 删除价格字段

(3)查询与统计

命令作用示例
HKEYS获取所有字段名HKEYS user:1["name", "age"]
HVALS获取所有字段值HVALS user:1["Alice", "30"]
HLEN获取字段数量HLEN user:12
HSTRLEN获取字段值的字节长度HSTRLEN user:1 name5("Alice"占 5 字节)
  • 示例
HKEYS product:1001   # 返回 ["name", "price", "stock"]
HLEN product:1001    # 返回 3

(4)原子操作

命令作用示例
HSETNX字段不存在时才设置HSETNX user:1 email "alice@example.com"
HSCAN增量迭代字段(大数据量时避免阻塞)HSCAN user:1 0
  • 示例
HSETNX user:1 email "alice@example.com"  # 仅当 email 不存在时设置

3. 对象的三种存储策略:单 key 存储、多 key 存储、使用 hash 类型

(1)序列化为字符串(单 Key 存储)

SET user:1000 '{"name":"Alice","age":30,"email":"alice@example.com"}'

(2)每个字段单独存储(多 Key 存储)

SET user:1000:name "Alice"
SET user:1000:age 30
SET user:1000:email "alice@example.com"

(3)使用 Hash 类型

HSET user:1000 name "Alice" age 30 email "alice@example.com"

(4)三种策略比较

维度序列化为字符串多 Key 存储Hash 类型
读写效率整体读写快,部分更新慢部分读写快,整体查询慢部分和批量读写均快
内存占用低(单个 Key)高(每个 Key 有元数据)中(小 Hash 用 zip list)
原子性高(整个对象原子操作)低(需事务)中(单字段操作原子)
字段级 TTL不支持支持不支持
适用字段规模任意少量字段中小规模字段
复杂结构支持支持(JSON 等序列化方式)需额外设计需序列化字段值

(四)Set 类型

Redis 的 Set 类型 是一个 无序、去重的集合,底层基于哈希表实现,支持插入、删除元素以及多个集合的交并差集运算,同时提供了随机返回指定个数元素的功能。

1. Set 的核心特性

  • 无序性:元素没有固定顺序,遍历时顺序不确定
  • 唯一性:自动去重,重复插入的元素会被忽略

2. 常用命令

(1)基本操作

命令作用示例
SADD添加元素(自动去重)SADD tags "redis" "db"
SREM删除元素SREM tags "db"
SMEMBERS获取所有元素SMEMBERS tags
SISMEMBER判断元素是否存在SISMEMBER tags "redis"1(存在)
SCARD获取集合元素数量SCARD tags2
SRANDMEMBER随机返回元素(可指定数量)SRANDMEMBER tags 2
  • 示例
SADD users:1000:followers "user1" "user2" "user3"
SMEMBERS users:1000:followers  # 返回 ["user1", "user2", "user3"]
SISMEMBER users:1000:followers "user1"  # 返回 1(存在)

(2)集合运算

命令作用示例
SINTER返回多个集合的交集SINTER set1 set2
SUNION返回多个集合的并集SUNION set1 set2
SDIFF返回第一个集合与其他集合的差集SDIFF set1 set2
SINTERSTORE存储交集到新集合SINTERSTORE result set1 set2
SUNIONSTORE存储并集到新集合SUNIONSTORE result set1 set2
SDIFFSTORE存储差集到新集合SDIFFSTORE result set1 set2
  • 示例
SADD group1 "user1" "user2" "user3"
SADD group2 "user2" "user3" "user4"
SINTER group1 group2  # 返回 ["user2", "user3"](共同成员)
SDIFF group1 group2   # 返回 ["user1"](仅在 group1 中的成员)

(3)随机返回元素

  • Redis 的 Set 类型提供了 随机返回元素 的功能,适用于 抽奖、随机推荐、随机选取样本 等场景
SRANDMEMBER key count
  • key:Set 的键名
  • count:指定返回的元素数量
    • count > 0:返回 不重复 的元素(最多返回整个 Set 的大小)
    • count < 0:返回元素可能 重复(适用于允许重复抽奖的场景)

(五)Sorted Set 类型

Redis 中的 Sorted Set 类型 也是一种集合类型,集合中的元素可以按照自定义分值排序,底层基于跳表实现。

1. 特点

  • 唯一性:成员(member)不可重复,但分数(score)可重复
  • 有序性:按 score 排序(默认升序),相同 score 按字典序排序

2. 核心命令

  • 成员操作命令

    命令功能
    ZADD key score member添加/更新成员(支持NX/XX/INCR选项)
    ZREM key member删除指定成员
    ZINCRBY key increment member增加成员分数
    ZSCORE key member获取成员分数
  • 查询命令

    命令功能
    ZRANGE key start stop按分数升序返回成员(WITHSCORES显示分数)
    ZREVRANGE key start stop按分数降序返回成员
    ZRANGEBYSCORE key min max返回分数在 [min,max] 区间的成员
  • 排名统计命令

    命令功能
    ZRANK key member获取成员升序排名(从 0 开始)
    ZREVRANK key member获取成员降序排名
    ZCARD key返回成员总数
    ZCOUNT key min max统计分数范围内的成员数
  • 集合运算命令

    计算多个有序集合的并集存储(交集存储)

    ZUNIONSTORE/ZINTERSTORE destkey numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

    • 必选参数

      • destkey:存储结果的键名
      • numkeys:参与计算的集合数量(后续需对应数量的 key
      • key:参与计算的集合键名(至少一个)
    • 可选参数

      • WEIGHTS:为每个集合的分值设置权重(默认权重为 1
      • AGGREGATE:合并重复成员的分值策略(SUM 求和、MIN 取最小、MAX 取最大,默认 SUM
    • 示例

    ZADD scores1 10 "Alice" 20 "Bob"
    ZADD scores2 5 "Alice" 30 "Charlie"
    ZUNIONSTORE result 2 scores1 scores2 WEIGHTS 2 3 SUM
    
    • Alice 的分值: 10 * 2 + 5 * 3 = 35

    • Bob 的分值 = 20 * 2 = 40

    • Charlie 的分值 = 30 * 3 = 90

    1) "Alice"   35
    2) "Bob"     40
    3) "Charlie" 90
    

3. 底层实现

Sorted Set 是 Redis 中最复杂的数据结构之一。它通过 跳表和哈希表 的混合实现,兼顾了高效查询和动态排序的能力。

编码方式数据结构触发条件特点
ziplist压缩列表 [member1, score1, member2, score2, ...]元素数量 ≤ zset-max-ziplist-entries(默认128)且所有元素长度 ≤ zset-max-ziplist-value(默认64字节)内存紧凑,但增删效率低(O(n))
skiplist + dict跳表 + 哈希表不满足 ziplist 条件时自动转换支持高效查询和范围操作(O(log n))
  • 哈希表与跳表的协同

    跳表保证有序性,哈希表加速单成员查询,两者互补

  • 内存与 CPU 的权衡

    小数据用 ziplist 节省内存,大数据用 skiplist 提升操作效率

(1)跳表的结构

  • 跳表(Skip List)是一种基于 多层有序链表 的数据结构,通过 概率平衡 实现高效的动态操作(平均 O(log n) 时间复杂度)

  • 跳表由多层链表组成,每层链表都是有序的,但高层链表是低层链表的【快速通道】:

    • 最底层链表:包含所有元素的有序链表

    • 高层链表:每层节点数约为下一层的一半,形成跳跃路径

(2)查找原理:平均 O(log n)(最坏 O(n)

  • 从最高层头节点开始,向右遍历:

    • 若当前节点的下一个节点值 ≤ 目标值,则继续向右

    • 若下一个节点值 > 目标值,则向下移动到下一层

  • 重复上述过程,直到最底层,找到目标节点或确认不存在

(3)插入原理:平均 O(log n)

  • 查找插入位置,记录每一层的前驱节点,即插入位置左侧的节点
  • 随机生成层高,每个新插入节点的层数由 概率决定,通常采用 “抛硬币”策略
    1. 初始层高:新节点至少在第 0 层(最底层,包含所有节点)
    2. 逐层晋升:每次“抛硬币” 若为“正面”(概率通常为 50%)则层数 +1;否则停止
    3. Redis 优化:降低晋升概率(p=0.25)和限制最大层数(32),平衡性能与内存开销
  • 在每一层(从生成的最高层到最底层)链表中插入新节点,并更新前后节点的指针
http://www.xdnf.cn/news/426511.html

相关文章:

  • 【PmHub后端篇】PmHub中基于Redis加Lua脚本的计数器算法限流实现
  • 【Canda】常用命令+虚拟环境创建到选择
  • aardio —— 虚表 —— 同一单元格内用不同的字体
  • maven中relativepath标签的含义及使用方法
  • TensorFlow 常见使用场景及开源项目实例
  • 大模型MCP之UV安装使用
  • 数据集-目标检测系列- 杨桃 数据集 Starfruit>> DataBall
  • leetcode 189. 轮转数组
  • 养生:打造健康生活的全方位策略
  • GPT-4.1和GPT-4.1-mini系列模型支持微调功能,助力企业级智能应用深度契合业务需求
  • Comparator不满足自反性错误,Comparison method violates its general contract
  • Cursor开发酒店管理系统
  • RevIN(Reversible Instance Normalization)及其在时间序列中的应用
  • SpringBoot中使用集群版Redis
  • sparkSQL读入csv文件写入mysql
  • 基于自动化工具autox.js的抢票(猫眼)
  • P1032 [NOIP 2002 提高组] 字串变换
  • [ctfshow web入门] web72
  • vscode百宝箱工具插件(devtools)
  • 数据可视化图表
  • pe文件二进制解析(用c/c++解析一个二进制pe文件)
  • 网络层试题
  • c语言第一个小游戏:贪吃蛇小游戏05
  • 2025.05.11阿里云机考真题算法岗-第三题
  • java高效实现爬虫
  • SAM 2: Segment Anything in Images and Videos
  • 2025年渗透测试面试题总结-渗透测试红队面试九(题目+回答)
  • kingbase链接数修改、数据备份/还原
  • py7zr解压文件时报错CrcError(crc32, f.crc32, f.filename)
  • 学习黑客Windows 卷影复制服务详解