引言

在完成了高并发秒杀(Seckill)模块的硬核攻坚后,我们对 Redis 的理解从简单的 String/Hash 缓存跃升到了分布式锁与原子性控制。然而,Redis 的强大不仅仅在于“快”,更在于其丰富的数据结构能优雅地解决复杂的业务场景。

本文将复盘《黑马点评》后半部分的核心功能:好友关注、Feed 流推送、基于 LBS 的附近商户、海量用户签到与 UV 统计。这部分内容展示了 Redis 在社交网络(Social Network)和大数据统计(Big Data Statistics)场景下的应用。


一、 社交关系的基石:好友关注 (Set)

1. 业务场景

用户关注博主、取消关注;查看两个人的“共同关注”。

2. 传统 MySQL 痛点

如果在 MySQL 中做“共同关注”,需要复杂的 JOIN 查询:

SQL

SELECT * FROM tb_follow f1 JOIN tb_follow f2 ON f1.user_id = f2.user_id ...

随着数据量增加,这种全表扫描或索引交叉的效率极低。

3. Redis 解决方案:Set 集合

利用 Redis Set无序、唯一、支持集合运算的特性。

  • 存储结构: key = follows:userId, value = {targetId1, targetId2...}
  • 关注/取关:SADD / SREM

核心亮点(共同关注): 直接使用 SINTER (Intersection) 命令。

  • Bash
SINTER follows:UserA follows:UserB

Redis 在内存中进行集合交集运算,速度比数据库 Join 快几个数量级。


二、 信息流设计:达人探店 Feed 流 (Sorted Set)

1. 业务场景

博主发布新笔记,粉丝的收件箱(Inbox)里能刷到这些笔记,并按时间倒序排列。

2. 架构选型:Push 还是 Pull?

这是面试中的高频考点。

  • 拉模式 (Pull/读扩散): 博主发帖只存自己库,粉丝上线时去拉取所有关注博主的帖子并排序。优点是省空间,缺点是粉丝上线加载慢(高延迟)。
  • 推模式 (Push/写扩散): 博主发帖后,直接推送到所有粉丝的收件箱。优点是粉丝读取极快,缺点是博主如果是大 V(千万粉丝),写扩散压力巨大。

本项目策略: 采用推模式 (Push)。因为是点评类应用,大 V 相对较少,为了保证用户体验,牺牲一部分写入性能换取读取性能。

3. Redis 解决方案:ZSet (Sorted Set)

我们需要一个既能存 ID,又能排序的结构。

  • Key:feed:userId (每个用户都有一个收件箱)
  • Value:blogId (笔记 ID)
  • Score:timestamp (发布时间戳)

当博主发帖时,遍历其粉丝列表,执行:

Bash

ZADD feed:粉丝ID  时间戳  笔记ID

用户读取时,使用 ZREVRANGEBYSCORE 实现滚动分页(解决传统分页在动态列表中数据重复或丢失的问题)。


三、 LBS 地理位置:附近商户 (GEO)

1. 业务场景

用户打开 App,查询“我周围 3km 内的火锅店”,并按距离排序。

2. 底层原理:GeoHash

Redis 的 GEO 模块并非只有 API,其底层是 ZSet

  • 原理: 将二维的经纬度映射为一维的 Base32 字符串(GeoHash)。将地图划分为无数个网格,距离越近,GeoHash 字符串的前缀匹配度越高。
  • 存储:Member 是商户 ID,Score 是经纬度转换后的 52 位整数。

3. 核心优势

如果用 MySQL BETWEEN 经纬度查询,难以利用索引。Redis GEOSEARCH (或 GEORADIUS) 利用 ZSet 的跳表结构,能极其高效地搜索指定范围内的元素。


四、 大数据统计的魔法:签到与 UV

1. 场景 A:用户签到 (BitMap)

  • 需求: 记录用户一年的签到情况,并统计连续签到天数。
  • 痛点: 如果用数据库,一人一年 365 条记录,1000 万用户就是 36.5 亿行数据,极其浪费。
  • Redis 方案:BitMap (位图)
    • 将一个月看作一个二进制串。第 1 天签到就把第 0 位置为 1。
    • 空间占用: 1 个月 30 天 = 30 bit ≈ 4 byte。1000 万用户一个月仅需 40MB 内存
    • 统计:BITCOUNT 统计总天数;BITFIELD 获取一段二进制并通过位运算(与运算、右移)计算连续签到。

2. 场景 B:UV 统计 (HyperLogLog)

  • 需求: 统计网站的独立访客(UV),需要去重。
  • 痛点: 使用 Set 存储 IP 或 UserID 确实能去重,但如果 UV 达到千万级,内存占用几百 MB 甚至 G 级。
  • Redis 方案:HyperLogLog (HLL)
    • 原理: 概率统计算法(伯努利试验)。通过 Hash 值末尾 0 的数量来估算基数。
    • 优势: 无论统计多少数据,每个 Key 固定占用 12KB 内存
    • 代价: 约 0.81% 的误差(对于 UV 统计完全可接受)。

结语:从 CRUD 到架构思维

《黑马点评》的后半部分是对 Redis 丰富数据结构的一次深度阅兵。

  • Set 解决了社交关系的交叉查询;
  • ZSet 完美契合了 Feed 流的时序排序;
  • GeoHash 将复杂的二维空间搜索降维成一维查找;
  • BitMap & HLL 则展示了在海量数据下,如何用极致的空间换取性能。

作为后端工程师,选择合适的数据结构往往比写出复杂的算法更重要。这即是黑马点评后半部分部分真正的价值所在。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