博客 / 詳情

返回

ByteByteGo學習筆記:通知系統設計

引言

在當今這個信息爆炸的時代,通知系統已經成為了現代應用程序中不可或缺的重要組成部分。無論是突發新聞的即時推送、產品更新的及時告知、促銷活動的精準觸達,還是用户交互的實時反饋,通知都扮演着至關重要的角色。一個高效、可靠、可擴展的通知系統,不僅能夠提升用户體驗,增強用户粘性,還能有效地傳遞關鍵信息,驅動業務增長。

本文將深入探討如何設計一個可擴展的通知系統,涵蓋了從需求分析、高層設計到詳細設計的各個環節,並着重強調了系統的可靠性、可擴展性、安全性以及其他關鍵的設計考量。

第一步:理解問題並確定設計範圍

在任何系統設計的初期階段,最重要的一步都是深刻理解問題明確設計範圍。對於通知系統而言,其功能看似簡單——發送通知,但實際上,要構建一個能夠發送數百萬條通知的可擴展系統,其背後涉及到諸多複雜的技術細節和架構選擇。

  • 通知類型: 系統需要支持推送通知 (移動端 - iOS, Android, 桌面端 - 筆記本/台式機)、短信電子郵件 三種主流通知形式。這三種形式各有特點,適用場景也不同,例如,推送通知更適合實時性要求高的場景,短信和郵件則更適用於非實時但需要保證送達的場景。
  • 實時性: 系統被定義為 軟實時系統。這意味着系統應儘可能快速地發送通知,但允許在系統高負載情況下出現輕微延遲。這種定義平衡了實時性需求和系統性能的考量,為後續設計提供了靈活性。
  • 支持設備: 系統需要覆蓋 iOS 設備、Android 設備以及 筆記本電腦/台式機。這要求系統需要能夠兼容不同的平台和設備,並針對不同平台的特性進行適配。
  • 觸發方式: 通知可以由 客户端應用程序 觸發,也可以在 服務器端 觸發。這表明通知系統需要支持多種觸發機制,以滿足不同的業務場景需求。例如,用户行為可以觸發客户端通知,而定時任務或系統事件可以觸發服務器端通知。
  • 用户選擇退出: 系統必須允許用户 選擇退出 接收通知。這體現了對用户隱私和選擇權的尊重,也是現代應用程序設計的基本原則。選擇退出機制需要在設計中予以充分考慮,並確保用户能夠方便地管理自己的通知偏好。
  • 日均發送量:1000萬條移動推送通知、100萬條短信和 500萬封電子郵件。這些指標直接關係到系統的容量規劃、性能優化和成本控制。高併發、大吞吐量是可擴展通知系統需要重點解決的問題。

通過以上問題的梳理,我們對通知系統的需求和設計範圍有了清晰的認識,這為後續的高層設計奠定了堅實的基礎。

第二步:提出高層設計並獲得認可

在高層設計階段,我們需要勾勒出系統的整體架構,明確各個組件的功能和交互關係。高層設計方案,清晰地展示了支持各種通知類型 (iOS 推送通知、Android 推送通知、短信和電子郵件) 的基本框架。其核心結構可以概括為以下三個方面:

1. 不同類型的通知

首先從技術層面剖析了各種通知類型的工作原理。

  • iOS 推送通知 (APNs): iOS 推送通知依賴於 Apple 推送通知服務 (APNs)。發送流程涉及三個關鍵組件:

    • 提供者 (Provider): 負責構建通知請求,包括設備令牌 (Device Token) 和負載 (Payload)。負載是一個 JSON 字典,可以包含通知的標題、內容、徽章 (Badge) 等信息。
    • APNs: 蘋果官方提供的遠程服務,負責將推送通知通過 "Apple to device" 協議傳播到 iOS 設備。
    • iOS 設備: 最終接收並展示推送通知的終端設備。

    image

  • Android 推送通知 (FCM): Android 推送通知流程與 iOS 類似,但通常使用 Firebase 雲消息傳遞 (FCM) 作為推送服務,而非 APNs。FCM 提供了跨平台的消息傳遞解決方案,也支持 Web 和 iOS 平台。

    image

  • 短信 (SMS): 短信服務通常會藉助於第三方服務提供商,例如 Twilio、Nexmo 等。這些服務商提供了 API 接口,方便開發者集成短信發送功能。選擇第三方服務可以降低自建短信網關的複雜度和成本,並通常能獲得更好的送達率和功能支持。

    image

  • 電子郵件 (Email): 電子郵件服務同樣可以自建郵件服務器,但更多公司傾向於選擇商業電子郵件服務,如 SendGrid、Mailchimp 等。商業郵件服務在送達率、反垃圾郵件、數據分析等方面通常更具優勢。

    image

2. 聯繫信息收集流程

要成功發送通知,首先需要收集用户的聯繫信息,包括移動設備令牌、電話號碼和電子郵件地址。

image

當用户首次安裝或註冊應用程序時,API 服務器負責收集用户聯繫信息,並將這些信息存儲到數據庫中。

