社交网络平台技术架构与实现指南
1. 社交网络系统架构概述
现代社交网络平台需要支持千万级用户并发访问、实时数据传输和复杂社交关系管理。基于WebFundamentals开源项目,我们构建了一套完整的社交网络技术栈,涵盖实时通信、数据存储、内容分发和安全防护等核心模块。
1.1 系统架构分层
1.2 核心技术栈
- 前端框架:React + Redux(组件化开发,状态管理)
- 后端技术:Node.js + Express(高性能API服务)
- 实时通信:WebSocket + Socket.IO(双向实时通信)
- 数据库:PostgreSQL(关系型数据)+ Redis(缓存)+ MongoDB(非结构化内容)
- 搜索引擎:Elasticsearch(全文搜索与内容索引)
- 部署环境:Docker + Kubernetes(容器化部署与编排)
2. 实时通信系统实现
社交网络的核心在于用户间的实时互动,我们采用WebSocket技术构建低延迟的实时通信系统。
2.1 WebSocket服务端实现
// WebSocket服务器集群实现
const WebSocket = require('ws');
const redis = require('redis');
const jwt = require('jsonwebtoken');
// 连接到Redis用于跨服务器通信
const pubClient = redis.createClient({ host: 'redis-server' });
const subClient = redis.createClient({ host: 'redis-server' });
// 创建WebSocket服务器集群
class WebSocketServer {
constructor() {
this.servers = new Map(); // 存储各服务器实例
this.connectionCount = 0;
this.redisPubSub = new RedisPubSub(pubClient, subClient);
// 初始化WebSocket服务器
this.init();
}
init() {
// 创建主WebSocket服务器
this.mainServer = new WebSocket.Server({
port: process.env.WS_PORT || 8080,
maxPayload: 1024 * 100, // 100KB最大消息大小
perMessageDeflate: { threshold: 1024 } // 压缩阈值
});
// 处理新连接
this.mainServer.on('connection', (ws, req) => {
this.handleConnection(ws, req);
});
// 集群间消息广播
this.redisPubSub.on('message', (channel, message) => {
const data = JSON.parse(message);
// 向除发送者外的其他用户广播消息
if (data.userId) {
this.broadcastToUser(data.userId, data.type, data.message);
} else {
this.broadcastToChannel(data.channel, data.type, data.message);
}
});
console.log(`WebSocket server started on port ${process.env.WS_PORT || 8080}`);
}
// 处理新连接
async handleConnection(ws, req) {
this.connectionCount++;
console.log(`New WebSocket connection. Total: ${this.connectionCount}`);
// 从请求URL获取认证令牌
const token = new URL(req.url, `http://${req.headers.host}`).searchParams.get('token');
let userId = null;
try {
// 验证JWT令牌
const decoded = jwt.verify(token, process.env.JWT_SECRET);
userId = decoded.userId;
// 存储用户连接信息
this.storeUserConnection(userId, ws);
// 处理消息
ws.on('message', (data) => this.handleMessage(ws, userId, data));
// 处理断开连接
ws.on('close', () => {
this.connectionCount--;
this.removeUserConnection(userId, ws);
console.log(`WebSocket connection closed. Total: ${this.connectionCount}`);
});
// 发送连接成功消息
ws.send(JSON.stringify({
type: 'connection_established',
userId,
timestamp: Date.now()
}));
} catch (error) {
console.error('WebSocket authentication failed:', error);
ws.close(4001, 'Authentication failed');
}
}
// 处理接收到的消息
handleMessage(ws, userId, data) {
try {
const message = JSON.parse(data.toString());
console.log(`Received message from user ${userId}:`, message);
// 根据消息类型处理
switch (message.type) {
case 'direct_message':
this.handleDirectMessage(userId, message.recipientId, message.content);
break;
case 'typing_status':
this.broadcastToUser(message.recipientId, 'typing', {
userId,
status: message.status
});
break;
case 'presence_status':
this.broadcastToUser(message.recipientId, 'presence', {
userId,
status: message.status
});
break;
default:
console.warn(`Unknown message type: ${message.type}`);
}
} catch (error) {
console.error('Error processing message:', error);
ws.send(JSON.stringify({
type: 'error',
message: 'Invalid message format',
timestamp: Date.now()
}));
}
}
// 存储用户连接
storeUserConnection(userId, ws) {
// 这里可以使用Redis存储活跃连接,实现跨服务器共享
this.redisPubSub.publish(`user:${userId}:connections`, JSON.stringify({
type: 'add',
wsId: ws._ultron.id,
timestamp: Date.now()
}));
}
// 广播消息到用户
async broadcastToUser(userId, type, message) {
const connections = await this.redisPubSub.get(`user:${userId}:connections`);
if (connections.length > 0) {
connections.forEach(wsId => {
const ws = this.servers.get(wsId);
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type,
message,
timestamp: Date.now()
}));
}
});
}
}
// 广播消息到频道
async broadcastToChannel(channel, type, message) {
const subscribers = await this.redisPubSub.get(`channel:${channel}:subscribers`);
if (subscribers.length > 0) {
subscribers.forEach(wsId => {
const ws = this.servers.get(wsId);
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type,
message,
channel,
timestamp: Date.now()
}));
}
});
}
}
// 关闭服务器
close() {
this.mainServer.close(() => {
console.log('WebSocket server closed');
});
}
}
// 主应用入口
const wss = new WebSocketServer();
// 处理进程退出
process.on('SIGINT', () => {
wss.close();
process.exit(0);
});
2.2 前端WebSocket客户端实现
// React组件中的WebSocket客户端
import React, { useState, useEffect, useRef } from 'react';
import io from 'socket.io-client';
const ChatComponent = ({ userId, recipientId }) => {
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const [typingStatus, setTypingStatus] = useState('');
const [isConnected, setIsConnected] = useState(false);
const [socket, setSocket] = useState(null);
const messagesEndRef = useRef(null);
// 连接WebSocket服务器
useEffect(() => {
const token = localStorage.getItem('auth_token');
const socket = io(`/ws?token=${token}`, {
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
path: '/ws/socket.io'
});
setSocket(socket);
// 连接状态
socket.on('connect', () => {
console.log('Connected to WebSocket server');
setIsConnected(true);
// 加入用户一对一聊天频道
socket.emit('join_channel', {
channel: `chat:${userId}:${recipientId}`,
user: userId
});
});
socket.on('disconnect', () => {
console.log('Disconnected from WebSocket server');
setIsConnected(false);
});
socket.on('error', (error) => {
console.error('WebSocket error:', error);
// 处理错误,可尝试自动重连
});
// 接收消息
socket.on('direct_message', (data) => {
if (data.message && data.message.userId === recipientId) {
setMessages(prev => [...prev, {
id: data.message.id,
userId: data.message.userId,
content: data.message.content,
timestamp: data.message.timestamp,
type: data.message.type || 'text'
}]);
}
});
// 接收用户状态更新
socket.on('typing', (data) => {
if (data.userId === recipientId) {
setTypingStatus(data.status === 'typing' ? data.userId : '');
}
});
// 清理函数
return () => {
socket.disconnect();
socket.off('connect');
socket.off('disconnect');
socket.off('direct_message');
socket.off('typing');
};
}, [userId, recipientId]);
// 自动滚动到底部
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
// 发送消息
const handleSendMessage = () => {
if (!newMessage.trim() || !socket) return;
socket.emit('send_message', {
type: 'direct_message',
recipientId,
content: {
id: Date.now().toString(),
userId,
content: newMessage,
timestamp: Date.now(),
type: 'text'
}
});
setNewMessage('');
};
// 监听输入状态
const handleInputChange = (e) => {
setNewMessage(e.target.value);
// 发送输入状态
if (e.target.value.length > 0) {
socket.emit('typing_status', {
recipientId,
status: 'typing'
});
} else {
socket.emit('typing_status', {
recipientId,
status: 'idle'
});
}
};
return (
<div className="chat-container">
<div className="chat-header">
<h3>与 {getUserName(recipientId)} 的聊天</h3>
<div className="connection-status">
{isConnected ? (
<span className="status-indicator online"></span> 在线
) : (
<span className="status-indicator offline"></span> 离线
)}
</div>
</div>
<div className="chat-messages">
{messages.map(message => (
<div
key={message.id}
className={`message ${message.userId === userId ? 'sent' : 'received'}`}
>
<div className="message-content">
{message.content}
</div>
<div className="message-time">
{formatTime(message.timestamp)}
</div>
</div>
))}
{typingStatus && (
<div className="typing-indicator">
{getUserName(typingStatus)} 正在输入...
</div>
)}
<div ref={messagesEndRef} />
</div>
<div className="chat-input">
<input
type="text"
value={newMessage}
onChange={handleInputChange}
placeholder="输入消息..."
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSendMessage();
}
}}
/>
<button onClick={handleSendMessage}>发送</button>
</div>
</div>
);
};
2.3 WebSocket集群通信优化
为支持千万级用户连接,我们采用Redis Pub/Sub实现WebSocket服务器间的消息广播,避免单点瓶颈:
- Redis Pub/Sub实现跨服务器通信
- 连接分片:按用户ID哈希路由到不同服务器
- 心跳检测与自动重连
- 连接池化与资源复用
- 断线重连机制与会话恢复
3. 社交关系与图谱系统
社交网络的核心是用户间的连接关系,我们设计了高效的社交图谱数据模型和查询算法。
3.1 社交关系数据模型
// 社交关系数据模型设计
class SocialGraphService {
constructor() {
this.userRepository = new UserRepository();
this.connectionRepository = new ConnectionRepository();
this.neo4jClient = neo4j.driver(
process.env.NEO4J_URI,
neo4j.auth.basic(process.env.NEO4J_USER, process.env.NEO4J_PASSWORD)
);
}
// 添加好友关系
async addFriendship(userId, friendId, options = {}) {
const session = this.neo4jClient.session();
try {
// 使用事务确保数据一致性
await session.run(
`MATCH (u1:User {id: $userId}), (u2:User {id: $friendId})
MERGE (u1)-[:FRIENDS_WITH {status: 'accepted', since: timestamp()}]->(u2)
MERGE (u2)-[:FRIENDS_WITH {status: 'accepted', since: timestamp()}]->(u1)
RETURN u1, u2`,
{ userId, friendId }
);
// 记录关系创建事件
await this.connectionRepository.createConnection({
userId,
targetId: friendId,
type: 'friend',
status: 'accepted',
createdAt: new Date()
});
// 通知双方
this.notificationService.sendFriendshipNotification(userId, friendId);
return { success: true, message: 'Friendship established' };
} catch (error) {
console.error('Error creating friendship:', error);
throw error;
} finally {
session.close();
}
}
// 获取用户好友列表(带分页)
async getUserFriends(userId, options = {}) {
const { page = 1, limit = 20, sort = 'recent' } = options;
const offset = (page - 1) * limit;
const session = this.neo4jClient.session();
try {
const query = `
MATCH (u:User {id: $userId})-[:FRIENDS_WITH]-(friend:User)
RETURN friend.id AS id, friend.name AS name, friend.avatar AS avatar,
friend.bio AS bio, friend.friendCount AS friendCount,
friend.followingCount AS followingCount, friend.followerCount AS followerCount,
(friend.lastActive > timestamp() - 86400000 * 7) AS isOnline,
relationship.status AS status,
relationship.since AS since
ORDER BY
CASE $sort
WHEN 'recent' THEN relationship.since
WHEN 'popular' THEN friend.friendCount
ELSE friend.name
END DESC
SKIP $offset
LIMIT $limit
`;
const result = await session.run(query, {
userId,
sort,
offset,
limit
});
const friends = result.records.map(record => {
const node = record.get('friend');
const rel = record.get('relationship');
return {
id: node.get('id'),
name: node.get('name'),
avatar: node.get('avatar'),
bio: node.get('bio'),
friendCount: node.get('friendCount'),
followingCount: node.get('followingCount'),
followerCount: node.get('followerCount'),
isOnline: node.get('isOnline'),
status: rel.get('status'),
since: new Date(rel.get('since'))
};
});
// 获取总数
const countResult = await session.run(
`MATCH (u:User {id: $userId})-[:FRIENDS_WITH]-(friend:User)
RETURN COUNT(friend) AS total`,
{ userId }
);
const total = countResult.records[0].get('total');
return {
friends,
pagination: {
total,
page,
limit,
pages: Math.ceil(total / limit)
}
};
} catch (error) {
console.error('Error fetching friends:', error);
throw error;
} finally {
session.close();
}
}
// 获取用户推荐好友(二度连接)
async getFriendRecommendations(userId, limit = 10) {
const session = this.neo4jClient.session();
try {
const query = `
MATCH (u:User {id: $userId})-[:FRIENDS_WITH]-(friend:User),
(friend)-[:FRIENDS_WITH]-(recommendation:User)
WHERE recommendation.id NOT IN
[ (u)-[:FRIENDS_WITH]-(x:User) | x.id ]
AND recommendation.id <> $userId
WITH friend, recommendation, COUNT(*) AS commonFriends
ORDER BY commonFriends DESC
LIMIT $limit
RETURN recommendation.id AS id, recommendation.name AS name,
recommendation.avatar AS avatar, recommendation.friendCount AS friendCount,
recommendation.bio AS bio, commonFriends
`;
const result = await session.run(query, {
userId,
limit
});
return result.records.map(record => ({
id: record.get('id'),
name: record.get('name'),
avatar: record.get('avatar'),
friendCount: record.get('friendCount'),
bio: record.get('bio'),
commonFriends: record.get('commonFriends')
}));
} catch (error) {
console.error('Error fetching recommendations:', error);
throw error;
} finally {
session.close();
}
}
// 检测用户关系状态
async checkRelationshipStatus(userId, targetId) {
const session = this.neo4jClient.session();
try {
const query = `
MATCH (u:User {id: $userId})-[r:FRIENDS_WITH]-(v:User {id: $targetId})
RETURN type(r) AS type, r.status AS status, r.since AS since
`;
const result = await session.run(query, {
userId,
targetId
});
if (result.records.length > 0) {
const rel = result.records[0].get('r');
return {
exists: true,
status: rel.get('status'),
since: new Date(rel.get('since'))
};
}
// 检查是否有未处理的好友请求
const requestResult = await session.run(
`MATCH (u:User {id: $userId})-[:PENDING_REQUEST]->(v:User {id: $targetId})
RETURN 'pending' AS status`,
{ userId, targetId }
);
if (requestResult.records.length > 0) {
return { exists: true, status: 'pending' };
}
return { exists: false };
} catch (error) {
console.error('Error checking relationship status:', error);
throw error;
} finally {
session.close();
}
}
}
3.2 社交图谱查询优化
- 使用Neo4j图数据库存储社交关系,实现高效路径查询
- 关系索引与缓存,热门用户关系预先计算
- 分页与延迟加载,避免大数据集一次性加载
- 推荐算法优化,基于共同好友、兴趣标签等多维度推荐
- 异步关系更新,避免阻塞主流程
4. 内容分享与互动系统
内容是社交网络的核心驱动力,我们构建了完整的内容发布、存储和互动系统。
4.1 内容发布与处理流程
// 内容服务核心实现
class ContentService {
constructor() {
this.contentRepository = new ContentRepository();
this.storageService = new StorageService();
this.analyticsService = new AnalyticsService();
this.searchIndexer = new SearchIndexer();
this.notificationService = new NotificationService();
}
// 创建内容
async createContent(userId, contentData) {
const {
type,
title,
text,
mediaUrls,
tags,
location,
privacy = 'public'
} = contentData;
// 1. 验证内容
if (!this.validateContent(type, text, mediaUrls)) {
throw new Error('Invalid content data');
}
// 2. 处理媒体文件
const processedMedia = await this.processMedia(mediaUrls, type);
// 3. 创建内容记录
const content = await this.contentRepository.create({
userId,
type,
title,
text,
media: processedMedia,
tags: tags || [],
location,
privacy,
status: 'pending' // 审核状态
});
// 4. 创建搜索索引
if (content.type !== 'video') { // 视频内容由专门服务处理
this.searchIndexer.indexContent(content);
}
// 5. 记录内容创建事件
this.analyticsService.trackContentCreation(userId, content.id, type);
// 6. 通知关注者
if (privacy !== 'private') {
this.notificationService.sendContentNotification(userId, content.id);
}
return content;
}
// 处理媒体文件
async processMedia(mediaUrls, type) {
if (!mediaUrls || mediaUrls.length === 0) return [];
const processedMedias = [];
for (const url of mediaUrls) {
try {
// 根据内容类型处理媒体
let processedUrl, metadata;
switch (type) {
case 'image':
// 图片处理:生成缩略图、压缩、格式转换
const [thumbnailUrl, optimizedUrl] = await this.storageService.processImage(url);
metadata = {
originalUrl: url,
thumbnailUrl,
optimizedUrl,
dimensions: await this.storageService.getImageDimensions(url),
size: await this.storageService.getFileSize(url)
};
processedUrl = optimizedUrl;
break;
case 'video':
// 视频处理:转码、生成缩略图、提取元数据
const [transcodedUrl, thumbnailUrl, metadata] = await this.storageService.processVideo(url);
processedUrl = transcodedUrl;
break;
case 'text':
case 'link':
default:
processedUrl = url;
break;
}
processedMedias.push({
url: processedUrl,
type: type,
metadata
});
} catch (error) {
console.error(`Error processing media ${url}:`, error);
// 记录错误但继续处理其他媒体
}
}
return processedMedias;
}
// 获取用户内容流
async getUserFeed(userId, options = {}) {
const {
page = 1,
limit = 20,
type = 'all',
withFollowing = true
} = options;
const offset = (page - 1) * limit;
// 1. 获取关注的用户
let followingIds = [];
if (withFollowing) {
const followingResult = await this.socialGraphService.getFollowingIds(userId);
followingIds = followingResult.followingIds;
}
// 2. 获取用户内容(包括关注的用户和自己的内容)
const contentResult = await this.contentRepository.getFeedContent({
userIds: followingIds,
userId,
type,
limit,
offset
});
// 3. 丰富内容数据(互动信息、用户信息)
const enrichedContent = await this.enrichContentData(contentResult.contents);
// 4. 计算分页信息
const total = contentResult.total;
return {
contents: enrichedContent,
pagination: {
total,
page,
limit,
pages: Math.ceil(total / limit)
}
};
}
// 互动功能:点赞
async likeContent(userId, contentId) {
// 1. 检查内容是否存在
const content = await this.contentRepository.getById(contentId);
if (!content) {
throw new Error('Content not found');
}
// 2. 检查是否已点赞
const existingLike = await this.interactionRepository.getInteraction({
userId,
contentId,
type: 'like'
});
if (existingLike) {
// 取消点赞
await this.interactionRepository.deleteInteraction(existingLike.id);
await this.contentRepository.decrementLikes(contentId);
return { success: true, action: 'unlike', count: content.likes - 1 };
} else {
// 添加点赞
const like = await this.interactionRepository.createInteraction({
userId,
contentId,
type: 'like'
});
await this.contentRepository.incrementLikes(contentId);
// 通知内容创建者
if (content.userId !== userId) {
this.notificationService.sendLikeNotification(
userId,
content.userId,
contentId
);
}
return { success: true, action: 'like', count: content.likes + 1 };
}
}
// 互动功能:评论
async commentOnContent(userId, contentId, commentData) {
const { text, parentCommentId } = commentData;
// 1. 验证评论内容
if (!text || text.trim().length === 0) {
throw new Error('Comment text cannot be empty');
}
// 2. 创建评论
const comment = await this.interactionRepository.createInteraction({
userId,
contentId,
type: 'comment',
parentId: parentCommentId,
text
});
// 3. 更新内容评论计数
await this.contentRepository.incrementComments(contentId);
// 4. 通知内容创建者和回复的用户
const content = await this.contentRepository.getById(contentId);
if (content.userId !== userId) {
this.notificationService.sendCommentNotification(
userId,
content.userId,
contentId,
comment.id
);
}
if (parentCommentId) {
const parentComment = await this.interactionRepository.getById(parentCommentId);
if (parentComment.userId !== userId) {
this.notificationService.sendReplyNotification(
userId,
parentComment.userId,
contentId,
comment.id
);
}
}
return comment;
}
}
4.2 内容Feed系统实现
// Feed算法实现
class FeedAlgorithm {
constructor() {
this.userRepository = new UserRepository();
this.contentRepository = new ContentRepository();
this.socialGraphService = new SocialGraphService();
this.algorithmConfig = {
// 权重配置
followingWeight: 0.7,
recencyWeight: 0.5,
engagementWeight: 0.3,
contentQualityWeight: 0.4,
// 算法参数
maxContentPerUser: 50,
maxSuggestedContent: 20,
minEngagementScore: 10
};
}
// 生成个性化Feed
async generatePersonalizedFeed(userId, options = {}) {
const {
page = 1,
limit = 20,
includeRecommended = true
} = options;
const offset = (page - 1) * limit;
// 1. 获取用户数据
const user = await this.userRepository.getById(userId);
if (!user) throw new Error('User not found');
// 2. 获取用户兴趣标签
const userInterests = await this.userInterestService.getUserInterests(userId);
// 3. 获取关注的用户
const { followingIds } = await this.socialGraphService.getFollowingIds(userId);
// 4. 获取关注用户的内容
const followingFeed = await this.getFollowingFeed(followingIds, {
limit: this.algorithmConfig.maxContentPerUser,
userInterests
});
// 5. 获取推荐内容
const recommendedFeed = includeRecommended
? await this.getRecommendedFeed(userId, userInterests, followingIds)
: [];
// 6. 合并并排序内容
const combinedFeed = [...followingFeed, ...recommendedFeed];
const rankedFeed = this.rankFeedItems(combinedFeed, userId);
// 7. 分页并返回
const paginatedFeed = rankedFeed.slice(offset, offset + limit);
return {
contents: paginatedFeed,
pagination: {
total: rankedFeed.length,
page,
limit,
pages: Math.ceil(rankedFeed.length / limit)
}
};
}
// 获取关注用户的内容
async getFollowingFeed(followingIds, options = {}) {
const { limit = 50, userInterests } = options;
if (!followingIds || followingIds.length === 0) {
return [];
}
// 获取关注用户的内容
const contentResult = await this.contentRepository.getContentByUsers(
followingIds,
{
limit,
sort: 'created_at',
order: 'desc'
}
);
// 过滤不感兴趣的内容
const filteredContent = this.filterByInterests(
contentResult.contents,
userInterests
);
return filteredContent;
}
// 获取推荐内容
async getRecommendedFeed(userId, userInterests, followingIds) {
const { maxSuggestedContent = 20 } = this.algorithmConfig;
// 1. 基于用户兴趣推荐
const interestBasedRecommendations = await this.recommendationService.getByInterests(
userInterests,
{
excludeUserIds: [userId, ...followingIds],
limit: maxSuggestedContent
}
);
// 2. 基于热门内容推荐
const trendingRecommendations = await this.recommendationService.getTrending(
{
excludeUserIds: [userId, ...followingIds],
limit: maxSuggestedContent - interestBasedRecommendations.length
}
);
// 合并推荐内容
return [...interestBasedRecommendations, ...trendingRecommendations];
}
// 对Feed项进行排序
rankFeedItems(contents, userId) {
// 获取用户互动历史
const userInteractions = this.interactionRepository.getUserInteractions(userId);
// 对每个内容项计算分数
const scoredContents = contents.map(content => {
// 1. 基础分数
let score = 0;
// 2. 关注用户权重
if (content.isFollowing) {
score += this.algorithmConfig.followingWeight * 10;
}
// 3. 时效性权重(时间衰减)
const ageScore = this.calculateAgeScore(content.createdAt);
score += ageScore * this.algorithmConfig.recencyWeight;
// 4. 互动权重(基于用户偏好)
const engagementScore = this.calculateEngagementScore(
content,
userInteractions
);
score += engagementScore * this.algorithmConfig.engagementWeight;
// 5. 内容质量权重(基于平台指标)
const qualityScore = this.calculateQualityScore(content);
score += qualityScore * this.algorithmConfig.contentQualityWeight;
return { ...content, score };
});
// 按分数排序
return scoredContents.sort((a, b) => b.score - a.score);
}
// 计算内容年龄分数(时间衰减)
calculateAgeScore(createdAt) {
const ageInHours = (Date.now() - createdAt) / (1000 * 60 * 60);
// 内容越新分数越高,24小时后分数衰减至0.5,72小时后衰减至0.25
return Math.max(0.1, Math.min(1, Math.pow(0.8, ageInHours / 24)));
}
// 计算互动分数(基于用户兴趣和历史互动)
calculateEngagementScore(content, userInteractions) {
// 基础分数
let score = 1;
// 互动类型权重:评论 > 分享 > 点赞 > 保存
const interactionWeights = {
like: 1,
comment: 3,
share: 5,
save: 2
};
// 计算用户互动分数
for (const interaction of userInteractions) {
if (interaction.contentId === content.id) {
score += interactionWeights[interaction.type] || 0;
}
}
// 内容互动热度(基于全局数据)
const globalEngagementScore = this.calculateGlobalEngagementScore(content);
score += globalEngagementScore;
// 确保分数不为负且不超过最大值
return Math.max(1, Math.min(10, score));
}
// 过滤用户不感兴趣的内容
filterByInterests(contents, userInterests) {
if (!userInterests || userInterests.length === 0) {
return contents;
}
// 对每个内容,检查是否与用户兴趣匹配
return contents.filter(content => {
// 内容标签匹配
const tagMatch = content.tags.some(tag =>
userInterests.includes(tag.toLowerCase())
);
// 内容作者匹配(关注的用户)
const authorMatch = content.author.isFollowing;
return tagMatch || authorMatch;
});
}
}
5. 安全与性能优化
5.1 安全防护策略
-
用户认证与授权
- JWT令牌基于角色的访问控制(RBAC)
- 密码加盐哈希存储(bcrypt)
- 多因素认证(MFA)支持
- 会话超时与自动登出
-
数据安全
- 敏感数据加密存储(AES-256)
- HTTPS/TLS 1.3加密传输
- 数据脱敏与最小化原则
- 定期安全审计与漏洞扫描
-
内容安全
- 基于AI的内容过滤系统
- 图片/视频内容自动审核
- XSS/CSRF防护措施
- 内容举报与人工审核流程
5.2 性能优化实现
-
多级缓存策略
// 实现Redis+内存多级缓存 class MultiLevelCache { constructor() { this.memoryCache = new Map(); this.redisClient = redis.createClient({ host: process.env.REDIS_HOST, port: process.env.REDIS_PORT }); this.memoryCacheTTL = new Map(); // 内存缓存过期时间 } // 获取缓存数据 async get(key, options = {}) { const { ignoreMemory = false, ignoreRedis = false } = options; // 1. 尝试从内存缓存获取 if (!ignoreMemory) { const now = Date.now(); const ttl = this.memoryCacheTTL.get(key); if (this.memoryCache.has(key) && (!ttl || ttl > now)) { return this.memoryCache.get(key); } else if (ttl && ttl <= now) { // 内存缓存已过期,清除 this.memoryCache.delete(key); this.memoryCacheTTL.delete(key); } } // 2. 尝试从Redis获取 if (!ignoreRedis) { try { const data = await this.redisClient.get(`cache:${key}`); if (data) { const parsedData = JSON.parse(data); // 同步到内存缓存 if (!ignoreMemory) { this.set(key, parsedData, { localOnly: true }); } return parsedData; } } catch (error) { console.error('Redis get error:', error); // Redis出错时降级到只使用内存缓存 } } // 缓存未命中 return null; } // 设置缓存数据 async set(key, value, options = {}) { const { ttl = 3600, localOnly = false, redisOnly = false } = options; const expiry = ttl ? Date.now() + (ttl * 1000) : null; // 1. 设置内存缓存 if (!redisOnly) { this.memoryCache.set(key, value); if (ttl) { this.memoryCacheTTL.set(key, expiry); // 设置内存缓存自动过期 setTimeout(() => { if (this.memoryCacheTTL.get(key) === expiry) { this.memoryCache.delete(key); this.memoryCacheTTL.delete(key); } }, ttl * 1000); } } // 2. 设置Redis缓存 if (!localOnly) { try { await this.redisClient.set( `cache:${key}`, JSON.stringify(value), ttl ? 'EX' : undefined, ttl ); } catch (error) { console.error('Redis set error:', error); // Redis出错时记录但不中断 } } } // 清除缓存 async invalidate(key, options = {}) { const { localOnly = false, redisOnly = false } = options; // 清除内存缓存 if (!redisOnly) { this.memoryCache.delete(key); this.memoryCacheTTL.delete(key); } // 清除Redis缓存 if (!localOnly) { try { await this.redisClient.del(`cache:${key}`); } catch (error) { console.error('Redis delete error:', error); } } } } -
数据库优化
- 读写分离:主库写入,从库读取
- 分库分表:按用户ID哈希分片
- 索引优化:针对高频查询创建复合索引
- 查询优化:分页查询、延迟加载、投影查询
-
前端性能优化
- 代码分割与懒加载
- 图片优化:WebP格式、响应式图片、渐进式加载
- 静态资源CDN分发
- 客户端缓存策略:Service Worker离线缓存
6. 总结与未来展望
社交网络平台是一个复杂的系统工程,需要综合考虑实时通信、数据存储、内容分发和安全防护等多个方面。通过WebFundamentals开源项目,我们构建了一套完整的社交网络技术栈,实现了从实时通信到内容互动的全流程解决方案。
关键技术亮点
- 实时通信系统:基于WebSocket的实时双向通信,支持千万级用户连接
- 社交图谱:Neo4j图数据库实现高效关系存储与查询,支持复杂社交关系
- Feed算法:个性化内容推荐,结合用户兴趣与社交关系
- 安全防护:多层次安全策略,保障用户数据安全
- 性能优化:多级缓存与数据库优化,支持高并发访问
未来发展方向
-
AI驱动社交体验
- 智能内容推荐系统
- 自动化内容生成与编辑
- 虚拟助手与聊天机器人
-
沉浸式社交体验
- AR/VR社交空间
- 元宇宙概念应用
- 3D互动与空间音频
-
去中心化社交
- 区块链技术保障数据主权
- 分布式身份认证
- P2P通信降低中心化依赖
通过持续优化和创新,社交网络平台将不断提升用户体验,创造更丰富的社交互动方式。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



