Skip to content

面试官:我看你们项目里有个“新建群发消息”功能,能讲讲你是怎么设计和实现的吗?

面试者: 当然可以。这个“新建群发”功能是我们平台运营和健康管理团队使用频率很高的一个模块,主要用于向用户群体发送健康资讯、活动邀请、重要通知等信息。

根据任务工单要求,我负责后端的整体设计与开发,包括:富文本内容管理、接收者选择、定时/重复发送机制、历史记录查询以及高并发下的稳定性保障。


面试官:用户是怎么创建一条群发消息的?支持哪些内容格式?

面试者: 前端集成了一个富文本编辑器(如 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) 联合主键;
  • 在插入发送记录前,先查询是否已存在,避免重复插入。
java
// 伪代码:幂等判断
if (sendRecordMapper.exists(taskId, userId)) {
    return; // 已发送,直接跳过
}
sendRecordMapper.insert(new Record(taskId, userId, ...));

2. 数据库乐观锁

  • 更新用户状态或号源时,使用版本号控制:
sql
UPDATE mass_message_task 
SET send_count = send_count + 1, version = version + 1 
WHERE id = ? AND version = ?

如果影响行数为0,说明已被其他线程更新,当前操作失败,需重试或丢弃。

3. 分布式锁(Redis)

  • 对关键操作(如任务状态变更)加锁:
shell
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内容白名单过滤

  • 使用 JsoupOWASP 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. 数据备份与恢复

  • 所有群发任务和发送记录每日备份;
  • 支持按时间点恢复,防止误删或数据库故障导致数据丢失。