ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Redis 数据类型全景:五种基础类型怎么用、什么时候用

Redis 数据类型全景:五种基础类型怎么用、什么时候用 个人主页 for_ever_love__ 欢迎各位大佬莅临其他栏目: 大模型开发从0到1 其他栏目: iOS项目总结大全 其他栏目: 我想学python了 其他栏目: iOS UI 文章目录Redis 数据类型全景五种基础类型怎么用、什么时候用一、Redis 的键与值底层编码同一个类型可能有多种实现二、String最基础也最常被误用适用场景⚠️ 常见误用什么都往 String 里塞三、Hash对象存储的正解适用场景⚠️ 两个坑四、List有序可重复适用场景五、Set无序去重适用场景六、ZSetSorted Set排行榜的不二之选适用场景七、三种扩展类型7.1 Bitmap海量布尔值7.2 HyperLogLogUV 统计7.3 Geo地理位置7.4 Stream正经的消息队列八、选型速查表九、三个通用原则十、小结Redis 数据类型全景五种基础类型怎么用、什么时候用Redis 快不全是因为在内存里数据结构选对了才是关键。用 String 存一个用户信息和用 Hash 存内存占用和网络传输量能差好几倍。本篇把五种基础类型 三种扩展类型讲透重点是每种类型的适用场景和一个能直接抄的例子。一、Redis 的键与值先明确一件事Redis 的 key 永远是 String我们说的数据类型指的是value 的类型。TYPE user:1# 查看类型OBJECT ENCODING user:1# 查看底层编码很重要见下文底层编码同一个类型可能有多种实现这是 Redis 内存优化的核心机制。比如 Hash条件编码特点字段少≤512 值小≤64字节ziplist紧凑列表省内存但查询是 O(n)超出阈值hashtable查询 O(1)但内存开销大HSET small_hash a1b2OBJECT ENCODING small_hash# ziplist / listpack# 塞进 600 个字段后OBJECT ENCODING small_hash# hashtable ← 自动转换⚠️转换是单向的一旦变成 hashtable删掉字段也不会变回 ziplist。所以阈值要提前规划可在配置里调hash-max-listpack-entries。二、String最基础也最常被误用SET nameTomGET name# TomSET counter0INCR counter# 1原子自增INCRBY counter10# 11SETEX token3600abc# 设置并指定 3600 秒过期原子操作SETNX lock_key1# 不存在才设置分布式锁的基石MSET k1 v1 k2 v2# 批量设置减少网络往返MGET k1 k2适用场景场景例子缓存单个值用户信息 JSON、配置计数器点赞数、浏览量INCR原子分布式锁SET key value NX EX 30限流INCREXPIRESessiontoken → 用户信息⚠️ 常见误用什么都往 String 里塞# ❌ 存整个对象改一个字段要全量读写SET user:1{name:Tom,age:20,city:Beijing}GET user:1# 只想看 age却要把整个 JSON 传回来如果这个对象经常只改一两个字段用Hash更合适。但如果每次都是整体读写比如缓存整个 HTML 片段String 反而更好——因为字符串编码更紧凑。判断标准整体读写 → String频繁改单个字段 → Hash三、Hash对象存储的正解HSET user:1 nameTomage20cityBeijingHGET user:1 name# TomHMGET user:1 name age# 批量取HGETALL user:1# 全取⚠️ 大 hash 会阻塞HINCRBY user:1 age1# 字段自增HLEN user:1# 字段数HEXISTS user:1 email# 字段是否存在适用场景场景例子对象存储用户信息、商品属性购物车cart:userId→{商品ID: 数量}配置项分组一组相关的配置# 购物车key cart:1001field 商品IDvalue 数量HSET cart:1001882991HINCRBY cart:1001881# 加一件HLEN cart:1001# 购物车里有几种商品HDEL cart:100199# 删除HGETALL cart:1001# 结算⚠️ 两个坑坑 1HGETALL在大 Hash 上会阻塞一个 Hash 有 10 万字段HGETALL会卡住 Redis 几百毫秒。用HSCAN分批HSCAN user:big0COUNT100# 每次 100 个游标迭代坑 2Hash 不能对单个 field 设过期过期只能设在 key 上。要单字段过期就得拆成多个 key。四、List有序可重复LPUSH queue a b c# 左侧插入 → [c, b, a]RPUSH queue d# 右侧插入 → [c, b, a, d]LPOP queue# 弹出 cRPOP queue# 弹出 dLRANGE queue0-1# 范围取LLEN queue LTRIM queue099# 只保留前 100 个控制长度适用场景场景命令组合消息队列LPUSHBRPOP阻塞弹出最新动态 / Feed 流LPUSHLTRIMLRANGE栈LPUSHLPOP# 简易队列生产用 Stream 更合适LPUSH task_queue{json}BRPOP task_queue30# 阻塞等 30 秒没任务就返回 nil# 保留最新的 100 条动态LPUSH feed:1001新动态LTRIM feed:1001099LRANGE feed:100109# 取最新 10 条⚠️List 做队列的两个问题没有 ACK 机制消费者崩溃消息就丢了不支持多消费者组生产环境用 StreamRedis 5.0它才是正经的消息队列。五、Set无序去重SADD tags:article1 redis mysql SREM tags:article1 mysql SMEMBERS tags:article1# 全部成员⚠️ 大集合会阻塞SISMEMBER tags:article1 redis# 是否存在 O(1)SCARD tags:article1# 成员数# 集合运算这是 Set 最独特的能力SINTER set1 set2# 交集SUNION set1 set2# 并集SDIFF set1 set2# 差集SINTERSTORE result set1 set2# 交集存到新 key适用场景场景例子去重已读文章、UV 统计标签系统文章标签、用户兴趣社交关系关注列表、好友、共同好友抽奖SRANDMEMBER/SPOP# 共同关注SADD following:u1 alice bob carol SADD following:u2 bob carol dave SINTER following:u1 following:u2# bob, carol# 判断是否点赞过SADD liked:article1 u1001 SISMEMBER liked:article1 u1002# 0 没赞过⚠️ 大集合用SSCAN代替SMEMBERS。六、ZSetSorted Set排行榜的不二之选ZSet Set 每个元素一个score按 score 排序。底层是跳表Skip List 哈希表所以既能按成员 O(1) 查找又能按 score 范围查询 O(log N)。ZADD rank100playerA85playerB92playerCZSCORE rank playerA# 100ZINCRBY rank10playerB# 95加分ZRANGE rank09WITHSCORES# 前 10 名score 升序ZREVRANGE rank09WITHSCORES# 前 10 名降序排行榜用这个ZRANK rank playerA# 排名从 0 开始升序ZREVRANK rank playerA# 降序排名ZCARD rank# 总数ZREM rank playerA ZREMRANGEBYRANK rank100-1# 删除 100 名之后的所有人只保留前 100适用场景场景例子排行榜积分榜、销量榜、热搜延迟队列score 执行时间戳优先级队列score 优先级时间线score 时间戳按时间范围取# 延迟队列score 存执行时间ZADD delay_queue1730000000task1# 取到期的任务ZRANGEBYSCORE delay_queue0$(date%s)LIMIT010# 取出后删除要用 Lua 保证原子# 排行榜 只保留前 100ZADD leaderboard1500user:1ZREVRANGE leaderboard09WITHSCORES# TOP 10ZREVRANK leaderboarduser:1# 我是第几名ZREMRANGEBYRANK leaderboard100-1# 定期清理七、三种扩展类型7.1 Bitmap海量布尔值SETBIT sign:2026-1051# 用户 5 在 10 月 5 日签到GETBIT sign:2026-105# 是否签到BITCOUNT sign:2026-10# 这个月签到几天BITOP AND both d1 d2# 两天都签到的用户价值极省内存。1 亿用户的签到状态只要约 12 MB。典型场景签到、活跃用户标记、布隆过滤器底层。7.2 HyperLogLogUV 统计PFADD uv:20261007 u1 u2 u3 u1 PFCOUNT uv:20261007# 3自动去重PFMERGE uv:week uv:d1 uv:d2# 合并多天0.81% 的误差率但只占 12 KB 内存不管你塞进去多少数据。统计 UV 用它精确去重才用 Set。⚠️不能取单个元素只能取基数。7.3 Geo地理位置GEOADD shops116.4039.90shop1116.4139.91shop2GEODIST shops shop1 shop2 km# 距离GEORADIUS shops116.4039.905km# 5 公里内的店铺已废弃GEOSEARCH shops FROMLONLAT116.4039.90BYRADIUS5km# 6.2 新命令底层就是 ZSetGeoHash 编码成 score所以 ZSet 命令也能用。7.4 Stream正经的消息队列XADD mystream * sensor_id1234temp19.8# * 表示自动生成 IDXREAD BLOCK2000STREAMS mystream $# 阻塞读新消息# 消费者组支持多消费者、ACK、重试XGROUP CREATE mystream group10XREADGROUP GROUP group1 c1 COUNT1STREAMS mystreamXACK mystream group1message-id# 确认处理完成XPENDING mystream group1# 查看未确认的消息Stream 解决了 List 做队列的所有问题多消费者组、ACK、消息持久化、回溯。八、选型速查表你的需求用什么缓存整个对象 / 计数器 / 锁String对象且要频繁改单个字段Hash简单队列 / 最新列表List或 Stream去重、集合运算、共同好友Set排行榜、延迟队列、带权重ZSet海量布尔标记签到BitmapUV 统计允许误差HyperLogLog附近的人 / 门店Geo可靠消息队列Stream九、三个通用原则1. key 要有命名空间# ❌ 全平铺容易冲突SET nameTomSET nameJerry# 覆盖了# ✅ 业务:对象:ID:属性SET user:1001:nameTomSET order:20261007:statuspaid2. 避免大 key类型危险阈值String 10 KB有说 1 MBHash/Set/ZSet/List元素数 5000或整体 10 MB大 key 的问题删除卡顿、迁移失败、网络传输慢、HGETALL/SMEMBERS阻塞。3. 一定要设过期时间SET cache:xxx value EX3600# 缓存必须有 TTL例外持久化数据如用户资料缓存可以不设但必须有主动更新/删除的机制。十、小结key 永远是 String类型说的是 valueRedis 会用不同编码存同一类型小数据用紧凑结构省内存转换单向String整体读写的缓存、计数器、分布式锁Hash对象且频繁改单字段HGETALL大 hash 会阻塞用HSCANList简单队列和最新列表生产队列用StreamSet去重 集合运算共同好友ZSet排行榜首选底层跳表范围查询 O(log N)HyperLogLogUV 统计12 KB 固定内存0.81% 误差不能取单元素key 用业务:对象:ID命名避免大 key缓存必设 TTL下一篇讲持久化——内存数据断电就没了Redis 靠 RDB 和 AOF 两种机制把数据落到磁盘它们的区别和选择是运维必须掌握的知识。
返回列表