这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
技术方案
热搜系统的核心挑战在于实时性与高性能的平衡。我们需要在海量数据中快速计算热度、维护排行榜,并支持高频查询。本节将对比不同技术方案的优劣,并给出推荐的架构设计。
方案对比
1. 关系型数据库(MySQL/PostgreSQL)
优势:
- 数据持久化可靠,支持事务
- 查询灵活,支持复杂关联
- 生态成熟,运维成本低
劣势:
- 排序操作性能差,
ORDER BY score DESC在大数据量下效率低 - 无法高效支持实时榜单更新
- 写操作频繁时锁竞争激烈
适用场景: 仅适合存储原始数据,不适合直接用于热搜排行榜计算。
2. Elasticsearch
优势:
- 强大的全文检索能力
- 支持复杂的聚合查询
- 水平扩展能力强
劣势:
- 实时性有限(默认刷新间隔 1 秒)
- 资源消耗大,内存占用高
- 排序性能不如专用数据结构
- 运维复杂度高
适用场景: 适合搜索场景,但不适合作为热搜排行榜的核心存储。
3. Redis ZSet(Sorted Set)
优势:
- 时间复杂度优秀:
ZADDO(log N),ZREVRANGEO(log N + M) - 原子操作,支持并发更新
- 内存存储,读写性能极高(10 万 + QPS)
- 天然支持排行榜功能(
ZRANK、ZREVRANK) - 支持按分数范围查询
劣势:
- 数据持久化依赖配置(RDB/AOF)
- 内存成本较高
- 不支持复杂查询
适用场景: 热搜排行榜的理想选择。
4. 混合方案
| 组件 | 职责 | 说明 |
|---|---|---|
| Redis ZSet | 实时热度计算与排行 | 核心数据结构 |
| MySQL | 原始数据存储 | 持久化备份 |
| Kafka | 异步消息队列 | 削峰填谷,解耦计算 |
| Flink/Spark | 离线热度计算 | 补充实时计算的不足 |
推荐架构:基于 Redis ZSet 的热搜系统
核心数据结构
┌─────────────────────────────────────────────────────────────┐
│ Redis ZSet (hot_ranking) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Member (内容 ID) │ Score (热度值) ││
│ ├─────────────────────────────────────────────────────────┤│
│ │ "post:10086" │ 9876543.21 ││
│ │ "post:10087" │ 9654321.45 ││
│ │ "post:10088" │ 9432109.87 ││
│ │ ... │ ... ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘系统架构图
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 用户行为 │────▶│ Kafka │────▶│ 热度计算服务 │
│ (点赞/评论/ │ │ 消息队列 │ │ (Flink/自研) │
│ 浏览/分享) │ │ │ │ │
└──────────────┘ └──────────────┘ └──────┬───────┘
│
▼
┌──────────────┐
│ Redis ZSet │
│ (hot_ranking)│
└──────┬───────┘
│
┌────────────────────────────┼────────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 热搜接口 │ │ 榜单查询 │ │ 排名查询 │
│ /api/hot │ │ TOP 10/50 │ │ /api/rank │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└────────────────────────────┼────────────────────────────┘
│
▼
┌──────────────┐
│ MySQL │
│ (数据持久化) │
└──────────────┘核心操作流程
1. 热度更新流程
用户行为 → Kafka → 热度计算 → Redis ZADD → 异步持久化 MySQL伪代码示例:
2. 榜单查询流程
查询请求 → Redis ZREVRANGE → 返回 TOP N → 缓存层 → 响应伪代码示例:
性能对比数据
以下是在相同硬件配置(4C8G)下的性能测试结果:
| 方案 | 写入 QPS | 查询 QPS (TOP 50) | P99 延迟 | 内存占用 |
|---|---|---|---|---|
| MySQL (ORDER BY) | 2,000 | 500 | 150ms | 2GB |
| Elasticsearch | 8,000 | 3,000 | 80ms | 4GB |
| Redis ZSet | 50,000+ | 20,000+ | 5ms | 1GB |
| 混合方案 | 30,000 | 15,000 | 10ms | 3GB |
测试条件:100 万条数据,并发 1000,热度分数随机分布
关键指标说明
- 写入性能:热搜系统需要实时处理大量用户行为,写入性能至关重要
- 查询性能:榜单查询是高频读操作,需要低延迟响应
- 内存效率:热搜数据通常为热数据,适合存储在内存中
- 扩展性:支持水平扩展以应对流量增长
时间衰减策略
热搜榜单需要体现”时效性”,新内容应有机会上榜。推荐使用时间衰减因子:
当前热度 = 原始热度 × e^(-λ × Δt)其中:
λ:衰减系数(通常 0.01~0.1)Δt:距离内容发布的时间(小时)
实现方案:
- 定期重算:定时任务重新计算所有内容的热度分数
- 惰性更新:查询时动态计算衰减后的分数
- 分层榜单:按时间维度建立多个榜单(1 小时榜、24 小时榜、7 天榜)
总结
| 维度 | 推荐方案 |
|---|---|
| 核心存储 | Redis ZSet |
| 数据持久化 | MySQL |
| 消息队列 | Kafka |
| 计算引擎 | Flink / 自研服务 |
| 缓存策略 | Redis + 本地缓存 |
| 衰减策略 | 指数衰减 + 分层榜单 |
设计原则:
- 实时性优先,保证榜单秒级更新
- 读写分离,避免计算影响查询
- 渐进式优化,从简单方案开始迭代
- 监控告警,及时发现异常
下一章将深入探讨热度计算公式的设计与实现。