在大厂面试中,面试题:如何设计一个站内信系统是考察分布式系统设计与用户体验平衡能力的经典题目。站内信系统作为用户沟通与系统通知的核心载体,需支撑千万级用户的消息收发、已读未读状态同步、历史消息存储等功能,同时面临高并发写入(如营销活动群发)、低延迟读取(如实时通知)、数据一致性(如未读计数准确)三大核心挑战。本文将从需求分析、架构设计、数据库选型到性能优化,全面拆解站内信系统的设计要点,结合真实业务案例与技术选型,帮你在面试中展现从业务到底层的全链路设计能力,正如鳄鱼java在《分布式系统实战指南》中强调的:"优秀的站内信系统,是在可用性、性能与用户体验之间找到最优解的艺术。"
需求分析:站内信系统的核心功能与技术指标

设计站内信系统需先明确业务场景与技术边界,避免功能冗余或性能瓶颈。
1. 核心功能需求
- 消息类型: - 点对点消息(用户间私信) - 点对面消息(管理员群发通知、系统公告) - 业务触发消息(订单状态变更、活动提醒)
- 消息状态:未读/已读、删除/未删除、草稿/已发送
- 核心操作:发送消息、接收消息、标记已读、删除消息、查询历史消息、获取未读数量
- 扩展功能:消息撤回、富文本支持、附件发送、消息搜索
某社交平台数据显示:站内信系统日均消息量达5000万条,其中90%为系统通知,10%为用户私信;用户对私信的平均响应延迟容忍度为3秒,对系统通知的容忍度为30秒。
2. 非功能需求与技术指标
| 指标类型 | 具体要求 | 技术挑战 |
|---|---|---|
| 性能 | 单发消息响应时间<100ms,群发支持10万用户/分钟,未读数量查询<50ms | 高并发写入与缓存设计 |
| 可用性 | 系统可用性99.99%,消息不丢失、不重复 | 消息持久化与重试机制 |
| 数据一致性 | 未读数量与消息状态实时同步,跨设备状态一致 | 分布式事务与缓存一致性 |
| 存储容量 | 支持单用户历史消息存储1年,总存储容量10TB+ | 分库分表与冷热数据分离 |
架构设计:分层解耦的高可用架构
站内信系统需采用分层架构设计,通过异步化、缓存化、服务化实现高并发与高可用。
1. 整体架构图与核心组件
用户端 → API网关(限流/鉴权) → 站内信服务集群
↓
Kafka消息队列
↓
┌───────────┴───────────┐
↓ ↓
消息存储服务 消息推送服务
↓ ↓
存储层(Redis+MySQL) 推送通道(WebSocket/APP推送)
关键设计原则: - 异步化处理:消息发送通过Kafka异步处理,避免同步阻塞 - 读写分离:消息写入与读取分离,读取服务可独立扩容 - 多级缓存:Redis缓存未读数量与最新消息,减轻数据库压力 - 可扩展架构:服务无状态化,支持水平扩容应对流量波动
2. 核心服务职责拆分
- 接入服务:接收消息发送请求,参数校验(如内容长度、敏感词过滤),限流控制(如单用户每分钟最多发送20条私信)
- 消息存储服务:消费Kafka消息,写入数据库,维护消息状态(已读/未读)
- 消息查询服务:处理消息列表查询、未读数量统计、历史消息分页加载
- 推送服务:通过WebSocket/APP推送实时通知新消息,支持离线消息缓存
鳄鱼java技术团队建议:将站内信服务与业务系统解耦,通过API网关和消息队列隔离,避免业务波动影响站内信核心功能。
数据库设计:从单表到分库分表的演进
站内信系统的存储设计需平衡查询效率与存储成本,核心在于消息表的设计与拆分策略。
1. 核心表结构设计
采用"消息内容表+用户消息状态表"的分离设计,避免数据冗余:
-- 消息内容表(存储消息主体,支持群发复用) CREATE TABLE message_content ( id BIGINT PRIMARY KEY AUTO_INCREMENT, sender_id BIGINT NOT NULL COMMENT '发送者ID', content TEXT NOT NULL COMMENT '消息内容', send_time DATETIME NOT NULL COMMENT '发送时间', message_type TINYINT NOT NULL COMMENT '消息类型:1-私信,2-系统通知,3-营销消息', is_global TINYINT NOT NULL DEFAULT 0 COMMENT '是否全局消息:0-否,1-是' );-- 用户消息状态表(存储用户与消息的关联状态) CREATE TABLE user_message_status ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT '接收用户ID', message_id BIGINT NOT NULL COMMENT '消息ID', is_read TINYINT NOT NULL DEFAULT 0 COMMENT '是否已读:0-未读,1-已读', is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除:0-未删,1-已删', receive_time DATETIME NOT NULL COMMENT '接收时间', UNIQUE KEY uk_user_message (user_id, message_id), KEY idx_user_receive_time (user_id, receive_time) );
设计优势: - 群发消息只需存储一条message_content,通过user_message_status关联多用户,减少存储冗余 - user_message_status按user_id分表,查询用户消息时只需访问单张分表,提升效率
2. 分库分表策略
当用户量达千万级,user_message_status表需分库分表: - 分表键:按user_id哈希分表(如分128张表),确保单表数据量控制在1000万以内 - 分库键:按user_id范围分库(如0-1000万用户一个库),支持独立扩容 - 历史数据归档:超过1年的消息迁移至冷数据存储(如HBase),查询时通过联邦查询合并结果
鳄鱼java实测显示:分表后单表查询性能提升10倍,千万用户的消息列表查询延迟从500ms降至50ms。
核心功能实现:从消息发送到状态同步
1. 消息发送流程
消息发送需处理单发、群发、草稿保存等场景,核心流程如下:
// 单发消息伪代码
public void sendPrivateMessage(Long senderId, Long receiverId, String content) {
// 1. 敏感词过滤
if (sensitiveFilter.check(content)) {
throw new BusinessException("消息包含敏感词");
}
// 2. 保存消息内容
Long messageId = messageContentMapper.insert(new MessageContent(senderId, content)); 版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。





