面试官:"如果让你设计微博的feed流推送系统,支持千万粉丝大V的实时推送,你会如何设计架构?"
微博、抖音等社交平台的feed流推送是系统架构中最具挑战性的场景之一,既要保证实时性,又要应对海量数据和高并发访问。今天我们就来深入解析这个经典面试题。
一、核心问题:为什么这么难?
1. 数据规模爆炸式增长
- 一个大V可能有5000万粉丝,一条微博需要推送给5000万人
- 每日新增内容量可达亿级别,存储和推送压力巨大
- 用户关系网络复杂,关注关系变化频繁
2. 实时性要求极高
- 用户期望发布后秒级看到新内容
- 热点事件时流量瞬间暴涨,系统要有弹性
- 移动端刷新频繁,API响应必须在毫秒级
3. 个性化与一致性平衡
- 不同用户看到不同的内容流
- 需要支持智能排序、广告插入等业务需求
- 保证跨设备、跨平台的内容一致性
二、架构设计方案:推拉结合的精妙平衡
2.1 三种基础模式对比
推模式(Push Model)
// 推模式核心实现:异步推送任务
@Service
public class PushService {
@Autowired
private UserRelationService userRelationService;
@Autowired
private FeedStorage feedStorage;
@Async("pushTaskExecutor")
public void pushPostToFollowers(Long authorId, Post post) {
// 获取作者的所有粉丝
List<Long> followerIds = userRelationService.getFollowers(authorId);
// 分批异步推送到粉丝的收件箱
int batchSize = 1000;
for (int i = 0; i < followerIds.size(); i += batchSize) {
List<Long> batch = followerIds.subList(i,
Math.min(i + batchSize, followerIds.size()));
// 异步处理每个批次
processBatch(batch, post);
}
}
@Async
public void processBatch(List<Long> followerIds, Post post) {
for (Long followerId : followerIds) {
// 推送到每个用户的个人时间线
feedStorage.pushToTimeline(followerId, post);
}
}
}
优点:
- 读取性能极佳:用户直接读取本地时间线
- 实时性好:发布后立即推送
- 适合活跃用户:在线用户能及时收到更新
缺点:
- 写入压力大:大V发布时产生海量写入操作
- 存储成本高:每个粉丝都需要存储副本
- 数据冗余:浪费存储空间
拉模式(Pull Model)
// 拉模式核心实现:动态聚合查询
@Service
public class PullService {
@Autowired
private UserRelationService userRelationService;
@Autowired
private PostService postService;
public List<Post> getUserFeed(Long userId, int page, int size) {
// 获取用户关注列表
List<Long> followingIds = userRelationService.getFollowings(userId);
// 聚合查询关注用户的最新动态
return postService.getLatestPosts(followingIds, page, size);
}
}
优点:
- 写入简单:发布时只需写入一次
- 存储节省:没有数据冗余
- 适合不活跃用户:冷数据不会占用资源
缺点:
- 读取性能差:需要实时聚合多个数据源
- 扩展性差:关注数多时查询缓慢
- 实时性难保证:聚合需要时间
2.2 混合模式:智能推拉结合
// 智能推拉结合实现
@Service
public class HybridFeedService {
@Autowired
private PushService pushService;
@Autowired
private PullService pullService;
@Autowired
private UserStatusService userStatusService;
/**
* 处理新内容发布
*/
public void handleNewPost(Long authorId, Post post) {
// 1. 获取粉丝列表
List<Long> followerIds = userRelationService.getFollowers(authorId);
// 2. 分离在线和离线用户
Map<Boolean, List<Long>> partitioned = followerIds.stream()
.collect(Collectors.partitioningBy(
userId -> userStatusService.isUserOnline(userId)
));
List<Long> onlineUsers = partitioned.get(true);
List<Long> offlineUsers = partitioned.get(false);
// 3. 对在线用户使用推模式
if (!onlineUsers.isEmpty()) {
pushService.pushToUsers(onlineUsers, post);
}
// 4. 对离线用户使用拉模式(标记需要更新)
offlineUsers.forEach(userId ->
userService.markNeedUpdate(userId)
);
}
/**
* 用户获取feed流
*/
public List<Post> getHybridFeed(Long userId, int page, int size) {
// 1. 先获取推模式存储的内容
List<Post> pushedPosts = feedStorage.getPushedPosts(userId, page, size);
// 2. 如果推模式内容不足,补充拉取内容
if (pushedPosts.size() < size) {
List<Post> pulledPosts = pullService.getLatestPosts(
userRelationService.getFollowings(userId),
0, size - pushedPosts.size()
);
pushedPosts.addAll(pulledPosts);
}
// 3. 智能排序、去重、广告插入等
return smartSort(pushedPosts);
}
}
2.3 冷热数据分离策略
// 冷热数据分离实现
@Service
public class TieredStorageService {
// 热数据:最近7天活跃用户的数据
@Cacheable(value = "hotFeed", key = "#userId")
public List<Post> getHotFeed(Long userId) {
return getFeedFromRedis(userId);
}
// 冷数据:7天前的数据
public List<Post> getColdFeed(Long userId, Date startDate, Date endDate) {
return getFeedFromHBase(userId, startDate, endDate);
}
// 用户活跃度判断
public boolean isActiveUser(Long userId) {
Long lastLogin = userStatusService.getLastLoginTime(userId);
return System.currentTimeMillis() - lastLogin < 7 * 24 * 3600 * 1000;
}
}
三、架构优化与扩展
1. 分级推送策略
- 明星用户:异步队列+批量推送
- 普通用户:实时推送
- 僵尸粉丝:延迟推送或仅标记
2. 智能缓存设计
// 多级缓存策略
public class MultiLevelCache {
// 本地缓存:Guava Cache,存储热点数据
// Redis集群:存储用户时间线数据
// HBase/数据库:存储历史数据
}
3. 流量削峰设计
- 消息队列缓冲写入压力
- 限流降级保护核心服务
- 自动扩缩容应对流量高峰
四、总结回顾
微博推送架构的核心设计哲学:
内容发布
→ 用户分组:[在线用户] vs [离线用户] vs [僵尸用户]
→ 推送策略:推模式(实时) + 拉模式(延迟) + 混合模式(智能)
→ 数据存储:热数据(内存) + 冷数据(磁盘) + 分层存储(成本优化)
→ 性能优化:缓存策略 + 异步处理 + 批量操作
五、面试建议
回答技巧:
- 先分析问题本质:数据量大、实时性要求高、读写比例失衡
- 对比方案优劣:详细说明推、拉模式的适用场景和限制
- 提出混合方案:推拉结合,根据用户状态智能选择
- 强调优化措施:冷热分离、缓存策略、异步处理等
- 考虑扩展性:如何支持更大规模、更多业务场景
加分回答点:
- 提到具体的技术选型:Redis、Kafka、HBase等
- 讨论数据一致性和可靠性保障
- 考虑监控、告警、降级等运维层面
- 提出AB测试和灰度发布方案
本文由微信公众号"程序员小胖"整理发布,转载请注明出处
明日面试题预告:大文件有限内存排序?