image

這是一個簡化的數據庫表結構,用於存儲聯繫信息。user 表存儲用户的電子郵件地址和電話號碼,device 表則存儲設備令牌。一個用户可以擁有多個設備,這意味着可以向用户的所有設備發送推送通知。這種一對多的關係模型,支持多設備場景下的通知觸達。

3. 通知發送/接收流程 (高層設計)

image

該設計方案的核心是一個 通知系統 組件,作為整個通知流程的中心樞紐。

  • 服務 1 到 N: 代表各種需要發送通知的業務服務,例如,計費服務、電商平台、社交應用等。這些服務通過調用通知系統提供的 API 來觸發通知發送。
  • 通知系統: 核心組件,負責接收來自各個服務的通知請求,並將其轉發給相應的第三方服務。初始設計中,所有通知處理邏輯都集中在一個通知服務器上。
  • 第三方服務: 負責實際的通知發送,例如 APNs, FCM, 短信服務商, 郵件服務商等。

初始設計的侷限性

雖然初始設計方案簡潔明瞭,但也存在一些明顯的侷限性:

  • 單點故障 (SPOF): 所有通知相關的組件都集中在一個服務器上,一旦該服務器發生故障,整個通知系統將癱瘓。
  • 難以擴展: 隨着業務增長,通知量不斷增加,單一服務器在數據庫、緩存和通知處理組件的擴展方面都面臨挑戰。垂直擴展 (Scale-Up) 終究有瓶頸,水平擴展 (Scale-Out) 在這種架構下也較為困難。
  • 性能瓶頸: 通知處理和發送本身是資源密集型任務,例如構建 HTML 郵件、等待第三方服務響應等。在高併發場景下,單一服務器容易成為性能瓶頸,導致系統過載。

高層設計 (改進)
image

改進的核心在於引入了 消息隊列緩存獨立的數據庫,並採用了 水平擴展 的策略。

  • 消息隊列 (Message Queue): 引入消息隊列 (如 Kafka, RabbitMQ) 作為系統組件之間的緩衝層,實現了服務之間的 解耦。消息隊列可以應對突發流量,平滑峯值,並提高系統的 異步處理能力可靠性。不同類型的通知事件 (iOS PN, Android PN, SMS, Email) 可以分別進入不同的消息隊列,實現更精細化的管理和隔離,避免單一類型的通知服務故障影響全局。
  • 緩存 (Cache): 引入緩存 (如 Redis, Memcached) 用於存儲用户信息、設備信息、通知模板等 高頻訪問但相對靜態的數據。緩存可以顯著提升數據讀取速度,降低數據庫負載,提高系統性能。
  • 獨立的數據庫 (DB): 將數據庫從通知服務器中分離出來,並可以採用 集羣部署分庫分表 等技術,提升數據庫的 可擴展性可靠性
  • 通知服務器集羣 (Notification Servers): 採用 水平擴展 策略,部署多個通知服務器實例,並通過 負載均衡 (Load Balancer) 將請求分發到不同的服務器實例。這顯著提升了系統的 併發處理能力可用性
  • Worker: 引入 Worker 組件,負責從消息隊列中消費通知事件,並調用相應的第三方服務發送通知。Worker可以水平擴展,根據消息隊列的積壓情況動態調整Worker數量,實現 彈性伸縮

改進後的高層設計流程

  1. 服務調用通知服務器 API: 業務服務通過調用通知服務器提供的 API 發送通知請求。API 設計需要考慮安全性,例如採用 內部 API認證機制,防止惡意請求或垃圾郵件。
  2. 通知服務器元數據提取: 通知服務器接收到請求後,首先進行 基本驗證 (例如,驗證郵箱格式、電話號碼格式等),然後從 緩存數據庫 中提取渲染通知所需的元數據,例如用户信息、設備令牌、通知設置等。
  3. 事件推送至消息隊列: 通知服務器將通知事件推送到相應的 消息隊列 (例如,iOS PN 隊列, SMS 隊列等)。
  4. Worker消費隊列事件: Worker 組件從消息隊列中拉取通知事件。
  5. Worker調用第三方服務發送通知: Worker根據事件類型,調用相應的 第三方服務 (APNs, FCM, 短信/郵件服務商) 發送通知。

第三步:設計深入

在高層設計的基礎上,我們需要進一步深入探討系統的細節設計,包括可靠性、附加組件以及其他重要的設計考量。

可靠性

