news 2026/8/7 15:24:44

Redis三大特殊数据类型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis三大特殊数据类型

文章目录

  • 前言
  • 一、Bitmap 位图:极致节省空间的二元状态存储
    • 1. 底层原理
    • 2. 核心实操命令
    • 3. 适用场景
    • 4. 踩坑总结
  • 二、HyperLogLog:亿级去重统计神器
    • 1. 底层原理
    • 2. 核心实操命令
    • 3. 适用场景
    • 4. 踩坑总结
  • 三、Geospatial(GEO) 地理坐标类型
    • 1. 底层原理
    • 2. 核心实操命令
    • 3. 适用场景
    • 4. 踩坑总结
  • 四、三大特殊类型完整总结
    • 整体学习感悟

前言

Redis藏了三个专门适配特殊业务的新数据类型:Bitmap、HyperLogLog、Geospatial,让我们继续学习


提示:以下是本篇文章正文内容,下面案例可供参考

一、Bitmap 位图:极致节省空间的二元状态存储

1. 底层原理

Bitmap并不是独立的数据结构,底层依托String实现,操作的是字符串里每一个二进制bit位,一个bit只有0、1两种值,完美适配“是/否”类业务状态。
举个对比案例:千万用户签到场景

  • MySQL方案:每条签到记录一条数据,海量数据占用大量磁盘,查询缓慢;
  • Bitmap方案:一个用户单月签到仅占用31bit,百万用户存储只需要几十MB,性能碾压传统方案。
    上限:单个Bitmap最大512M,对应2^32个bit,日常业务完全够用。

2. 核心实操命令

  1. SETBIT key offset 0/1:指定下标存入状态(offset从0开始)
    示例:setbit sign:user1 0 1用户1当月1号签到
  2. GETBIT key offset:查询指定位置bit值
  3. BITCOUNT key:统计值为1的bit总数(统计签到天数)
  4. BITOP and/or/xor dest key1 key2:位图位运算,统计多天连续签到用户

实例运行:

# ========== 第一组:Bitmap基础命令实操 ========== # setbit key 偏移量 0/1:设置指定bit位的值,返回修改前该位置的旧值 # bit1的第0位设为1,之前是空默认0,返回0 127.0.0.1:6379> setbit bit1 0 1 (integer) 0 # bit1的第1位设为1,旧值0 127.0.0.1:6379> setbit bit1 1 1 (integer) 0 # bit1的第3位设为1,跳过2号位,旧值0 127.0.0.1:6379> setbit bit1 3 1 (integer) 0 # bit1的第5位设为1,旧值0 127.0.0.1:6379> setbit bit1 5 1 (integer) 0 # bit1的第7位设为1,旧值0 127.0.0.1:6379> setbit bit1 7 1 (integer) 0 # getbit key 偏移量:查询指定bit位的值 # 查询第3位,值为1 127.0.0.1:6379> getbit bit1 3 (integer) 1 # 查询第2位,从未赋值,默认0 127.0.0.1:6379> getbit bit1 2 (integer) 0 # bitfield key get uN offset:从offset开始读取N个无符号bit,转十进制 # 从0号位读取2个bit:bit0=1、bit1=1 → 二进制11=十进制3 127.0.0.1:6379> bitfield bit1 get u2 0 1) (integer) 3 # bitpos key bit值:查找第一个等于目标bit的偏移量 # 查找bit1中第一个0,位置是2 127.0.0.1:6379> bitpos bit1 0 (integer) 2

3. 适用场景

用户签到打卡、APP登录状态标记、海量用户黑白名单、日活用户筛选

4. 踩坑总结

offset不要直接使用超大用户ID,会造成大量空bit浪费内存;仅适合二元状态,多状态场景不适用。

二、HyperLogLog:亿级去重统计神器

1. 底层原理

专门做基数统计(统计不重复元素数量),核心优势是极致压缩内存:无论存入多少数据,单个HyperLogLog固定仅占用12KB内存,最大可统计2^64个不同元素,仅存在0.81%左右微小误差,绝大多数互联网业务可以忽略。
对比Set:存储百万独立访客,Set需要几十MB,HLL仅12KB,差距巨大。
短板:只能统计数量,无法取出存入的原始数据。

2. 核心实操命令

  1. PFADD key 元素:添加数据,自动去重
    示例:pfadd uv:20260807 u001 u002 u003记录今日访客
  2. PFCOUNT key:查询不重复元素总数(网站UV)
  3. PFMERGE newkey key1 key2:合并多个HLL,统计周期总访客

实例运行:

