Skip to content

系统设计:设计一个通知系统(10)

Published: at 13:08:10

近年来,通知系统已经成为许多应用程序非常流行的功能。 通知提醒用户重要信息,如突发新闻、产品更新、活动、优惠等。它已成为我们日常生活中不可或缺的一部分。 在本章中,您需要设计一个通知系统。

通知不仅仅是移动推送通知,三种类型的通知格式:移动推送通知、短信和电子邮件。 图 10-1 显示了每个通知的示例。

第1步:了解问题并确定设计范围

构建一个每天发送数百万条通知的可扩展系统并非易事。 它需要对通知生态系统有深入的了解。 面试问题特意设计为开放式和模棱两可的,你有责任提出问题以明确要求。

候选人:系统支持哪些类型的通知? 面试官:推送通知、短信、邮件。

候选人:它是一个实时的系统吗?

采访者。让我们说这是一个软实时系统。我们希望用户能尽快收到通知。但是,如果系统处于高负荷工作状态,稍有延迟也是可以接受的。

候选人:支持的设备有哪些?

面试官:iOS设备、安卓设备和笔记本电脑/台式机。

候选人:什么触发通知?

面试官:通知可以由客户端应用程序触发。 他们也可以由服务器端调度。

候选人:用户是否能够选择退出?

面试官:是的,选择退出的用户将不再收到通知。

候选人:每天发出多少份通知?

面试官:1000万条移动推送通知,100万条短信,500万封电子邮件。

第2步:提出高层次的设计方案并获得认同

本节展示了支持各种通知类型的高层设计:iOS推送通知、Android推送通知、短信和电子邮件。它的结构如下:

不同的通知类型

我们先看一下每种通知类型在高层次上是如何工作的。

iOS推送通知

我们主要需要三个组件来发送 iOS 推送通知:

  1. Provider(提供商):提供商构建通知请求并将其发送到 Apple 推送通知服务 (APNS)。 要构建推送通知,提供者提供以下数据:

  2. 设备 token:这是用于发送推送通知的唯一标识符。

  3. 有效载荷:是一个包含通知有效载荷的 JSON 字典。 例子:

    {
        "aps": {
            "alert": {
                "title": "Game Request",
                "body": "Bob wants to play chess",
                "action-loc-key": "PLAY"
            },
            "badge": 5
        }
    }
  4. 苹果推送通知服务(APNS): 这是 Apple 提供的远程服务,用于将推送通知传播到 iOS 设备。

  5. iOS 设备:它是接收推送通知的终端客户端。

Android推送通知

Android 采用了类似的通知流程。 Firebase Cloud Messaging (FCM) 通常用于向 Android 设备发送推送通知,而不是使用 APN。

短信

对于SMS信息,通常使用第三方SMS服务,如Twilio[1]、Nexmo[2]和其他许多服务。它们中的大多数是商业服务。

邮件

虽然公司可以设置自己的电子邮件服务器,但其中许多公司选择商业电子邮件服务。 Sendgrid [3] 和 Mailchimp [4] 是最受欢迎的电子邮件服务之一,它们提供更好的交付率和数据分析。

图 10-6 显示了包含所有第三方服务后的设计。

联系人信息收集流程

要发送通知,我们需要收集移动设备令牌、电话号码或电子邮件地址。 如图 10-7 所示,当用户安装我们的应用程序或首次注册时,API 服务器会收集用户联系信息并将其存储在数据库中。

图10-8显示了存储联系人信息的简化数据库表。电子邮件地址和电话号码存储在用户表中,而设备令牌则存储在设备表中。一个用户可以有多个设备,表明推送通知可以被发送到所有的用户设备上。

通知发送/接收流程

我们将首先介绍初始设计;然后,提出了一些优化方案。

高层设计

图 10-9 显示了设计,下面解释了每个系统组件。

服务1到N:一个服务可以是一个微服务,一个cron job,或者一个触发通知发送事件的分布式系统。例如,一个计费服务发送电子邮件提醒客户到期付款,或者一个购物网站通过短信告诉客户他们的包裹明天会被送到。

通知系统:通知系统是发送/接收通知的中心环节。从简单的东西开始,只使用一个通知服务器。它为服务1到N提供API,并为第三方服务建立通知有效载荷。

第三方服务:第三方服务负责向用户发送通知。在与第三方服务集成时,我们需要特别注意可扩展性。良好的可扩展性意味着一个灵活的系统可以很容易地插入或拔出第三方服务。另一个重要的考虑因素是,第三方服务可能在新的市场或在未来无法使用。例如,FCM在中国是不可用的。因此,在那里使用替代的第三方服务,如Jpush、PushY等。

iOS, Android, SMS, Email:用户在其设备上收到通知。

在这个设计中,发现了三个问题:

  1. 单点故障(SPOF):单一通知服务器意味着SPOF。
  2. 难以扩展:通知系统在一台服务器上处理所有与推送通知有关的事情。要独立扩展数据库、缓存和不同的通知处理组件是很有挑战性的。
  3. 性能瓶颈:处理和发送通知可能是资源密集型的。例如,构建HTML页面和等待第三方服务的响应可能需要时间。在一个系统中处理所有事情可能会导致系统过载,尤其是在高峰期。

高层设计(改进后的)

在列举了初始设计中的挑战后,我们对设计进行了如下改进:

图10-10显示了改进后的高层设计。

浏览上图的最佳方式是从左到右。

接下来,让我们来看看每个组件是如何一起工作来发送通知的。

  1. 一个服务调用通知服务器提供的API来发送通知
  2. 通知服务器从缓存或数据库中获取元数据,如用户信息、设备令牌和通知设置。
  3. 一个通知事件被发送到相应的队列进行处理。例如,一个iOS推送通知事件被发送到iOS PN队列中。
  4. 工作者从消息队列中获取通知事件。
  5. 工作者向第三方服务发送通知。
  6. 第三方服务向用户设备发送通知。

第3步:深入设计

在高层设计中,我们讨论了不同类型的通知、联系信息收集流程和通知发送/接收流程。我们将深入探讨以下内容。

可靠性

在分布式环境中设计通知系统时,我们必须回答几个重要的可靠性问题。

如何防止数据丢失?

通知系统最重要的要求之一是它不能丢失数据。 通知通常可以延迟或重新排序,但绝不会丢失。 为了满足这个需求,通知系统将通知数据持久化到数据库中,并实现了重试机制。 包含通知日志数据库以实现数据持久化,如图 10-11 所示。

接受者只会收到一次通知吗?

最简洁的答案是不。 尽管大多数时候通知只发送一次,但分布式特性可能会导致重复通知。 为了减少重复的发生,我们引入了重复数据删除机制并仔细处理每个失败案例。 这是一个简单的重复数据删除逻辑:

当一个通知事件第一次到达时,我们通过检查事件的ID来检查它是否在之前出现过。如果在之前出现过,它将被丢弃。否则,我们将发送通知。有兴趣的读者可以研究一下为什么我们不能仅一次发送,请参考参考资料[5]。

其他组件和考虑因素

我们已经讨论了如何收集用户的联系信息,发送和接收通知。一个通知系统远不止这些。在这里,我们讨论了额外的组件,包括模板重复使用、通知设置、事件跟踪、系统监控、速率限制等。

更新后的设计

把所有东西放在一起,图10-14显示了更新的通知系统设计。

在这个设计中,与以前的设计相比,增加了许多新的组件。

第4步:总结

通知是不可缺少的,因为它们让我们及时了解重要信息。它可能是关于你在Netflix上最喜欢的电影的推送通知,关于新产品折扣的电子邮件,或关于你在线购物付款确认的信息。

在这一章中,我们描述了一个可扩展的通知系统的设计,它支持多种通知格式。推送通知、SMS消息和电子邮件。我们采用了消息队列来解耦系统组件。

除了高层次的设计,我们还深入挖掘了更多的组件和优化。

恭喜你走到了这一步!现在给自己一个鼓励,干得漂亮!

参考资料