
1) 【一句话结论】采用分层微服务架构,结合分布式缓存(Redis)、消息队列(Kafka)、数据库分库分表(MySQL),通过Seata分布式事务保证跨库一致性,消息幂等处理避免重复消费,缓存双写(互斥锁+空值缓存)应对雪崩,最终一致性模型下延迟控制在1分钟内,平衡高并发性能与数据一致性。
2) 【原理/概念讲解】系统拆解为用户层(API网关)、服务层(好友/公会服务)、数据层(Redis+MySQL分库分表)。关键点:
3) 【对比与适用场景】(分布式事务方案对比):
| 方案 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| Seata (AT模式) | 分布式事务框架,支持本地事务与分布式事务切换 | 基于本地事务,低开销,支持补偿机制 | 跨库事务(如好友关系跨用户表) | 需配置事务管理器,补偿机制可能影响性能 |
| 2PC (两阶段提交) | 传统分布式事务,协调者与参与者两阶段 | 强一致性,但高并发下性能差,阻塞风险高 | 对一致性要求极高(如金融系统) | 适用于低并发场景,不适合社交系统 |
4) 【示例】(添加好友流程伪代码):
def add_friend(user_id_a, user_id_b):
# 1. 缓存穿透检查(互斥锁+空值缓存)
lock_key = f"friend_lock_{user_id_a}_{user_id_b}"
with redis_lock(lock_key, timeout=10):
if not cache.get(f"friend_list_{user_id_a}"):
friend_list = db.get_user_friends(user_id_a) # 数据库查
cache.set(f"friend_list_{user_id_a}", friend_list, expire=3600) # 缓存1小时
# 2. 检查是否已存在
if user_id_b in cache.get(f"friend_list_{user_id_a}"):
return "已存在"
# 3. 发送消息到Kafka(幂等)
msg_id = f"{user_id_a}_{user_id_b}"
kafka_producer.send("add_friend", value=msg_id, key=msg_id) # 消息唯一标识
# 4. 跨库事务(Seata)
with db.transaction():
db.add_friend(user_id_a, user_id_b) # 更新A好友列表
db.add_friend(user_id_b, user_id_a) # 更新B联系人列表
消费端:
def process_add_friend(msg):
user_id_a, user_id_b = msg.split('_')
with db.transaction():
db.add_friend(user_id_a, user_id_b)
db.add_friend(user_id_b, user_id_a)
5) 【面试口播版答案】面试官您好,针对社交系统(好友、公会)的高并发设计,我的核心方案是分层微服务架构+分布式缓存+消息队列+数据库分库分表+Seata分布式事务+消息幂等+缓存双写,平衡性能与一致性。具体来说:
系统分层:用户层(API网关)负责请求路由与限流,服务层(好友/公会服务)处理业务,数据层(Redis+MySQL分库分表)存储数据。关键技术点:分库分表按用户ID分库(每个库100万用户)、按时间分表(好友表按月),解决数据库瓶颈;Seata分布式事务(AT模式)保证跨库操作的原子性(如添加好友时同时更新两个用户的好友列表);Kafka消息队列解耦服务,添加好友时先发消息到队列,异步处理,避免服务阻塞;Redis缓存热点数据(如用户好友列表),减少数据库压力;缓存雪崩用随机过期时间+限流,缓存穿透用互斥锁+空值缓存(设置默认值,避免热点key失效后大量请求数据库);消息幂等通过消息唯一标识(用户ID+好友ID)避免重复消费。流程示例:用户A添加好友B,先检查Redis缓存(若缓存无数据则查数据库),检查是否已存在,然后发送消息到Kafka,后台任务通过Seata事务更新数据库,确保数据一致。最终一致性模型下,延迟控制在1分钟内,不影响用户体验。总结来说,这套方案通过分层解耦、缓存加速、消息异步处理、分布式事务保证一致性,能有效支撑高并发操作,同时保证数据最终一致。
6) 【追问清单】:
7) 【常见坑/雷区】: