【通知系统】设计核心
【通知系统】设计核心
学习核心
- 如何设计一个【通知】系统?(系统的核心功能)
- 沟通对齐(问题切入分析)
- ① 通知推送类型:推送通知、短信、邮件
- ② 是否支持实时?(是一个实时系统吗?):软实时系统,希望用户可以尽快收到通知(如果系统处于高负荷工作状态可以接收稍许延迟)
- ③ 推送支持设备:支持多端设备,iOS设备、安卓设备和笔记本电脑/台式机
- ④ 什么时候触发通知?:通知可以由客户端应用程序触发,也可以由服务器端调度
- ⑤ 是否支持用户自由订阅?:用户可以选择退出,选择退出的用户将不再接收通知
- ⑥ 日内通知量级?:参考1000万条移动推送通知,100万条短信,500万封电子邮件
- 要点分析(或难点分析)
- ① 不同的通知类型支持:推送通知(IOS、Android)、SMS(短信)、Email(邮箱)
- 核心组件涉及:Provider(生产通知)、第三方推送服务、Client(客户端)
- ② 联系人信息收集流程:数据库设计(用户表、设备表,支持一个用户绑定多台设备)
- 当用户安装APP或者首次注册时便将用户信息通过系统提供的API存储到数据库中进行绑定
- ③ 通知发送/接收流程
- 基础版:单机服务构建一个最基础的通知流程,引入现存问题(单点故障、难以扩展、并发度差)
- 进阶版:基于基础版衍生问题,通过多机部署、独立Cache和DB、引入MQ等机制优化系统设计
- ④ 深入设计:从可靠性、其他组件因素等方面切入,优化系统设计
- 认证 & 速率限制:通知服务器配备了两个更关键的功能,认证(authentication)和速率限制(rate limiti)
- 引入重试(消息丢失问题) & 幂等性处理(消息重复问题):
- 添加了一个重试机制来处理通知失败。如果系统发送通知失败,它们会被放回消息队列中,工作者会重试预定的次数
- 针对已经通知过的消息固化到数据库中,每次发送通知前校验消息ID确认是否已经发送过,已发送的消息则不重复处理
- 通知模板:通知模板提供一致且高效的通知创建过程
- 监测 & 跟踪:为系统健康检查和未来改进增加了监测和跟踪系统
- ① 不同的通知类型支持:推送通知(IOS、Android)、SMS(短信)、Email(邮箱)
- 总结陈述
学习资料
🟢【通知系统】场景核心
🚀【通知系统】场景实战
1.沟通对齐
此处的沟通对齐方向,主核心方向是需求分析、请求量分析、精准度分析、难点/要点分析,可能还有涉及到其他的一些容量、设计等方面的对齐
① 需求分析
什么是【通知系统】?
近年来,通知系统已经成为许多应用程序非常流行的功能。 通知提醒用户重要信息,如突发新闻、产品更新、活动、优惠等。它已成为我们日常生活中不可或缺的一部分,通知不仅仅是移动推送通知,三种类型的通知格式:移动推送通知、短信和电子邮件
- 问题切入方向
- ① 通知推送类型:推送通知、短信、邮件
- ② 是否支持实时?(是一个实时系统吗?):软实时系统,希望用户可以尽快收到通知(如果系统处于高负荷工作状态可以接收稍许延迟)
- ③ 推送支持设备:支持多端设备,iOS设备、安卓设备和笔记本电脑/台式机
- ④ 什么时候触发通知?:通知可以由客户端应用程序触发,也可以由服务器端调度
- ⑤ 是否支持用户自由订阅?:用户可以选择退出,选择退出的用户将不再接收通知
- ⑥ 日内通知量级?:参考1000万条移动推送通知,100万条短信,500万封电子邮件
业务流程分析
② 请求量分析
③ 精准度分析
④ 难点/要点分析
理解各种通知类型的工作流程和高层设计:IOS推送通知、Android推送通知、短信和电子邮件
- 不同的通知类型支持
- 联系人信息收集流程
- 通知发送/接收流程
(1)不同的通知类型支持
针对不同通知类型的支持,可以理解为其本质上涉及3个核心组件:Provider
、第三方通知服务
、Client
Provider
:用于构建通知请求,并将请求转发到第三方通知服务第三方通知服务
:可以理解为桥梁,用于将通知请求传播到指定设备Client
:客户端,用于接收请求
简化图示分析如下所示:
推送通知(IOS、Android)
IOS 和 Android 采用类似的通知流程,主要涉及3个组件构成通知机制:provider(消息生产方)
、第三方推送通知服务(APNs(IOS)/FCM(Android))
、客户端(IOS/Android)
①
Provider
提供商构建通知请求并发送到第三方通知服务(携带 token 和 JSON 数据)
# token : 设备token,用于发送推送通知的唯一标识符 # JSON :有效载荷,一个包含通知有效载荷的JSON字典 { "aps": { "alert": { "title": "Game Request", "body": "Bob wants to play chess", "action-loc-key": "PLAY" }, "badge": 5 } }
②
第三方推送通知服务
APNs
:苹果推送通知服务,Apple 提供的远程服务,用于将推送通知传播到 iOS 设备FCM
: Firebase Cloud Messaging (FCM) 通常用于向 Android 设备发送推送通知
③
Client
:接收推送通知的终端客户端,即IOS或Android
短信
电子邮件
一般公司可以设置自己的电子邮件服务器,但其中许多公司选择商业电子邮件服务。 Sendgrid和 Mailchimp是最受欢迎的电子邮件服务之一,它们提供更好的交付率和数据分析
参考发送电子邮件的API案例:POST https://api.example.com/v/sms/send
{
"to":[
{
"user_id": 123456
}
],
"from":{
"email": "hh@126.com"
},
"subject": "Hello!",
"content":[
{
"type": "text/plain",
"value":"Hello World!"
}
]
}
(2)联系人信息收集流程
要发送通知,需要收集移动设备令牌、电话号码或电子邮件地址。 如图所示,当用户安装我们的应用程序或首次注册时,API 服务器会收集用户联系信息并将其存储在数据库中。
(3)通知发送/接收流程
🟢 初版设计
基于上述分析,构建通知机制的基础框架(基本组件):
- ① Services(服务1到N):一个服务可以是一个微服务,一个cron job,或者一个触发通知发送事件的分布式系统
- 例如,一个计费服务发送电子邮件提醒客户到期付款,或者一个购物网站通过短信告诉客户他们的包裹明天会被送到
- ② 通知系统:通知系统是发送/接收通知的中心环节。从简单的东西开始,只使用一个通知服务器。它为服务1到N提供API,并为第三方服务建立通知有效载荷
- ③ 第三方服务:第三方服务负责向用户发送通知。在与第三方服务集成时,需要特别注意可扩展性。良好的可扩展性意味着一个灵活的系统可以很容易地插入或拔出第三方服务。另一个重要的考虑因素是,第三方服务可能在新的市场或在未来无法使用。例如,FCM在中国是不可用的。因此,在那里使用替代的第三方服务,如Jpush、PushY等
- ④ 客户端:接收通知的设备组件(IOS、Android、SMS、Email)
问题分析
基于上述基础版本设计可以看到存在三个问题:
- 单点故障(SPOF):单一通知服务器意味着SPOF
- 难以扩展:通知系统在一台服务器上处理所有与推送通知有关的事情。要独立扩展数据库、缓存和不同的通知处理组件是很有挑战性的
- 性能瓶颈:处理和发送通知可能是资源密集型的。例如,构建HTML页面和等待第三方服务的响应可能需要时间。在一个系统中处理所有事情可能会导致系统过载,尤其是在高峰期
🟡 进阶设计
基于上述基础版本问题分析,此处引出相应的改进思路:
- 多机部署(拆分应用服务器、数据存储服务器):将数据库和缓存从通知服务器中移出
- 水平扩展:添加更多的通知服务器,并设置自动水平缩放功能
- 异步处理:引入消息队列,使系统组件解耦
基于上述分析,构建通知机制的进阶版本框架(基本组件):
- ① Services(服务1到N):代表不同的服务(通过通知系统服务器提供的API发送通知)
- ② 通知系统:通知系统是发送/接收通知的中心环节,其核心功能说明如下:
- 提供API:为服务提供发送通知的API。这些API只能由内部或经过验证的客户访问,以防止垃圾邮件
- 基础验证:进行基本验证,以核实电子邮件、电话号码等
- 数据查询:查询数据库或缓存以获取渲染通知所需的数据
- 对接MQ:将通知数据放到消息队列中进行并行处理
- ③ Cache:缓存(缓存用户信息、设备信息、通知模板等内容)
- ④ DB(数据库):存储用户、通知、设置等方面的数据
- ⑤ MQ(消息队列):消除组件之间的依赖性,当大量的通知被发送出去时,消息队列可以作为缓冲区。每种通知类型都被分配了一个不同的消息队列,所以一个第三方服务的中断不会影响其他通知类型
- ⑥ Workers:Workers 是一组服务器,它们从消息队列中拉取通知事件并将它们发送到相应的第三方服务
- ⑦ 第三方服务:第三方服务负责向用户发送通知(用于传播消息)
- ⑧ 客户端:接收通知的设备组件(IOS、Android、SMS、Email)
结合上述图示流程分析每个组件是如何结合起来完成整个流程:
- ① 一个服务调用通知服务器提供的API来发送通知
- ② 通知服务器从缓存或数据库中获取元数据,如用户信息、设备令牌和通知设置
- ③ 一个通知事件被发送到相应的队列进行处理。例如,一个iOS推送通知事件被发送到iOS PN队列中
- ④ 工作者从消息队列中获取通知事件
- ⑤ 工作者向第三方服务发送通知
- ⑥ 第三方服务向用户设备发送通知
(4)深入设计
在上述设计中讨论了不同的通知类型支持、联系人信息收集流程、通知发送/接收流程,进一步思考其他方面的因素:
- 可靠性(Reliability):消息丢失、消息重复
- 其他组件和考虑因素:通知模板、通知设置、速率限制、重试机制、推送通知的安全性、监控排队通知和事件跟踪。
- 更新后的设计
可靠性
如何防止数据丢失?
通知系统最重要的要求之一是它不能丢失数据。 通知通常可以延迟或重新排序,但绝不会丢失。 为了满足这个需求,通知系统将通知数据持久化到数据库中,并实现了重试机制。 包含通知日志数据库以实现数据持久化
接收者只会收到一次通知吗?
尽管大多数时候通知只发送一次,但分布式特性可能会导致重复通知。 为了减少重复的发生,可以引入重复数据删除机制并仔细处理每个失败案例。 这是一个简单的重复数据删除逻辑:当一个通知事件第一次到达时,通过检查事件的ID来检查它是否在之前出现过。如果在之前出现过,它将被丢弃。否则,将发送通知
其他组件和考虑因素
已经讨论了如何收集用户的联系信息,发送和接收通知。一个通知系统远不止这些。在这里,我们讨论了额外的组件,包括模板重复使用、通知设置、事件跟踪、系统监控、速率限制等。
通知模板
一个大型的通知系统每天会发出数百万条通知,其中许多通知都遵循类似的格式。通知模板的引入是为了避免从头开始建立每一个通知。通知模板是一个预先格式化的通知,通过自定义参数、样式、跟踪链接等来创建你独特的通知。下面是一个推送通知的例子模板。
BODY: You dreamed of it. We dared it. [ITEM NAME] is back — only until [DATE]. CTA: Order Now. Or, Save My [ITEM NAME] The benefits of using notification templates include maintaining a consistent format, reducing the margin error, and saving time.
通知设置
用户一般每天都会收到太多的通知,他们很容易感到不堪重负。因此,许多网站和应用程序让用户对通知设置进行细化控制。这些信息存储在通知设置表中,有以下字段:
user_id bigInt channel varchar # push notification, email or SMS opt_in boolean # opt-in to receive notification
在向用户发送任何通知之前,我们首先检查用户是否选择接收这种类型的通知
速率限制
为了避免用户被过多的通知所淹没,可以限制一个用户可以收到的通知数量。这一点很重要,因为如果发送得太频繁,接收者可能会完全关闭通知
重试机制
当第三方服务无法发送通知时,该通知将被添加到消息队列中进行重试。如果问题持续存在,将向开发者发出警报
推送通知的安全问题
对于iOS或Android应用程序,appKey和appSecret被用来保护推送通知API。只有经过认证或验证的客户端才允许使用系统提供的API发送推送通知
监视排队通知
要监控的一个关键指标是排队通知的总数。如果这个数字很大,说明 workers 处理通知事件的速度不够快。为了避免通知交付的延迟,需要更多的工作者(Workers)
事件跟踪
打开率、点击率和参与度等通知指标对于了解客户行为非常重要。 分析服务实现事件跟踪。 通常需要通知系统和分析服务之间的集成

