第 10 章:设计通知系统
简介
通知系统为现代应用提供及时的商品动态、活动、优惠和告警等信息。通知渠道包括:
- 推送通知(移动设备或桌面端);
- 短信;
- 电子邮件。
本章重点设计每天能够发送数百万条通知的可扩展系统。
第一步:理解问题
需求
- **通知类型:**推送通知、短信和电子邮件。
- **送达时效:**软实时,尽量减少延迟。
- **平台:**iOS、Android 和桌面端。
- **触发方式:**可由客户端应用触发,也可在服务端定时触发。
- 规模:
- **推送通知:**每天 1000 万条;
- **短信:**每天 100 万条;
- **电子邮件:**每天 500 万封。
- **退订支持:**用户可以关闭特定类型的通知。
第二步:概要设计
组件
通知渠道:
- **iOS 推送:**使用 Apple Push Notification Service(APNS)。
- **Android 推送:**使用 Firebase Cloud Messaging(FCM)。
- **短信:**使用 Twilio 或 Nexmo 等第三方服务。
- **电子邮件:**使用 SendGrid 或 Mailchimp 等商业邮件服务。
收集联系方式:

- 在安装应用或注册时收集设备令牌、电话号码和邮箱地址。
- 将联系方式存入数据库:
- **设备令牌表:**用于推送通知。
- **用户表:**用于邮箱地址和电话号码。
通知发送流程:

- 触发服务:
- 产生通知事件,如账单提醒和物流更新。
- 可以是微服务、定时任务或分布式系统。
- 通知服务器:
- 提供发送通知的 API。
- 对邮箱地址和电话号码进行基本校验。
- 从数据库或缓存获取渲染通知所需的数据。
- **第三方服务:**将通知送达用户。
- 触发服务:
初始设计的挑战
- **单点故障(SPOF):**唯一的通知服务器一旦故障,整个系统就会瘫痪。
- **扩容困难:**数据库、缓存和处理组件难以独立扩容。
- **性能瓶颈:**发送通知需要大量资源。
改进设计
<img src="/images/chapter-10/improved-design.png" alt="改进设计" width="500" />
- 将数据库和缓存从通知服务器中独立出来。
- 部署多台通知服务器,实现水平扩容。
- 使用消息队列解耦组件,并在通知量激增时提供缓冲。
- 增加工作进程,从队列中取出通知事件,交给对应的第三方服务发送。
第三步:详细设计
可靠性
防止数据丢失:

- 将通知数据持久化到数据库,并实现重试机制。
- 通知日志数据库用于保存通知记录。
去重:
- 检查事件 ID,避免重复发送通知。
- 通知事件到达时,先根据事件 ID 判断是否处理过;处理过则丢弃,否则发送。
补充组件
- **通知模板:**预定义格式,保证通知一致性并提高生成效率。
- 通知设置:
- 用户可以分别订阅或退订推送、短信和邮件。
- 设置保存在专门的通知设置表中。
- **限流:**限制向同一用户发送通知的频率。
- **重试机制:**第三方服务发送失败时重新尝试。
- **队列监控:**跟踪积压量,以便动态扩展工作进程。
- **事件追踪:**收集打开率、点击率和参与度等指标。
安全性
- 使用 AppKey 和 AppSecret 验证推送通知 API 请求。
通知流程

- 触发服务调用 API 请求发送通知。
- 通知服务器验证请求,并从缓存或数据库读取元数据。
- 通知事件进入消息队列。
- 工作进程处理事件,并调用第三方服务。
- 第三方服务将通知送达用户。
关键优化
- **水平扩容:**增加通知服务器以分担负载。
- **消息队列:**解耦处理流程,承受大量通知。
- **缓存:**缓存常用数据以降低延迟。
- **地理分布式处理:**按地理位置优化消息投递,提高性能。