1. IM项目中的好友管理子服务概述
在即时通讯(IM)系统架构中,好友管理子服务承担着用户关系链维护的核心职能。这个看似基础的功能模块实际上需要处理诸多复杂场景:从好友申请的发起、审批到关系链的同步更新,从黑名单管理到分组标签维护,每个环节都直接影响着用户体验和系统稳定性。
以主流IM产品为例,微信的好友管理逻辑就经历了多次迭代:早期简单的双向确认机制,到后来支持设置朋友圈权限、添加备注标签,再到如今支持仅聊天、朋友圈可见范围等精细化控制。这些演进背后都是好友管理子服务的持续优化。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 好友管理子服务的核心功能设计
2.1 好友关系建模
关系型数据库设计中通常采用以下表结构:
sql复制CREATE TABLE user_relationship (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL COMMENT '主用户ID',
friend_id BIGINT NOT NULL COMMENT '好友用户ID',
relation_type TINYINT NOT NULL COMMENT '0-好友 1-黑名单 2-已删除',
remark VARCHAR(50) COMMENT '好友备注',
group_id INT COMMENT '分组ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_user_friend (user_id, friend_id)
);
关键设计要点:使用组合唯一索引防止重复关系,通过relation_type字段实现软删除,避免物理删除导致的历史记录丢失。
2.2 好友申请流程
完整的申请审批流程应包含以下状态机:
code复制[发起申请] → [待审核] → ([同意] → [成为好友] / [拒绝] → [结束])
↳ [过期] → [结束]
实际代码实现建议采用状态模式:
java复制public interface FriendApplyState {
void handle(FriendApplyContext context);
}
public class PendingState implements FriendApplyState {
@Override
public void handle(FriendApplyContext context) {
if(context.isExpired()) {
context.setState(new ExpiredState());
} else if(context.isApproved()) {
context.setState(new ApprovedState());
}
// 其他处理逻辑...
}
}
2.3 关系链同步机制
当好友关系变更时,需要采用多级缓存策略保证数据一致性:
- 先更新数据库
- 删除Redis缓存
- 通过MQ通知各端进行本地缓存更新
典型的消息通知格式:
json复制{
"event_type": "friend_update",
"operator": 10001,
"target_user": 10002,
"operation": "add",
"timestamp": 1630000000
}
3. 高并发场景下的技术挑战
3.1 热点用户问题处理
当明星用户发布动态时,其粉丝关系链查询可能形成读热点。解决方案:
- 采用缓存分片:对用户ID进行hash分片到不同Redis实例
- 本地缓存:客户端缓存最近联系人列表
- 降级策略:超时后返回最近缓存数据
3.2 分布式事务一致性
跨服务的添加好友操作需要保证:
- 申请记录写入
- 双方关系建立
- 通知消息发送
建议采用TCC模式:
python复制def add_friend_try(user_id, friend_id):
# 预留资源
reserve_relation(user_id, friend_id, status='pending')
reserve_relation(friend_id, user_id, status='pending')
def add_friend_confirm(user_id, friend_id):
# 确认执行
update_relation(user_id, friend_id, status='friend')
send_notification(friend_id, 'friend_accept')
def add_friend_cancel(user_id, friend_id):
# 取消预留
delete_relation(user_id, friend_id)
delete_relation(friend_id, user_id)
4. 性能优化实践方案
4.1 关系链分页查询优化
传统分页在深度分页时性能急剧下降:
sql复制-- 不推荐写法
SELECT * FROM user_relationship WHERE user_id=1 LIMIT 10000,20;
优化方案采用游标分页:
sql复制SELECT * FROM user_relationship
WHERE user_id=1 AND id > 10000
ORDER BY id ASC LIMIT 20;
4.2 批量操作合并
对于频繁的好友状态更新,可采用写合并策略:
go复制type FriendUpdate struct {
UserID int64
FriendID int64
Action string // 'add'/'delete'/'block'
}
func BatchUpdate(updates []FriendUpdate) {
// 合并相同用户的多次操作
merged := make(map[int64]map[int64]string)
for _, u := range updates {
if _, ok := merged[u.UserID]; !ok {
merged[u.UserID] = make(map[int64]string)
}
merged[u.UserID][u.FriendID] = u.Action
}
// 批量执行数据库操作
batchExec(merged)
}
5. 安全与权限控制
5.1 敏感操作验证
所有修改好友关系的接口必须验证操作者身份:
javascript复制router.post('/friends/:id', authMiddleware, (req, res) => {
if(req.user.id !== parseInt(req.params.id)) {
return res.status(403).json({error: '无权操作'});
}
// 处理逻辑...
});
5.2 数据可见性控制
好友信息的可见范围需要严格校验:
java复制public List<FriendInfo> getFriendList(Long userId, Long requesterId) {
if(!userId.equals(requesterId)) {
// 非本人查询需要检查权限
if(!privacyService.canViewFriends(userId, requesterId)) {
throw new PermissionDeniedException();
}
return filterSensitiveInfo(friendRepository.findByUserId(userId));
}
return friendRepository.findByUserId(userId);
}
6. 监控与运维要点
6.1 关键指标监控
需要建立以下监控项:
- 好友操作成功率
- 关系链查询延迟
- 好友申请处理时长
- 缓存命中率
Prometheus配置示例:
yaml复制- name: friend_service
rules:
- record: friend_add_success_rate
expr: sum(rate(friend_add_total{status="success"}[5m])) / sum(rate(friend_add_total[5m]))
6.2 数据迁移方案
当需要调整关系存储结构时,应采用双写方案:
- 新版本服务同时写入新旧两套存储
- 后台任务逐步迁移历史数据
- 验证数据一致性后切换读路径
- 最终清理旧数据
7. 前沿技术演进方向
7.1 图数据库应用
对于复杂社交关系,Neo4j等图数据库能更高效处理多度关系查询:
cypher复制MATCH (u:User)-[:FRIEND]->(f:User)-[:FRIEND]->(fof:User)
WHERE u.id = '1001' AND NOT (u)-[:FRIEND]->(fof)
RETURN fof LIMIT 10
7.2 服务网格治理
通过Istio实现精细化的流量控制:
yaml复制apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: friend-service
spec:
host: friend-service
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
outlierDetection:
consecutiveErrors: 5
interval: 10s
baseEjectionTime: 30s
在实际项目中,我们发现好友管理服务最容易被低估的复杂性在于异常场景的处理。比如当两个用户同时向对方发送好友申请时,如何避免产生重复关系;或者在分布式环境下如何处理网络分区导致的关系状态不一致。这些都需要在业务逻辑层做好幂等设计和冲突解决机制。
