十、设计通知系统
近年来,通知系统已经成为许多应用程序中非常流行的功能。通知提醒用户重要信息,如突发新闻、产品更新、事件、产品等。它已经成为我们日常生活中不可或缺的一部分。在这一章中,你被要求设计一个通知系统。
通知不仅仅是移动推送通知。三种通知格式是:移动推送通知、SMS 消息和电子邮件。图 10-1 显示了这些通知的一个例子。
第一步——了解问题并确定设计范围
构建一个每天发送数百万条通知的可扩展系统并不是一件容易的事情。它需要对通知生态系统有深刻的理解。面试问题特意设计成开放式的,模棱两可的,你有责任提问明确要求。
候选人 :系统支持什么类型的通知?
面试官 :推送通知、短信、邮件。
候选: 是实时系统吗?
面试官: 姑且说是软实时系统吧。我们希望用户尽快收到通知。但是,如果系统工作负载较高,稍微延迟是可以接受的。
候选: 支持哪些设备?
面试官: iOS 设备,android 设备,以及笔记本电脑/台式机。
候选: 什么触发通知?
面试官: 客户端应用程序可以触发通知。它们也可以在服务器端进行调度。
候选人: 用户可以选择退出吗?
面试官: 是的,选择退出的用户将不再收到通知。
候选人: 每天发出多少通知?
面试官:1000 万条移动推送通知,100 万条短信,500 万封邮件。
第二步——提出高水平的设计并获得认同
本节展示了支持各种通知类型的高级设计:iOS 推送通知、Android 推送通知、短信和电子邮件。其结构如下:
不同类型的通知
联系信息采集流程
通知收发流程
不同类型的通知
我们先来看看每种通知类型在高层次上是如何工作的。
iOS 推送通知
我们主要需要三个组件来发送 iOS 推送通知:
提供者。提供商构建通知请求并将其发送给苹果推送通知服务(APNS)。为了构造推送通知,提供商提供以下数据:
设备令牌:这是用于发送推送通知的唯一标识符。
有效负载:这是一个 JSON 字典,包含通知的有效负载。下面是一个例子:
APNS:这是苹果提供的一项远程服务,用于向 iOS 设备传播推送通知。
iOS 设备:是终端客户端,接收推送通知。
安卓推送通知
Android 采用了类似的通知流程。Firebase Cloud Messaging (FCM)通常用于向 android 设备发送推送通知,而不是使用 APN。
短信
对于短信,通常使用 Twilio [1]、Nexmo [2]等第三方短信服务。大部分是商业服务。
电子邮件
虽然公司可以建立自己的电子邮件服务器,但许多公司选择商业电子邮件服务。Sendgrid [3]和 Mailchimp [4]是最受欢迎的电子邮件服务,它们提供更好的投递率和数据分析。
图 10-6 显示了包含所有第三方服务后的设计。
联系信息收集流程
为了发送通知,我们需要收集移动设备令牌、电话号码或电子邮件地址。如图 10-7 所示,当用户安装我们的应用程序或者第一次注册时,API 服务器收集用户的联系信息并存储在数据库中。
图 10-8 显示了存储联系信息的简化数据库表。电子邮件地址和电话号码存储在 用户 表中,而设备令牌存储在 设备 表中。一个用户可以有多个设备,这表明推送通知可以被发送到所有的用户设备。
通知发送/接收流程
我们将首先展示最初的设计;然后,提出一些优化。
高--水平设计
图 10-9 显示了设计,每个系统组件解释如下。
服务 1 到 N :服务可以是微服务、cron 作业,也可以是触发通知发送事件的分布式系统。例如,一个账单服务发送电子邮件提醒客户他们的到期付款,或者一个购物网站通过短信告诉客户他们的包裹将于明天送达。
通知系统 :通知系统是发送/接收通知的核心。从简单的开始,只使用一个通知服务器。它为服务 1 到 N 提供 API,并为第三方服务构建通知有效负载。
第三方服务: 第三方服务负责向用户发送通知。在与第三方服务集成的同时,我们需要额外关注可扩展性。良好的可扩展性意味着一个灵活的系统,可以很容易地插入或拔出第三方服务。另一个重要的考虑是,第三方服务可能在新的市场或未来不可用。例如,FCM 在中国是不可用的。因此,替代的第三方服务,如 Jpush,PushY 等,在那里使用。
iOS、Android、短信、电子邮件 :用户在其设备上接收通知。
在本设计中发现了三个问题:
单点故障(SPOF):单一通知服务器是指 SPOF。
难以扩展:通知系统在一台服务器上处理与推送通知相关的一切。独立扩展数据库、缓存和不同的通知处理组件是一项挑战。
性能瓶颈:处理和发送通知可能是资源密集型的。例如,构建 HTML 页面和等待第三方服务的响应可能需要时间。在一个系统中处理所有事情会导致系统过载,尤其是在高峰时段。
高级设计(改进)
在列举了初始设计中的挑战后,我们对设计进行了如下改进:
将数据库和缓存移出通知服务器。
添加更多通知服务器并设置自动水平缩放。
引入消息队列来分离系统组件。
图 10-10 显示了改进的高层设计。
浏览上图的最佳方式是从左到右:
服务 1 到 N :它们代表通过通知服务器提供的 API 发送通知的不同服务。
通知服务器 :提供以下功能:
为发送通知的服务提供 API。这些 API 只能在内部访问或由经过验证的客户端访问,以防止垃圾邮件。
进行基本验证,以验证电子邮件、电话号码等。
查询数据库或缓存以获取呈现通知所需的数据。
将通知数据放入消息队列进行并行处理。
下面是发送电子邮件的 API 示例:
职务
请求体
缓存 :缓存用户信息、设备信息、通知模板。
DB :存储用户、通知、设置等数据。
消息队列 :它们移除组件之间的依赖关系。当要发送大量通知时,消息队列充当缓冲区。每种通知类型都分配有不同的消息队列,因此一个第三方服务的中断不会影响其他通知类型。
Workers:Workers 是从消息队列中拉出通知事件并发送给相应的第三方服务的服务器列表。
第三方服务 :已在初步设计中说明。
iOS、Android、短信、邮箱 :在初步设计中已经说明。
接下来,让我们看看每个组件如何协同工作来发送通知:
1。服务调用通知服务器提供的 API 来发送通知。
2。通知服务器从缓存或数据库中获取元数据,如用户信息、设备令牌和通知设置。
3。通知事件被发送到相应的队列进行处理。例如,iOS 推送通知事件被发送到 iOS PN 队列。
4。工作人员从消息队列中提取通知事件。
5。工作人员向第三方服务发送通知。
6。第三方服务向用户设备发送通知。
步骤 3 -设计深度潜水
在概要设计中,我们讨论了不同类型的通知、联系信息收集流程和通知发送/接收流程。我们将深入探讨以下内容:
可靠性。
附加组件和考虑事项:通知模板、通知设置、速率限制、重试机制、推送通知中的安全性、监控排队通知和事件跟踪。
更新设计。
可靠性
在分布式环境中设计通知系统时,我们必须回答几个重要的可靠性问题。
如何防止数据丢失?
通知系统中最重要的要求之一是不能丢失数据。通知通常可以延迟或重新排序,但永远不会丢失。为了满足这一要求,通知系统将通知数据保存在数据库中,并实现重试机制。如图 10-11 所示,包含通知日志数据库是为了数据持久化。
收件人会收到一次通知吗?
简短的回答是否定的。尽管大多数情况下通知只发送一次,但分布式的本质可能会导致重复的通知。为了减少重复的发生,我们引入了重复数据删除机制,并仔细处理每个故障情况。下面是一个简单的重复数据删除逻辑:
当一个通知事件第一次到达时,我们通过检查事件 ID 来检查它以前是否被看到过。如果是之前看到的,就丢弃。否则,我们将发出通知。感兴趣的读者可以参考参考资料[5],探究为什么我们不能一次交货。
附加组件和注意事项
我们已经讨论了如何收集用户联系信息、发送和接收通知。通知系统远不止于此。这里我们讨论其他组件,包括模板重用、通知设置、事件跟踪、系统监控、速率限制等。
通知模板
大型通知系统每天会发出数百万条通知,其中许多通知都遵循相似的格式。引入通知模板是为了避免从头开始构建每个通知。通知模板是一种预先格式化的通知,通过自定义参数、样式、跟踪链接等来创建您的独特通知。下面是推送通知的一个示例模板。
正文:
你梦见了它。我们敢于挑战。[项目名称]已恢复—仅到[日期]为止。
CTA:
现在订购。或者,保存我的【物品名称】
使用通知模板的好处包括保持格式一致、减少误差和节省时间。
通知设置
用户通常每天会收到太多的通知,他们很容易感到不知所措。因此,许多网站和应用程序允许用户对通知设置进行精细控制。该信息存储在通知设置表中,具有以下字段:
用户标识 bigInt
channel varchar #推送通知、电子邮件或短信
opt_in boolean # opt-in 接收通知
在向用户发送任何通知之前,我们首先检查用户是否选择接收此类通知。
速率限制
为了避免过多的通知让用户不知所措,我们可以限制用户可以接收的通知数量。这很重要,因为如果我们发送得太频繁,接收者可能会完全关闭通知。
重试机制
当第三方服务未能发送通知时,该通知将被添加到消息队列中进行重试。如果问题仍然存在,将向开发人员发出警告。
推送通知中的安全性
对于 iOS 或 Android 应用,appKey 和 appSecret 用于保护推送通知 API[6]。只有经过认证或验证的客户端才允许使用我们的 API 发送推送通知。感兴趣的用户可以参考参考资料[6]。
监控排队通知
要监控的一个关键指标是排队通知的总数。如果数量很大,则工作线程处理通知事件的速度不够快。为了避免通知传递的延迟,需要更多的工人。图 10-12 显示了一个待处理的排队消息的例子。
图 10-12
事件跟踪
打开率、点击率和参与度等通知指标对于了解客户行为非常重要。分析服务实现事件跟踪。通知系统和分析服务之间的集成通常是必需的。图 10-13 显示了出于分析目的可能被跟踪的事件的例子。
更新设计
图 10-14 显示了更新后的通知系统设计。
与之前的设计相比,本次设计增加了许多新部件。
通知服务器配备了两个更关键的功能:身份验证和速率限制。
我们还增加了重试机制来处理通知失败。如果系统未能发送通知,它们将被放回消息队列,工作人员将重试预定义的次数。
此外,通知模板提供了一致且高效的通知创建流程。
最后,增加了监控和跟踪系统,用于系统健康检查和未来改进。
步骤 4 -总结
通知是必不可少的,因为它们让我们了解重要的信息。它可能是网飞上关于你最喜欢的电影的推送通知,一封关于新产品折扣的电子邮件,或者一条关于你的网上购物支付确认的消息。
在本章中,我们描述了支持多种通知格式的可扩展通知系统的设计:推送通知、SMS 消息和电子邮件。我们采用消息队列来分离系统组件。
除了高级设计,我们还深入研究了更多组件和优化。
可靠性:我们提出了一个健壮的重试机制来最小化故障率。
安全性:AppKey/appSecret 对用于确保只有经过验证的客户端才能发送通知。
跟踪和监控:这些在通知流的任何阶段都可以实现,以捕获重要的统计数据。
尊重用户设置:用户可以选择不接收通知。我们的系统在发送通知前会先检查用户设置。
速率限制:用户会喜欢对他们收到的通知数量设置频率上限。
祝贺你走到这一步!现在给自己一个鼓励。干得好!
参考资料
【1】Twilio 短信:T3】https://www.twilio.com/smsT5】
【2】NEX mo 短信:T3】https://www.nexmo.com/products/smsT5】
【3】send grid:https://sendgrid.com/
【4】Mailchimp:T3】https://mailchimp.com/T5】
【5】你不能恰好有一次投递:https://brave newgeek . com/You-can-Have-exact-Once-Delivery/
【6】安全推送通知:【https://cloud.ibm.com/docs/services/mobilepush?】topic =移动推送通知安全推送通知T5】
【7】RadditMQ:T3】https://bit.ly/2sotIa6T5】