面试官:我看你们项目里有个“新建群发消息”功能,能讲讲你是怎么设计和实现的吗?
面试者: 当然可以。这个“新建群发”功能是我们平台运营和健康管理团队使用频率很高的一个模块,主要用于向用户群体发送健康资讯、活动邀请、重要通知等信息。
根据任务工单要求,我负责后端的整体设计与开发,包括:富文本内容管理、接收者选择、定时/重复发送机制、历史记录查询以及高并发下的稳定性保障。
面试官:用户是怎么创建一条群发消息的?支持哪些内容格式?
面试者: 前端集成了一个富文本编辑器(如 Quill 或 TinyMCE),用户可以:
- 输入标题和正文;
- 插入图片(自动上传至OSS并生成外链);
- 添加超链接(跳转到文章、课程或挂号页);
- 使用加粗、列表、段落等基础排版功能。
提交时,内容以 HTML + JSON 元数据的形式传给后端。我们在服务端会对HTML做XSS过滤,只允许白名单标签(如<p>, <img>, <a>),防止安全风险。
同时,我们会将富文本内容做摘要提取,用于推送通知的预览文字,比如:“【健康提醒】春季过敏高发,请注意防护……”
面试官:群发支持即时、定时、重复发送,这些是怎么实现的?
面试者: 是的,这是我们设计的核心部分,基于一个统一的“消息任务调度系统”来管理不同类型的发送策略。
1. 即时发送
- 用户点击“立即发送”,后端立即触发消息分发流程;
- 异步拉取目标用户列表(支持按标签、科室、病种等筛选);
- 消息通过 RabbitMQ/Kafka 分片投递,由多个消费者并行处理;
- 支持多渠道下发:App推送、短信、微信模板消息。
2. 定时发送
- 用户设置未来某个时间点(如 2025-04-10 09:00);
- 系统将任务状态设为“待调度”,不立即执行;
- 我们使用 XXL-JOB 作为分布式任务调度中心,注册定时任务;
- 到达时间后,调度中心触发执行,进入“发送中”状态,后续流程与即时发送一致。
3. 重复发送
- 用户可设置周期规则,如“每周一上午9点”或“每月1日”;
- 后端解析为 Cron 表达式,注册到调度系统;
- 每次执行完成后,自动生成下一次计划,直到手动停止;
- 适用于周期性健康提醒,如“血压监测周报”、“用药提醒”。
面试官:怎么选择接收者?特别是患者搜索这块怎么做的?
面试者: 这是非常关键的一环。我们提供了多种方式来灵活选择接收者。
1. 手动选择
- 运营人员可在页面上直接勾选具体用户。
2. 按标签分组选择
- 支持按预设标签筛选,如:
- “糖尿病患者”
- “30-40岁女性”
- “近3个月未复诊用户”
- 标签数据来自用户画像系统,提前计算好并缓存到 Redis 或 Elasticsearch,避免实时查库慢。
3. 搜索患者功能
支持输入
关键字或拼音首字母
进行模糊匹配,例如:
- 输入“zsl” 可匹配“张三林”
- 输入“tou” 可匹配“头痛”
后端使用 Elasticsearch 实现高效检索,支持姓名、性别、年龄、最近就诊日期、简要病情描述等字段。
搜索结果以列表视图展示,包含基本信息,方便快速识别。
4. 我的患者(医生视角)
- 医生登录后,可查看自己服务过的患者列表,按最近一次服务时间倒序排列;
- 数据来源于“医患关系表”,通过索引优化保证查询性能。
所有选择方式最终都会生成一个“目标用户ID集合”,用于后续消息推送。
面试官:群发历史记录怎么管理?如果数据量很大怎么办?
面试者: “群发历史”模块非常重要,用于审计、复盘和效果分析。
我们做了以下设计:
1. 数据存储
- 所有已发送任务记录在
mass_message_history表中,核心字段包含:- 任务ID、标题、内容摘要
- 发送时间、发送类型(即时/定时/重复)
- 目标人数、实际发送数、成功率
- 创建人、操作日志
2. 查询性能优化
历史记录按发送时间降序排列,默认展示最近50条;
对大数据量场景,我们考虑使用
缓存 + 分页
策略:
- 将近期高频访问的历史记录缓存到 Redis;
- 老旧数据归档到独立的历史库,避免主表膨胀。
3. 支持导出与详情查看
- 可查看每条群发的详细内容和发送报表;
- 支持导出为Excel,供运营分析使用。
面试官:高并发下,比如一次性发100万人,系统会不会扛不住?
面试者: 这是我们必须面对的挑战。我们从架构设计、资源隔离、限流降级三个层面做了保障。
1. 异步化 + 消息队列
- 所有发送任务都走 Kafka/RabbitMQ,生产者只负责投递,消费者异步处理;
- 避免主线程阻塞,提升响应速度。
2. 分片批量处理
- 100万用户拆分为每批1万,多消费者并行处理;
- 每个消费者处理一个“用户分片”,避免单点压力过大。
3. 外部接口限流
- 对短信、微信推送等第三方接口做速率控制(如每秒1000条);
- 使用 Sentinel 实现熔断降级:若某渠道失败率过高,自动切换为“仅App推送”。
4. 幂等与重试
- 每条消息带唯一ID(message_id + user_id),防止重复发送;
- 发送失败的消息进入“重试队列”,最多重试3次,确保最终可达。
面试官:你怎么验证这个功能做对了?有没有测试方案?
面试者: 我们严格按照任务工单中的验收标准进行验证,主要从五个方面:
| 验收项 | 验证方式 |
|---|---|
| 消息创建 | 确保用户能成功填写标题、内容、选择接收者,保存为草稿或直接发送 |
| 接收者选择 | 测试手动选择、标签筛选、拼音搜索等多种方式是否准确匹配目标用户 |
| 发送与接收 | 在测试环境模拟发送,验证用户设备是否收到消息,内容一致 |
| 数据一致性 | 对比发送内容与接收内容,确保无丢失、乱码或格式错误 |
| 时间戳记录 | 检查数据库中 send_time 字段是否准确记录,支持按时间排序查询 |
此外,我们还进行了:
- JMeter压力测试:模拟10万用户并发群发,监控CPU、内存、数据库连接等资源使用情况;
- 生成压力测试报告:分析TPS、响应时间、错误率,优化瓶颈;
- 业务流程图 & ER图:输出设计说明书,明确表结构和状态流转;
面试官:你觉得这个功能最难的部分是什么?
面试者: 我认为最难的是平衡“灵活性”和“稳定性”。
- 运营需要足够灵活:能自由编辑内容、按各种条件筛选用户、支持定时重复;
- 但系统必须足够稳定:不能因为一次百万级群发导致整个平台卡顿。
我们的解决方案是:
前端灵活配置,后端异步解耦,核心链路可监控、可降级、可追溯。
这个功能虽然看似简单,但涉及内容管理、用户筛选、任务调度、消息推送、高并发处理等多个复杂模块,是一个典型的“小功能,大系统”。
作为Java开发,我不仅要写接口,更要设计一个可靠、可扩展、可运维的后台系统。
面试官:高并发场景下如何确保数据安全?
下面我将从“数据一致性、访问安全、内容合规、操作审计”四个维度,结合“新建群发”功能的实际场景,详细说明我们是如何在高并发下确保数据安全的。
一、数据一致性安全:防止错发、漏发、重复发
在高并发群发时,最怕的就是:
- 同一条消息给同一个用户发了多次(重复发)
- 应该收到的人没收到(漏发)
- 不该收到的人收到了(错发)
我们通过以下机制保障:
1. 唯一任务标识 + 幂等处理
- 每次群发任务生成全局唯一ID(如UUID);
- 每条消息发送记录包含
(task_id, user_id)联合主键; - 在插入发送记录前,先查询是否已存在,避免重复插入。
// 伪代码:幂等判断
if (sendRecordMapper.exists(taskId, userId)) {
return; // 已发送,直接跳过
}
sendRecordMapper.insert(new Record(taskId, userId, ...));2. 数据库乐观锁
- 更新用户状态或号源时,使用版本号控制:
UPDATE mass_message_task
SET send_count = send_count + 1, version = version + 1
WHERE id = ? AND version = ?如果影响行数为0,说明已被其他线程更新,当前操作失败,需重试或丢弃。
3. 分布式锁(Redis)
- 对关键操作(如任务状态变更)加锁:
SETNX lock:mass_send:task_123 true EX 5确保同一时间只有一个线程能修改任务状态,防止并发写入导致状态错乱。
二、访问安全:防止未授权操作和数据泄露
群发功能涉及大量用户隐私数据(如手机号、病情),必须严格控制访问权限。
1. 接口权限控制
- 所有群发相关接口都需登录,并校验角色权限:
- 运营人员:可创建、发送
- 医生:仅可查看“我的患者”并发送
- 普通用户:不可访问
- 使用 Spring Security + JWT 实现认证与鉴权。
2. 敏感数据脱敏
- 在日志、管理后台展示用户信息时,自动脱敏:
- 手机号 →
138****1234 - 姓名 →
张*林
- 手机号 →
- 导出Excel时也默认脱敏,需特殊权限才能申请明文导出。
3. HTTPS + 参数加密
- 所有接口走 HTTPS,防止中间人窃听;
- 对敏感参数(如用户ID列表)做加密传输,避免URL暴露。
三、内容安全:防止恶意内容传播
富文本内容可能被注入XSS脚本或违规信息,我们做了多层过滤。
1. HTML内容白名单过滤
- 使用 Jsoup 或 OWASP Java HTML Sanitizer 对富文本进行清洗;
- 只允许
<p>,<img src="trusted-domain">,<a href="https://">等安全标签; - 移除所有
onerror,onclick等事件属性。
2. 敏感词检测
- 提交内容前,调用敏感词过滤服务(基于DFA算法);
- 拦截“免费送药”“包治百病”“ guaranteed cure”等违规词汇;
- 检测到敏感词时,提示运营修改,无法直接发送。
3. 人工审核开关(可选)
- 对高风险内容(如涉及药品推广),可配置“需人工审核后才发送”;
- 审核通过后,状态变为“已批准”,调度系统才会执行。
四、操作审计与追溯:确保每一步都可查
在医疗平台,任何群发行为都必须可追溯,便于事后审计。
1. 完整操作日志
- 记录每一次关键操作:
- “用户A创建了群发任务”
- “用户B于10:00发送了任务ID=123的消息”
- “任务因短信接口超时失败,已重试2次”
日志包含:操作人、时间、IP、操作类型、任务ID。
2. 发送记录持久化
- 所有发送结果(成功/失败)都写入数据库;
- 支持按任务ID查询“谁收到了、谁没收到、失败原因”。
3. 定期对账机制
- 每天定时跑批,对比:
- 应发人数 vs 实际发送数
- App推送成功数 vs 微信回调数
- 发现不一致时,自动告警,人工介入排查。
五、极端情况下的安全兜底
1. 熔断与降级
- 如果微信推送接口异常,自动降级为“仅App推送”;
- 避免因第三方故障导致整个任务失败或数据混乱。
2. 流量控制
- 使用
Sentinel对群发接口限流:- 单用户每小时最多创建5个任务
- 每秒最多处理10个发送请求
- 防止恶意刷单或误操作压垮系统。
3. 数据备份与恢复
- 所有群发任务和发送记录每日备份;
- 支持按时间点恢复,防止误删或数据库故障导致数据丢失。