面试知识库
进阶

通知系统设计#

一句话答案#

通知系统核心设计:业务方发通知请求 → MQ 削峰 → 通知中心(模板渲染+去重+频控+偏好过滤)→ 多渠道分发(站内信/Push/SMS/Email),通过优先级队列 + 限流 + 重试保证可靠送达。

核心要点

整体架构#

业务方 → 通知 API → Kafka → 通知中心引擎 → 渠道网关 → 用户

                    ┌───────────────┼───────────────┐
                    │               │               │
              ┌─────┴─────┐  ┌─────┴─────┐  ┌─────┴─────┐
              │ 站内信     │  │ Push推送   │  │ SMS/Email │
              │ (自建)    │  │ (APNs/FCM) │  │ (三方服务) │
              └───────────┘  └───────────┘  └───────────┘
plaintext

核心流程#

1. 业务方调用: notify(userId, templateId, params, channels, priority)
2. 消息入 MQ(Kafka),按 priority 分 Topic
3. 通知引擎消费:
   a. 模板渲染(标题/正文/跳转链接)
   b. 去重检查(同一通知 X 分钟内不重发)
   c. 频控检查(单用户每天最多 N 条 Push)
   d. 用户偏好过滤(用户关闭了某类通知)
   e. 免打扰时段检查(22:00-08:00 延迟发送)
4. 分发到各渠道网关
5. 记录发送日志 + 状态回调
plaintext

多渠道设计#

渠道特点送达率成本
站内信用户打开 App 才看到低(需主动查看)免费
Push系统通知栏高(Android)/中(iOS)免费
SMS100% 送达极高¥0.04/条
Email可能进垃圾箱
企微/钉钉工作场景免费

渠道降级策略:

高优先级通知(交易/安全):Push + SMS 双发
普通通知(营销):Push → 未送达 → 站内信
低优先级(推荐):仅站内信
plaintext

频控与去重#

// 频控:滑动窗口限流
// key = user:{userId}:channel:{channel}:date:{date}
// Redis INCR + EXPIRE

// 去重:
// key = dedup:{userId}:{templateId}:{bizId}
// Redis SETNX + TTL(如 5 分钟内同一通知不重发)

// 免打扰:
// 22:00-08:00 的通知写入延迟队列(Redis ZSET + score=目标发送时间)
java

优先级队列#

高优先级(P0):验证码、安全告警、交易通知 → 独立 Topic,专用消费者
中优先级(P1):订单状态、系统通知 → 共享 Topic
低优先级(P2):营销、推荐 → 低优先级 Topic,限速消费

实现:Kafka 多 Topic + 消费者资源倾斜
plaintext

模板管理#

模板示例:
  标题: "您的订单 {{orderNo}} 已发货"
  正文: "预计 {{deliveryDate}} 送达,快递单号 {{trackingNo}}"
  跳转: "app://order/detail?id={{orderId}}"

模板中心:运营后台配置,支持 A/B 测试不同文案
多语言:根据用户 locale 选择模板版本
plaintext

可观测性#

核心指标:
- 发送量/成功率/失败率(per channel)
- 端到端延迟(从业务调用到用户收到)
- 打开率/点击率(Push/Email 的 CTR)
- 退订率/投诉率(Email 域名信誉)
plaintext
面试回答(2分钟版)

通知系统的核心是「接收→处理→分发」三阶段。接收层提供统一 API 给业务方,消息入 Kafka 按优先级分 Topic 削峰。处理层是通知引擎,依次做模板渲染、去重(Redis SETNX 同一通知短时间不重发)、频控(滑动窗口限制每日推送量)、用户偏好过滤和免打扰时段检查。分发层对接多渠道网关:站内信自建、Push 走 APNs/FCM、SMS/Email 走三方。渠道降级策略是高优先级(验证码/安全)Push+SMS 双发,普通通知仅 Push,低优先级仅站内信。可靠性保证:MQ 持久化 + 消费确认 + 失败重试(指数退避)+ 渠道降级。优先级通过 Kafka 多 Topic + 消费者资源倾斜实现。免打扰用 Redis ZSET 延迟队列,到时间再消费发送。

追问与易错

追问方向:

  • “怎么保证通知不丢?”→ MQ 持久化 + 消费 ACK + 失败重试 + 状态追踪
  • “怎么防止用户被骚扰?”→ 频控 + 去重 + 偏好设置 + 免打扰时段
  • “Push 送达率怎么提高?”→ 多通道(厂商通道/自建长连接)+ 离线转 SMS
  • “百万用户群发怎么做?”→ 分批发送 + 限速 + 异步(不阻塞业务方)

易错点:

  • ❌ “通知就是发个消息”——需要去重、频控、偏好、降级等完整链路
  • ❌ “所有通知都 Push”——低优先级通知过多会导致用户关闭推送权限
  • ❌ “SMS 作为主要渠道”——成本高,仅用于高优先级和兜底