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

资讯详情

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

03-特殊数据结构:Geo/Stream/Bitmap/HyperLogLog 业务场景落地

03-特殊数据结构:Geo/Stream/Bitmap/HyperLogLog 业务场景落地 特殊数据结构Geo/Stream/Bitmap/HyperLogLog 业务场景落地作者黒漂技术佬 | 系列Redis 缓存与高并发实战上一篇文章讲了五大基础数据结构那些是 Redis 的常规武器。今天聊四个特殊数据结构它们在特定场景下能发挥出惊人威力。先记住一句话选对数据结构代码量能少一半性能能翻十倍。一、Bitmap位图用几个字节搞定百万级统计它是什么Bitmap 不是存字符串而是直接操作二进制位。一个 Bitmap 可以看成一条很长很长的 0/1 序列每个位的值是 0 或 1。因为一个字节能存 8 个位所以用 Bitmap 存百万级数据内存开销极小。类比传统方式存100 万用户今天的签到状态每人一个 String Key内存可能几十 MB。BitMap 存同样的数据只需 100 万 bit ≈ 125 KB差了上百倍。常用命令SETBIT sign:2024073010011# 用户1001今天签到第1001位设1GETBIT sign:202407301001# 查用户1001是否签到BITCOUNT sign:20240730# 统计今天签到总人数BITOP AND result sign:0730 sign:0731# 两个位图做与运算连续签到场景 1无人售货柜每日签到运营搞活动每天在一台售货柜上签到扫码但不买也算连续签到 7 天送优惠券。# 用户 9527 在售货柜 3 号上签到SETBIT cabinet:3:sign:2024073095271# 统计今日签到人数BITCOUNT cabinet:3:sign:20240730# 返回342# 找连续 7 天都签到的用户与前 6 天 BITOP ANDBITOP AND streak cabinet:3:sign:0730 cabinet:3:sign:0729 cabinet:3:sign:0728\cabinet:3:sign:0727 cabinet:3:sign:0726 cabinet:3:sign:0725 cabinet:3:sign:0724 BITCOUNT streak# 返回28 28个用户连续7天签到注意Bitmap 的索引offset上限是 2^32 - 1约 42 亿所以偏移量最好用数字型用户 ID不要用 UUID。场景 2在线状态# 售货柜第3台在线 → 位置3设为1SETBIT cabinet:online31# 统计在线设备数BITCOUNT cabinet:online二、Geo地理位置附近的人、附近的柜子它是什么Geo 是 Redis 3.2 引入的地理位置数据类型底层基于 ZSet。你可以把经纬度坐标存进去然后按半径搜索附近的点。常用命令GEOADD locations116.40439.915北京站GEOADD locations121.47331.230上海站GEOPOS locations北京站# 返回经纬度GEODIST locations北京站上海站km# 两点距离GEORADIUS locations116.4039.9010km# 10公里内的点场景查找附近无人售货柜# 录入 10 台售货柜的坐标GEOADD cabinets120.15530.274cabinet:1GEOADD cabinets120.16030.280cabinet:2GEOADD cabinets120.17030.290cabinet:3# ... 省略 7 台# 用户当前位置 (120.158, 30.277)找 2 公里内的柜子GEORADIUS cabinets120.15830.2772km WITHDIST WITHCOORD# 1) cabinet:1 距离: 0.45 km 坐标: 120.155,30.274# 2) cabinet:2 距离: 0.55 km 坐标: 120.160,30.280# 3) cabinet:3 距离: 1.78 km 坐标: 120.170,30.290WITHDIST显示距离WITHCOORD显示坐标。用户 App 拿到结果直接在地图上标点体验丝滑。原理Geo 底层用 ZSet 的 score 存储 GeoHash 编码。GeoHash 是一种把二维经纬度映射为一维字符串的算法相邻地点的 GeoHash 前缀相同。三、HyperLogLog用 12KB 统计上亿 UV它是什么HyperLogLog 是一种概率性数据结构非精确统计用来估算一个集合里有多少个不重复的元素。核心优势不管数据量多大单个 HyperLogLog 只占用约12KB内存误差率约0.81%。常用命令PFADD uv:page:home user1 user2 user3 PFADD uv:page:home user2 user4# user2 重复不会重复计数PFCOUNT uv:page:home# 返回大概的 UV 数PFMERGE uv:total uv:page:home uv:page:detail# 合并多个页面场景智慧农业大棚 UV 统计一个农业物联网平台有上千个大棚每个大棚的数据监控页面需要统计 UV独立访客。传统方式要记每个访客 ID内存爆炸。用 HyperLogLogPFADD greenhse:42:uv101102103104# 42号大棚的访客PFCOUNT greenhse:42:uv# 返回4什么时候不用需要精确数字的场景别用。比如今天销售额统计用INCR不能用 HyperLogLog。UV 趋势可以接受 0.81% 误差就用它。四、Stream流Redis 版 Kafka消息队列的完全体它是什么Redis 5.0 引入的重量级数据结构。之前用 List 做消息队列缺了确认机制Pub/Sub 又没持久化。Stream 补齐了这两个短板支持消费者组、消息确认、消息回溯俨然一个轻量级的 Kafka。核心命令# 生产者发消息XADD mystream * sensor temp1 value25.3# ↑ *表示自动生成消息ID# 消费者读消息非阻塞从最早开始XREAD COUNT2STREAMS mystream0# 创建消费者组XGROUP CREATE mystream group10# 消费者组内读消息XREADGROUP GROUP group1 consumer1 COUNT1STREAMS mystream# ↑ 只读新消息# 确认处理完成XACK mystream group1 消息ID场景工控设备消息可靠投递智慧工厂里每台设备不断上报状态到消息队列。用 List 的问题消费者崩溃消息丢了用 Pub/Sub 的问题断开期间的消息收不到。用 Stream生产者设备采集程序 → XADD device:events * device_id D001 status RUNNING temp 42.5 消费者组 group-monitoring3 个消费者分摊处理 → XREADGROUP ... → 处理 → XACK → 确认完成消费者挂了消息会pending其他消费者可以认领重新处理XCLAIM。消息丢了Stream 持久化存储哪怕重启 Redis开启 AOF消息还在。回溯历史指定消息 ID 范围即可。生产注意Stream 消息不会自动删除需要手动XTRIM或设MAXLEN限制长度否则内存会无限增长。选型速查数据结构一句话用途典型场景Bitmap用几百 KB 统计百万用户行为签到、活跃度、布隆过滤Geo存坐标、算距离、找附近LBS、附近门店/设备HyperLogLog12KB 估算海量去重数UV、日活、独立设备数Stream可靠的消息队列设备数据、订单流水、日志收集四个特种兵各自在特定战场上以一当百。掌握它们你的 Redis 工具箱才算真正完整。
返回列表