深入设计版本更新
在这个设计中,与以前的设计相比,增加了许多新的组件
- 认证 & 速率限制:通知服务器配备了两个更关键的功能:认证(authentication)和速率限制(rate limiti)
- 引入重试:添加了一个重试机制来处理通知失败。如果系统发送通知失败,它们会被放回消息队列中,工作者会重试预定的次数
- 通知模板:通知模板提供一致且高效的通知创建过程
- 监测 & 跟踪:为系统健康检查和未来改进增加了监测和跟踪系统
2.整体设计(架构设计)
① 服务设计(分层设计)
② 存储设计(存储选型)
③ 业务设计(业务流程)
3.要点分析
4.总结陈述
- 深刻总结
- 要点牵引
- 收尾请教
通知是不可缺少的,因为它们让我们及时了解重要信息。它可能是关于你在Netflix上最喜欢的电影的推送通知,关于新产品折扣的电子邮件,或关于你在线购物付款确认的信息。此处通知系统的设计,它支持多种通知格式。推送通知、SMS消息和电子邮件。采用了消息队列来解耦系统组件。
除了高层次的设计,还深入挖掘了更多的组件和优化
- 可靠性:我们提出了一个强大的重试机制,以尽量减少失败率
- 安全性:AppKey/appSecret对用于确保只有经过验证的客户才能发送通知
- 跟踪和监测:这些都是在通知流程的任何阶段实施的,以捕捉重要的统计资料
- 尊重用户设置:用户可以选择不接收通知。 我们的系统在发送通知之前首先检查用户设置
- 速率限制:用户会喜欢对收到的通知数量设置频率上限