# pfadd key 元素:往HyperLogLog添加数据;元素首次加入返回1,重复添加无变化返回0 127.0.0.1:6379> pfadd k1 java (integer) 1 # java第一次存入k1,新增成功 127.0.0.1:6379> pfadd k1 html (integer) 1 # html第一次存入k1,新增成功 127.0.0.1:6379> pfadd k1 javascript (integer) 1 # javascript第一次存入k1,新增成功 127.0.0.1:6379> pfadd k1 java (integer) 0 # java已存在,无新增,返回0 # pfcount key:统计HLL中不重复元素的近似基数(去重总数) 127.0.0.1:6379> pfcount k1 (integer) 3 # k1去重后共3个元素:java、html、javascript # 新建HLL集合k2,存入spring 127.0.0.1:6379> pfadd k2 spring (integer) 1 # 存入mysql 127.0.0.1:6379> pfadd k2 mysql (integer) 1 # 统计k2去重数量 127.0.0.1:6379> pfcount k2 (integer) 2 # k2去重后2个元素 # pfmerge 目标key 源key1 源key2:合并多个HLL,所有去重数据存入目标key 127.0.0.1:6379> pfmerge k3 k1 k2 OK # 合并操作执行成功 # 统计合并后k3的总去重数量(3+2无重复,结果为5) 127.0.0.1:6379> pfcount k3 (integer) 5

3. 适用场景

网站独立访客UV统计、搜索关键词去重计数、活动参与人数统计

4. 踩坑总结

如果业务必须获取全部唯一数据,不能用HLL,优先选择Set;对数据精准度要求极高的金融场景慎用。

三、Geospatial(GEO) 地理坐标类型

1. 底层原理

Redis3.2新增地理数据类型,底层依托Zset有序集合实现,将经纬度坐标编码成score存储,原生封装地图相关计算指令,不用自己写复杂地理算法。

2. 核心实操命令

  1. GEOADD key 经度 纬度 名称:存入地点坐标
    示例:geoadd city 121.47 31.23 shanghai
  2. GEOPOS key 地点:获取目标经纬度
  3. GEODIST key A B km/m:计算两点直线距离
  4. GEORANGE key 经度 纬度 半径 km:查询指定范围内所有地点

实例运行:

# ===================== 一、GEO地理坐标类型实操 ===================== # geoadd key 经度 纬度 地点名:添加地理坐标,返回本次新增地点数量 127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai (integer) 1 # 成功新增上海1个坐标 # 批量添加重庆、深圳、北京三个城市,返回新增总数3 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing (integer) 3 # geopos key 地点:查询指定城市的经纬度 127.0.0.1:6379> geopos china:city shanghai 1) 1) "121.47000163793563843" # 经度 2) "31.22999903975783553" # 纬度 # geodist 计算两点直线距离,默认单位米(m) 127.0.0.1:6379> geodist china:city beijing shanghai "1068153.5181" # 北京到上海距离,单位米 # 追加km参数,单位切换为千米 127.0.0.1:6379> geodist china:city beijing shanghai km "1068.1535" # 北京到深圳直线距离,单位千米 127.0.0.1:6379> geodist china:city beijing shenzhen km "1945.5740" # georadius 给定经纬度+半径,查询范围内所有存储的地点 127.0.0.1:6379> georadius china:city 110 30 1000 km 1) "chongqing" 2) "shenzhen" # flushdb:清空当前数据库所有key 127.0.0.1:6379> flushdb OK # ===================== 二、Redis事务场景1:正常执行提交 ===================== # multi:开启事务,后续命令全部进入队列缓存,不会立刻执行 127.0.0.1:6379> multi OK # 命令入队,返回QUEUED标识 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> get k1 QUEUED 127.0.0.1:6379(TX)> get k2 QUEUED # exec:提交事务,一次性串行执行队列所有命令,逐条返回执行结果 127.0.0.1:6379(TX)> exec 1) OK # set k1执行结果 2) OK # set k2执行结果 3) "v1" # get k1查询结果 4) "v2" # get k2查询结果 # 清空数据库,准备下一组测试 127.0.0.1:6379> flushdb OK # ===================== 三、Redis事务场景2:discard放弃事务 ===================== 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> get k1 QUEUED 127.0.0.1:6379(TX)> get k2 QUEUED # discard:丢弃事务队列中全部命令,不执行任何操作 127.0.0.1:6379(TX)> discard OK # 事务作废,key不存在返回nil 127.0.0.1:6379> get k1 (nil) 127.0.0.1:6379> get k2 (nil) 127.0.0.1:6379> flushdb OK # ===================== 四、Redis事务场景3:入队阶段语法错误,整体作废 ===================== 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED # set语法错误(缺少value参数),入队直接报错 127.0.0.1:6379(TX)> set k3 (error) ERR wrong number of arguments for 'set' command 127.0.0.1:6379(TX)> get k1 QUEUED 127.0.0.1:6379(TX)> mget k2 k3 QUEUED # 只要入队时有语法错误,exec直接拒绝执行整个事务,全部失效 127.0.0.1:6379(TX)> exec (error) EXECABORT Transaction discarded because of previous errors 127.0.0.1:6379> flushdb OK # ===================== 五、Redis事务场景4:入队无错、执行时报错(无回滚) ===================== 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED # incr仅支持数字,存入字符串,执行阶段才会报错,入队不会报错 127.0.0.1:6379(TX)> incr k1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> get k2 QUEUED # 执行时:正确命令正常生效,出错命令单独报错,不会整体回滚(Redis事务不支持原子回滚) 127.0.0.1:6379(TX)> exec 1) OK # set k1执行成功 2) (error) ERR value is not an integer or out of range # incr执行失败 3) OK # set k2执行成功 4) "v2" # get k2查询成功