可靠性是通知系統設計的核心要素之一。用户期望能夠及時、準確地收到重要通知,任何數據丟失或延遲都可能影響用户體驗甚至業務運營。

  • 如何防止數據丟失?: 為了確保通知數據不丟失,系統需要做到 數據持久化實現重試機制
  • 數據持久化: 將通知數據 (如圖11 所示的 "通知日誌數據庫" 中的數據) 存儲到數據庫中,即使系統發生故障,數據也不會丟失,可以用於後續的重試或審計。
  • 重試機制: 當通知發送失敗時 (例如,第三方服務故障、網絡異常等),系統需要具備 自動重試 的能力。重試機制需要考慮重試策略 (例如,指數退避、最大重試次數等),避免無限重試導致系統壓力過大。
  • 每個接收者是否恰好接收一次通知?: 在分佈式系統中,由於網絡延遲、消息重複等因素,很難保證 精確的一次性交付 (Exactly-Once Delivery)。通知系統 無法保證每個接收者恰好接收一次通知,但可以通過 去重機制 (Deduplication) 來 減少重複通知的發生
  • 去重機制: 一種簡單的去重邏輯是 基於事件 ID。當通知事件觸發時,首先檢查事件 ID 是否已經處理過。如果已經處理過,則丟棄該事件;否則,發送通知並記錄事件 ID。更復雜的去重機制可能需要藉助分佈式鎖或狀態管理系統。

附加組件和考量因素

除了核心的發送流程,一個完善的通知系統還需要考慮許多附加組件和因素,以提升用户體驗、系統效率和可維護性。

  • 通知模板 (Notification Templates): 對於大型通知系統,每天需要發送數百萬條通知,其中很多通知的格式和結構是相似的。引入 通知模板 可以實現 模板複用,避免重複構建相似的通知,提高效率,並保持通知格式的一致性。

    短信通知模板的示例:

    你夢想的[ITEM NAME]回來了——僅此[DATE]。
    CTA: 現在下單,或保存我的[ITEM NAME]。

    通知模板可以使用佔位符 (例如 [ITEM NAME], [DATE]) 來表示動態參數,在發送通知時,將這些佔位符替換為實際的內容。

  • 通知設置 (Notification Settings): 用户通常會收到大量的通知,過多的通知容易引起用户的反感。因此,為用户提供 精細化的通知設置選項 至關重要。用户可以根據自己的偏好,選擇接收哪些類型的通知,以及通過哪些渠道接收通知。

    通知設置表的字段示例:

    • user_id: 用户 ID
    • channel: 通知渠道 (推送通知, 電子郵件, 短信)
    • opt_in: 用户是否選擇接收該渠道的通知 (Boolean)
    • rate_limiting: 頻率限制設置 (可選)

    系統在發送通知前,需要 首先檢查用户的通知設置,尊重用户的選擇。

  • 安全推送通知 (Secure Push Notifications): 對於推送通知,安全性至關重要。為了防止未授權的訪問和濫用,需要採取安全措施。對於 iOS 和 Android 應用,可以使用 apnscertappsecret 進行 API 鑑權,只有經過身份驗證的客户端才能通過 API 發送推送通知。
  • 監控隊列通知 (Monitoring Queue Notifications): 監控 是保證系統穩定運行的關鍵手段。對於通知系統,隊列積壓情況 是一個重要的監控指標。如果隊列積壓量過大,意味着通知事件處理速度跟不上產生速度,可能導致通知延遲。監控隊列長度,並根據情況 動態調整Worker數量,可以有效避免通知延遲。
  • 事件跟蹤 (Event Tracking): 為了瞭解通知的 效果用户行為,需要進行 事件跟蹤。例如,追蹤通知的 打開率點擊率用户參與度 等指標。這些數據對於分析用户行為、優化通知內容和策略都非常有價值。通知系統需要與 分析服務 集成,將事件數據上報給分析服務進行處理和展示。
  • 速率限制 (Rate Limiting): 為了防止系統被濫用 (例如,惡意發送大量垃圾郵件或短信),以及保護用户免受過多的通知打擾,需要實施 速率限制。速率限制可以針對不同的維度進行,例如,限制單個用户在單位時間內接收的通知數量,限制單個 IP 地址在單位時間內發送的通知請求數量等。

最終設計

image

整合所有上述組件和考量因素後,最終的通知系統設計。與之前的設計相比,最終設計更加完善和健壯,考慮了可靠性、安全性、監控、用户設置和速率限制等關鍵方面。

總結

構建一個可擴展的通知系統,需要重點關注以下幾個方面:

  • 需求明確: 深入理解業務需求,明確通知類型、實時性要求、支持設備、觸發方式、用户偏好以及性能指標等。
  • 架構合理: 採用分佈式架構,引入消息隊列、緩存、獨立的數據庫和通知服務器集羣,提升系統的可擴展性、可靠性和性能。
  • 可靠性保障: 實施數據持久化和重試機制,最大程度地減少數據丟失,並採用去重機制降低重複通知的概率。
  • 功能完善: 提供通知模板、用户通知設置、安全推送、隊列監控和事件跟蹤等附加組件,提升用户體驗和系統管理能力。
  • 安全性考量: 採用 API 鑑權等安全措施,防止系統被濫用。
  • 用户體驗至上: 尊重用户選擇,提供精細化的通知設置,並實施速率限制,避免過度打擾用户。

參考資料
ByteByteGo

user avatar TwilightLemon 頭像 mylxsw 頭像 xiaoqian01 頭像 nogeek 頭像 zbooksea 頭像 kubesphere 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.