Redis别再只当缓存用!8种常用数据结构+实战选型,一看就会
大家好,我是直奔標竿!
做开发的朋友应该都有这种体会:学Redis入门,基本上都是从GET/SET开始,简单好记,上手也快。可一到实际项目里就犯难——不管什么数据,都往String里塞,到最后Redis虽说能正常运行,但用起来越来越别扭:
✅ 对象更新得先反序列化,改完再整体写回去,麻烦到不行;
✅ 想做个简单的排行榜,还得自己写排序逻辑,又笨重又低效;
✅ 维护用户订阅关系,去重和查询都特别费劲,越改越乱。
其实很多人都搞错了:Redis的核心优势,从来不止是“快”,更在于它内置的多种数据结构。选对结构,写代码会特别顺畅,后期维护也没压力;选错了,只会没完没了地打补丁,甚至拖慢系统性能。
今天直奔標竿就跟大家掏心窝子分享,把Redis最常用的8种数据结构讲得明明白白,结合实际项目场景,告诉大家每种结构该怎么用、适合解决什么问题,新手也能直接照搬套用!
一、String:最基础,也最容易用错
String是Redis里最基础、最常用的数据结构,本质就是“key-value”键值对,没有复杂逻辑,上手就能用。
但正因为简单,才最容易被用错——很多人不管什么数据,都序列化后塞进String里,最后把自己坑得不行。
它真正适合的场景,就3类,记牢就好:
缓存一个完整的值(整体读取、整体写入);
做计数器(原子自增,高并发情况下也不会出错);
简单的状态控制(比如开关、令牌之类)。
举个实际例子:实时行情项目里,一只股票的完整快照、市场统计结果,就特别适合用String存储——拿回来直接反序列化,不用拆分字段,逻辑简单直接。
✅ 常见实战场景(一定要记):
缓存用户信息JSON、商品详情(整对象缓存);
存储验证码、token、session(短期有效,整体读写即可);
阅读数、点赞数、自增序列号(用INCR原子操作,避免并发问题);
分布式锁、告警去重锁(一条SET NX EX命令就能搞定)。
直奔標竿一句话总结:只要你的数据是“一个完整对象”,不是“多个独立字段”,优先用String,简单高效还不踩坑!
二、Hash:最适合存“对象字段”(局部更新超方便)
如果说String适合存“完整对象”,那Hash就适合存“对象的多个字段”——可以理解成Redis里的“小型对象存储”,一个key下面能挂多个field-value,能精准操作单个字段。
举个直观的例子,存储用户信息:
HSET user:1001 name Tom age 18 city Tokyo
不用把整个用户JSON序列化,想改年龄就改age字段,想改城市就改city字段,不用整体重写,效率直接拉满。
这也是它最核心的优势:字段多、而且经常只改其中一部分,用Hash准没错。
✅ 常见实战场景:
用户资料(姓名、年龄、手机号,经常单独修改);
订单状态(待支付、已发货、已完成,按字段更新);
配置项、实时指标对象(多字段,局部更新频繁);
交易统计对象(成交金额、笔数,分开统计更新)。
再举个项目实例:行情系统里,某只股票除了基础快照,还有涨速、均线、更新时间等扩展信息。如果塞进一个大JSON里,改一个字段就要把整个对象重写;用Hash,直接更新对应field,又省事又高效。
直奔標竿一句话总结:数据是“一个对象的多个字段”,而且经常单独读写,优先用Hash,再也不用麻烦地整体序列化!
三、List:看重顺序,适合队列和有序列表
List本质是双端链表,核心特点:有顺序、可重复,两端插入和删除的速度特别快(时间复杂度O(1)),中间查询则比较慢(O(n))。
它的应用场景很明确,全和“顺序”有关,尤其是先进先出(FIFO)的场景。
✅ 核心适用场景:
消息队列、任务队列(生产者用LPUSH入队,消费者用BRPOP阻塞出队,轻量级异步首选);
时间顺序列表(最近浏览、最近操作、最近自选的内容);
简单排行榜快照(阶段性保存,天生有序,不用额外做排序)。
实战案例:资讯抓取系统中,待处理的文章链接可以放进List,消费者依次取出抓取,避免重复处理;用户系统里,用List缓存“最近浏览的商品”,按时间顺序展示,简单又高效。
直奔標竿一句话总结:需要顺序、先进先出,或者保存有序记录,直接想到List,不用瞎折腾!
四、Set:去重+判断关系,刚需场景必用
Set的核心特性:无序、元素唯一,自带去重效果,而且判断某个元素是否存在的速度特别快(O(1))。
它最擅长的两件事:去重、判断元素是否存在,还有集合关系运算(交集、并集、差集),在实际项目里用得特别多。
✅ 常见实战场景:
标签集合(用户标签、商品标签,避免重复);
去重名单(活动参与用户、今日访问用户,天生去重);
在线用户集合(判断用户是否在线,快速查询);
订阅关系(订阅某只股票、某个频道的用户,判断是否订阅);
风控系统(今日风险股票集合、黑名单,快速匹配)。
实战亮点:做共同好友、用户画像匹配时,用Set的交集运算(SINTER),一行命令就能搞定,比在应用层自己计算高效多了。
直奔標竿一句话总结:核心需求是去重、判断元素是否存在、集合运算,直接用Set,不用自己写去重逻辑,省时间又高效!
五、Sorted Set:Redis最有业务价值的结构(排行榜首选)
Sorted Set(简称ZSet),可以理解成“带分数的Set”——元素唯一,每个元素都有一个score(分数),Redis会自动按score排序,还支持范围查询,是Redis里最有业务价值的高级结构之一。
很多实时系统里,ZSet的使用频率甚至超过String,因为它能完美解决“排序+范围查询”的核心需求。
✅ 核心适用场景:
各种排行榜(热搜榜、热度榜、收益榜、打赏榜,用ZADD存数据、ZREVRANGE查Top N);
按时间排序的数据流(分时趋势、成交明细,用时间戳当score);
延时任务(把score设为过期时间,定期查询到期任务);
区间查询(查询某个分数段、某个时间段的数据)。
实战案例:实时金融系统里,ZSet能同时承担多个角色——分时趋势数据按时间戳排序、板块热度按热度分排序、组合收益按涨跌幅排序,甚至交易日历也能按日期排序存储。很多系统到最后,Redis里占用空间最大的部分,就是一堆ZSet。
直奔標竿一句话总结:只要需要“排序+范围查询”,不管是排行榜还是时序数据,优先用ZSet,效率和代码简洁度直接拉满!
六、Bitmap:海量0/1状态,超级省空间
很多人不知道,Bitmap其实不是独立的数据结构,而是基于String的位操作——用bit(位)来表示0/1状态,一个字节能存8个状态,特别省空间。
它的适用场景很单一,但非常刚需:海量用户的布尔状态存储,比如“是否登录”“是否签到”“是否完成任务”。
举个直观的例子:千万级用户,要记录“今天是否登录”,用普通String得存千万个键值对,内存占用特别大;用Bitmap,一个键就能存所有用户的状态,1000万用户也只需要约1.2MB内存,省空间的效果特别明显。
✅ 常见实战场景:
用户签到(每天一个Bitmap,bit位对应用户ID,1=签到,0=未签到);
在线状态标记(1=在线,0=离线,快速查询批量用户状态);
某日是否完成某操作(比如用户是否完成今日任务、是否领取优惠券)。
直奔標竿一句话总结:有海量布尔状态需要存储,优先用Bitmap,省内存又高效,谁用谁知道!
七、HyperLogLog:海量去重计数,不用存明细
如果你的需求是“统计去重后的数量”,但不关心“具体是谁”,那HyperLogLog就是最优解——它的核心优势是:空间占用极小,不管数据量多大,占用的内存几乎不变(约12KB)。
注意:它的缺点是结果是近似值(误差在0.81%以内),但大多数业务场景下,这个误差完全可以接受。
✅ 常见实战场景:
UV统计(网站独立访客数,不用存每个访客的ID);
独立设备数统计(APP独立设备,海量数据去重计数);
活动独立参与人数统计(不关心具体参与用户,只看人数)。
实战对比:统计一个千万级访问量网站的UV,用Set要存千万个用户ID,内存占用极大;用HyperLogLog,12KB就能搞定,虽然是近似值,但完全能满足业务需求。
直奔標竿一句话总结:只需要统计去重后的数量,不关心明细,用HyperLogLog,省内存又省事!
八、Stream:正式消息流,比List更靠谱
如果你的消息队列需求比较正式,对可靠性要求高,那Stream比List更合适——它是Redis专门为消息流设计的结构,比List更像一个“真正的消息队列”。
和List相比,Stream的核心优势是支持消费组、消息确认、消息重放、多消费者协作,能解决List作为队列的很多痛点(比如消息丢失、无法重复消费)。
✅ 常见实战场景:
日志采集(分布式日志,多消费者协作采集);
正式异步任务(需要消息确认,避免丢失);
事件驱动架构(系统间事件通信,支持消息重放)。
直奔標竿一句话总结:简单的轻量级队列,用List就够了;需要消息可靠、多消费者协作,用Stream,避免后期踩坑!
九、高频痛点:String和Hash,到底该怎么选?
这是很多开发者最纠结的问题,直奔標竿结合实战经验,给大家讲透,不用再瞎猜:
1. 存储方式不同
String:把对象整体序列化(比如JSON)后存进去,key对应整个对象;
Hash:把对象拆成多个field-value,key对应对象,field对应字段。
2. 更新方式不同(关键区别)
如果只想改一个字段:
String:必须先用GET取出来,反序列化,修改字段,再用SET写回去,步骤繁琐,还可能出现并发问题;
Hash:直接用HSET key field value,精准修改单个字段,不用整体操作。
结论:字段经常变动,优先选Hash。
3. 读取方式不同
如果经常只读部分字段:
String:必须GET整个对象,反序列化后再取字段,浪费带宽和性能;
Hash:直接用HGET/HMGET,只取需要的字段,高效又省资源。
结论:经常局部读取,优先选Hash。
4. 内存占用不同(纠正误区)
很多人以为Hash一定更省内存,其实并不是这样:
String结构简单,存储完整对象更直接,没有额外开销;
Hash需要存储field和内部结构,通常会多一点开销;
但对于小而扁平的Hash,Redis会做紧凑编码,内存差距不大;
如果字段多、字段名长,Hash可能比String更占内存。
5. 实用判断标准(记牢)
问自己两个问题,答案就出来了:
我是不是经常只改对象里的某几个字段?
我是不是经常只读对象里的某几个字段?
✅ 两个都是“是”:选Hash;
✅ 两个都是“否”:选String(简单又高效)。
十、实战总结:项目里最常用的选型方案
直奔標竿结合多年实战经验,整理了真实系统里最常用的选型方式,直接套用,不用踩坑:
用户、商品、快照整体缓存 → String;
用户状态、指标字段、配置对象 → Hash;
任务队列、最近记录(浏览/操作) → List;
订阅关系、在线用户、风险名单 → Set;
趋势、排行、成交明细、热度列表 → Sorted Set;
海量布尔状态(签到、在线) → Bitmap;
海量去重计数(UV、独立设备) → HyperLogLog;
正式消息流、可靠异步任务 → Stream。
结尾:真正用好Redis,从选对数据结构开始
很多团队用Redis,到最后就只剩下GET/SET,虽然能运行,但浪费了Redis 80%的价值。
其实Redis真正厉害的地方,不是“能缓存”,而是能让你把不同的业务问题,对应到最合适的数据结构上——不用自己写复杂逻辑,不用频繁打补丁,代码简洁,性能还优。
真正把Redis用顺的人,脑子里想的不是“我要不要用Redis”,而是:
这是整体值,还是对象字段?(对应String/Hash)
这是顺序问题,还是去重问题?(对应List/Set)
这是集合关系,还是排序问题?(对应Set/Sorted Set)
下次再设计缓存层、排行榜、订阅系统、实时趋势数据时,不妨先问自己一句:这个业务问题,对应的到底是哪一种数据结构?
我是直奔標竿,专注分享实战技术,拒绝纸上谈兵。如果这篇文章对你有帮助,欢迎点赞、收藏、关注,后续会分享更多Redis实战技巧!