3. 适用场景

外卖附近商家、同城好友、门店范围检索、打车附近车辆匹配

4. 踩坑总结

经纬度有合法区间(经度-180180,纬度-85.0585.05),超出会报错;只能计算直线距离,不包含道路路程。

四、三大特殊类型完整总结

数据类型底层依托核心优势局限性核心业务场景
BitmapString占用空间极小,读写速度快仅支持0/1二元状态用户签到、用户状态标记
HyperLogLogString12KB固定内存,海量去重统计无法取出原始数据,存在微小误差UV独立访客、去重计数
GeospatialZSet内置地理计算,无需自研算法仅直线距离,坐标区间有限附近门店、同城匹配

整体学习感悟

  1. Redis每种数据结构都是为特定业务量身设计,没有万能类型,选型优先贴合业务需求;
  2. 三大新类型都是底层复用已有基础结构,Redis设计极度精简,没有冗余代码;
  3. 开发选型思路:
    • 二元状态统计 → Bitmap
    • 海量数据去重计数,不查明细 → HyperLogLog
    • 经纬度、范围、距离计算 → G
  4. 实操小建议:平时写Demo多模拟线上大数据量场景,才能直观感受到不同结构的内存差距。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 15:24:15

PDFdir:3分钟为扫描版PDF添加智能导航的终极解决方案

PDFdir:3分钟为扫描版PDF添加智能导航的终极解决方案 【免费下载链接】pdfdir PDF导航(大纲/目录)添加工具 项目地址: https://gitcode.com/gh_mirrors/pd/pdfdir 你是否曾经面对一本几百页的扫描版PDF电子书,却因为没有书…

作者头像 李华
网站建设 2026/8/7 15:23:22

终极指南:5个步骤在Android上安装开源漫画阅读器Mihon

终极指南:5个步骤在Android上安装开源漫画阅读器Mihon 【免费下载链接】mihon Free and open source manga reader for Android 项目地址: https://gitcode.com/gh_mirrors/mi/mihon 还在为寻找一款免费、无广告的漫画阅读应用而烦恼吗?Mihon作为…

作者头像 李华
网站建设 2026/8/7 15:21:37

《创业团队选型成本收益分析 线上高并发排障实战》

《创业团队选型成本收益分析 线上高并发排障实战》 作者: 钟伊人 (钟哩哩) 技术方向: AI 效率工具产品化、智能项目管理、AI 辅助创业决策、操作系统与端侧 AI 结合💡 导语与现场排障背景 在最近一次线上压测复盘中,我们的 AI 智能服务集群触发了 P99 延…

作者头像 李华
网站建设 2026/8/7 15:18:42

ZTE光猫工厂模式技术深度剖析与安全访问解决方案

ZTE光猫工厂模式技术深度剖析与安全访问解决方案 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 在当今网络设备管理领域,ZTE光猫设备作为家庭和企业网络的核心组件&#x…

作者头像 李华
网站建设 2026/8/7 15:18:26

Linux目录树状图工具tree命令详解:从安装到高阶应用

1. 从“ls”到“tree”:为什么我们需要一个目录树状图工具 在Linux世界里, ls 命令无疑是每个用户最先接触、使用最频繁的命令之一。它简洁、高效,能快速列出目录内容。但当你面对一个嵌套了十几层、包含数百个文件和子目录的复杂项目结构时…

作者头像 李华
网站建设 2026/8/7 15:18:07

128GB M3 Max本地部署DeepSeek V4 Flash:1M上下文实战与优化策略

1. 项目缘起:当顶级大模型遇上个人工作站最近圈子里讨论得最火的话题之一,就是DeepSeek V4 Flash这个模型。作为DeepSeek家族的新成员,它凭借MoE(专家混合)架构和高达1M(一百万)的上下文长度&am…

作者头像 李华