尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Redis三大特殊数据类型

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. 核心实操命令SETBIT key offset 0/1指定下标存入状态offset从0开始示例setbit sign:user1 0 1用户1当月1号签到GETBIT key offset查询指定位置bit值BITCOUNT key统计值为1的bit总数统计签到天数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个bitbit01、bit11 → 二进制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) 23. 适用场景用户签到打卡、APP登录状态标记、海量用户黑白名单、日活用户筛选4. 踩坑总结offset不要直接使用超大用户ID会造成大量空bit浪费内存仅适合二元状态多状态场景不适用。二、HyperLogLog亿级去重统计神器1. 底层原理专门做基数统计统计不重复元素数量核心优势是极致压缩内存无论存入多少数据单个HyperLogLog固定仅占用12KB内存最大可统计2^64个不同元素仅存在0.81%左右微小误差绝大多数互联网业务可以忽略。对比Set存储百万独立访客Set需要几十MBHLL仅12KB差距巨大。短板只能统计数量无法取出存入的原始数据。2. 核心实操命令PFADD key 元素添加数据自动去重示例pfadd uv:20260807 u001 u002 u003记录今日访客PFCOUNT key查询不重复元素总数网站UVPFMERGE 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的总去重数量32无重复结果为5 127.0.0.1:6379 pfcount k3 (integer) 53. 适用场景网站独立访客UV统计、搜索关键词去重计数、活动参与人数统计4. 踩坑总结如果业务必须获取全部唯一数据不能用HLL优先选择Set对数据精准度要求极高的金融场景慎用。三、Geospatial(GEO) 地理坐标类型1. 底层原理Redis3.2新增地理数据类型底层依托Zset有序集合实现将经纬度坐标编码成score存储原生封装地图相关计算指令不用自己写复杂地理算法。2. 核心实操命令GEOADD key 经度 纬度 名称存入地点坐标示例geoadd city 121.47 31.23 shanghaiGEOPOS key 地点获取目标经纬度GEODIST key A B km/m计算两点直线距离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事务场景2discard放弃事务 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内置地理计算无需自研算法仅直线距离坐标区间有限附近门店、同城匹配整体学习感悟Redis每种数据结构都是为特定业务量身设计没有万能类型选型优先贴合业务需求三大新类型都是底层复用已有基础结构Redis设计极度精简没有冗余代码开发选型思路二元状态统计 → Bitmap海量数据去重计数不查明细 → HyperLogLog经纬度、范围、距离计算 → G实操小建议平时写Demo多模拟线上大数据量场景才能直观感受到不同结构的内存差距。
返回列表