社交架构:Feed流、消息推送与关系链
社交架构:Feed流、消息推送与关系链
社交系统架构概览
社交系统的核心是用户关系和内容分发。主要模块包括:用户系统、关系链、Feed流、消息推送、内容存储、推荐系统。
社交系统架构:
接入层:负载均衡、API网关、限流
业务层:
- 用户服务:注册、登录、资料管理
- 关注服务:关注、取关、关系查询
- Feed服务:Feed流生成、分发、排序
- 消息服务:私信、通知、推送
- 内容服务:图文、视频、动态
- 推荐服务:内容推荐、用户推荐
数据层:MySQL、Redis、HBase、Elasticsearch
Feed流架构设计
Feed流是社交系统的核心,需要根据用户关注关系生成个性化的时间线。常见的方案有推模式、拉模式、推拉结合。
三种Feed流方案对比:
推模式(写扩散):
原理:用户发布内容时,推送到所有粉丝的Feed流
优点:读取快,直接返回
缺点:写放大,大V问题严重
适用:粉丝数有上限的场景
拉模式(读扩散):
原理:用户请求Feed时,实时拉取所有关注者的最新内容
优点:写入简单,无数据冗余
缺点:读取慢,需要实时计算
适用:粉丝数少,关注数多的场景
推拉结合:
原理:普通用户用推模式,大V用拉模式
优点:平衡读写性能
缺点:实现复杂,需要区分用户类型
适用:主流社交平台
// Feed流生成服务
@Service
public class FeedService {
@Autowired
private FeedRepository feedRepository;
@Autowired
private FollowService followService;
// 推模式:发布时推送到粉丝Feed
public void publishFeed(UserPost post) {
// 1. 保存帖子
feedRepository.savePost(post);
// 2. 获取粉丝列表
List<Long> followers = followService.getFollowers(post.getUserId());
// 3. 推送到粉丝Feed
for (Long followerId : followers) {
feedRepository.pushToFeed(followerId, post.getId());
}
}
// 拉模式:请求时实时生成
public List<FeedItem> getFeed(Long userId, int page, int size) {
// 1. 获取关注列表
List<Long> following = followService.getFollowing(userId);
// 2. 拉取每个关注者的最新帖子
List<FeedItem> items = new ArrayList<>();
for (Long followeeId : following) {
List<Post> posts = feedRepository.getLatestPosts(followeeId, 10);
items.addAll(convertToFeedItems(posts));
}
// 3. 排序和分页
items.sort(Comparator.comparing(FeedItem::getCreateTime).reversed());
return paginate(items, page, size);
}
}
关系链存储设计
社交系统的关系链是核心数据,需要支持高效的关注/取关、粉丝查询、共同好友等操作。
# 关系链存储方案
class RelationshipService:
def __init__(self):
self.mysql = MySQLStorage() # 持久化存储
self.redis = RedisCache() # 热点数据缓存
def follow(self, user_id, target_id):
# 1. 写入MySQL
self.mysql.insert_follow(user_id, target_id)
# 2. 更新Redis缓存
self.redis.add_following(user_id, target_id)
self.redis.add_follower(target_id, user_id)
# 3. 异步更新Feed流
self.async_update_feed(user_id, target_id)
def get_following(self, user_id):
# 优先从Redis读取
following = self.redis.get_following(user_id)
if following is None:
following = self.mysql.get_following(user_id)
self.redis.set_following(user_id, following, ttl=3600)
return following
def get_common_friends(self, user_id1, user_id2):
# 获取共同好友
following1 = set(self.get_following(user_id1))
following2 = set(self.get_following(user_id2))
return list(following1.intersection(following2))
消息推送架构
消息推送需要支持多种推送渠道(站内信、App推送、短信、邮件),并保证消息的可靠投递。
// 消息推送服务
@Service
public class NotificationService {
@Autowired
private MessageQueue mq;
@Autowired
private PushChannelRegistry channels;
public void sendNotification(Notification notification) {
// 1. 持久化消息
saveNotification(notification);
// 2. 根据用户设置选择推送渠道
List<PushChannel> userChannels = getUserChannels(
notification.getUserId(),
notification.getType()
);
// 3. 通过消息队列异步推送
for (PushChannel channel : userChannels) {
PushMessage message = PushMessage.builder()
.channel(channel)
.userId(notification.getUserId())
.title(notification.getTitle())
.content(notification.getContent())
.build();
mq.send("push-topic", message);
}
}
}
// 推送渠道注册
@Component
public class PushChannelRegistry {
private final Map<String, PushChannel> channels = new HashMap<>();
@PostConstruct
public void init() {
channels.put("app", new AppPushChannel());
channels.put("sms", new SmsPushChannel());
channels.put("email", new EmailPushChannel());
channels.put("web", new WebPushChannel());
}
public PushChannel getChannel(String channelType) {
return channels.get(channelType);
}
}
内容存储设计
社交内容包括文字、图片、视频等多种类型,需要设计合理的存储方案。
# 内容存储分层设计
class ContentStorage:
def __init__(self):
self.mysql = MySQLStorage() # 元数据
self.redis = RedisCache() # 热点内容
self.s3 = S3Storage() # 文件存储
self.cdn = CDNService() # 内容分发
def save_content(self, content):
# 1. 保存元数据到MySQL
content_id = self.mysql.save_metadata(content)
# 2. 上传文件到S3
if content.has_media():
file_url = self.s3.upload(content.get_media())
content.set_media_url(file_url)
# 3. 更新MySQL中的文件URL
self.mysql.update_media_url(content_id, file_url)
# 4. 加入Redis热点缓存
self.redis.cache_content(content_id, content, ttl=3600)
return content_id
def get_content(self, content_id):
# 优先从Redis读取
content = self.redis.get_content(content_id)
if content is None:
content = self.mysql.get_content(content_id)
if content:
self.redis.cache_content(content_id, content, ttl=3600)
# 通过CDN返回文件URL
if content and content.has_media():
content.set_media_url(self.cdn.get_url(content.get_media_url()))
return content
社交系统性能优化
社交系统的性能优化重点在于热点数据处理和缓存策略。
性能优化策略:
热点数据缓存:
- 用户资料缓存(Redis)
- 关注关系缓存(Redis)
- 热门内容缓存(Redis + CDN)
- Feed流缓存(Redis Sorted Set)
数据库优化:
- 读写分离
- 分库分表(按用户ID)
- 索引优化
- 热点数据预加载
异步处理:
- Feed流异步生成
- 消息推送异步处理
- 内容审核异步进行
- 统计数据异步计算
限流降级:
- 接口限流
- 热点用户降级
- 推送服务降级
- 搜索服务降级