金融科技之中,通知非可有可无之功能也。
实乃产品之信层所系。
若用户转账而无确认,则惶惶不安。
若一次性码迟至三分钟,则登录不果。
若价格预警复至,则用户信心顿失。
于小处而言,发送通知似简而易行:
Application → Twilio/SendGrid → Done
然则,一旦涉于百万之众,多途交错,重试频仍,供者偶废,流峰骤起……则通报之制,遂成散系之患。
而散系之道,大抵在容败而安之。
试想一金融科技之台,发交易警讯:
- 交易警讯
- 一次性密码
- 投资组合更新
- 价格警报
- 安全通知
…逾百万人之用:
- 推送通知
- 短信
- 电子邮件
其难非惟“传讯”而已
其真难在使系统:
- 不遣复文
- 不默然失讯
- 存续于供者之患
- 于骤增之际可扩
- 事谬时犹可察
此乃吾所拟之构架.
高阶构架
[App Service]
│
▼
[Notification Queue (Redis Streams / SQS / Kafka)]
│
▼
[Worker Pool]
│
▼
[Provider Router]
│
┌────┼───────────────────────────────┐
▼ ▼ ▼
SMS Email Push
│ │ │
▼ ▼ ▼
Twilio SendGrid FCM/APNs
│
▼
Fallback Providers
(Termii / Mailgun / Direct APNs)
│
▼
[Delivery Log + Idempotency Store]
(PostgreSQL + Redis)
一、基于队列之构架
夫团队初起,其大谬者,莫过于直从API请求之循环而发通知也.
此法暂可…然当流量骤增.
试想黑五之日,或加密市场崩殂,抑或薪酬支付之时.
倏忽间,百万通知须顿发无间。
若汝之应用,须待 Twilio 或 SendGrid 之应,方返响于用户,则全应用为外供所掳矣。
此乃险途。
然则,API 当行一事:
速纳请而推警事于列。
自兹以往,工役之程,异步以达。
是故,此变系统之全貌矣。
队列予尔:
- 横扩之能
- 重试之效
- 逆压之御
- 败散之隔
若供者迟滞,队列纳峰而不倾尔之应用。
于此量级,队列非复可略之基设也。
乃为保护其余系统之安全缓冲。
推荐技术:
- Redis Streams
- AWS SQS
- Kafka(尤适于极高吞吐量系统)
2. 可靠性与 不可逆性
通知系统中最难之问题,往往非发送失败也。
此乃重复之讯.
世人于迟滞之通知,殊为宽宥.
然其于复收三度之扣款警讯,则非宽宥.
重试之处,重复之讯恒生.
譬如:
- 工作者发短讯.
- 然供者实得之。
- 网络超时,应答未返
- 工者以为败
- 工者复试
- 用户得重SMS
欲防此,每报皆当携idempotency_key.
工者发前,查之:
“此报已否经手?”
例约如
UNIQUE(user_id, notification_type, idempotency_key)
此乃微末之建筑决断,可免日后巨痛.
纵使重试屡次,数据库终为防重之终极屏障.
每试必录.
非独成功,万事皆录。
notification_attempts
所含:
- 所使用者
- 响应之状
- 重试之数
- 时辰之记
- 所使用者之误载
盖因生产之中,事有乖谬,欲得实据,非猜度也
3. 所使用者之定向& 退备之策
长老工程师终将悟得之实:
外供者之失,较所期尤甚。
Twilio 或颓。
SendGrid 或限请。
FCM 或滞推。
谬者,乃设系时,辄臆供者必恒在耳。
可靠之系统,视故障为常理。
故非硬编码单一提供者,乃设提供者路由之层。
例示路由之策
| 信道 | 主用 | 备选 |
|---|---|---|
| SMS | Twilio / Termii | Flutterwave SMS |
| 电子邮件 | SendGrid | Mailgun |
| 推 | Firebase FCM | 直APNs |
役者之流为:
- 试主供
- 察时或败
- 智重试
- 要则自溃
人不应觉其供者有失意之日.
此乃其旨.
4. 重试之策
重试初看似简,及至害起则不然.
不良之重试系统可致:
- 扰用户
- 累供者
- 增停摆之患
- 生巨费
常误者,过急重试也。
若Twilio已然困顿,骤以千试猛攻,适得其反,事益恶。
宜用指数退避法。
例:
Retry #1 → 30 seconds
Retry #2 → 2 minutes
Retry #3 → 10 minutes
此法使供者得暇复苏,而压力可御。
若穷试而不可乎?
则移此讯于死信队列(DLQ)。
此队列实乃尔“异事偶发之桶”。
届时,当唤工程师知之。
5. 调和之务
散系之中,微隐之患有焉:
或有供者云“已受”,然终至递送不达.
此乃险境之盲区.
或有通知,看似内中成功,而用户实未得之.
是故,校验之务甚要.
每数刻,背景之务当察可疑之状:
Notifications stuck in "pending" for too long
则:
→ Re-query provider APIs
→ Update delivery status
→ Retry if needed
此等任务默然救系统于偏颇之境,所由者:
- webhook之败
- 瞬息之废
- 络脉之阻
- 供者之迟
信頼性工学之要,实乃構築自能修正之體系也。
6. 用戶之好尚&速率制限
善之通知體系,非僅信頼而已。
亦謂尊重。
用戶當自主其接觸之法。
例證:
- 禁用营销短信
- 夜阑十时,罢非要之讯。
- 独推之好尚
- 每日简报代即时警报
简易之表
user_notification_settings
…可大幅增善用户体验。
限流亦关紧要。
无之,则虫噬或循环之患,可骤成巨费。
试想,误发一次性密码(OTP)于重试循环之中,致数千用户受扰。
基于Redis之限,可助御此患。
例如:
Max 3 SMS/hour/user
此可护:
- 用户免于垃圾信息之扰
- 供者御过载
- 业避靡费之祸
7. 察&可察之理
宏大之境,隐系统者危矣.
须知:
- 队列增否?
- 役者败否?
- 何供者迟滞?
- 何地受其影响?
至要之度,多属寻常操持之务。
金之信号
- 队列迟滞
- 队列之深
- 工者谬误之率
- 供者应时
复次,商界之指标:
- 投递成事之率
- 三十秒内送达之比率
- 服务商之费用
- 用户之选择退出比率
终而:警报.
例:
Alert if SMS failure rate exceeds 5% for 2 minutes
早察劣化,事乃微.
八. 测试失效之境况
诸系统之别,观之可靠者,与可靠者,其异在故障之试耳.
盖因诸事于乐途之演中皆顺遂.
所问者真,
何如于依存失性行之时?
一善策,乃影试之法。
取生产之流,仅其微乎其微者,导于新供,以安详较其果效。
例:
- 较其迟滞
- 较其达率
- 验其格式之均一
乱象之试,亦至为宝贵。
例:
Intentionally fail 10% of Twilio requests in staging
初闻之,似有可怖。
然可验其是否。
- 重试实有成效
- 故障转移触发无误
- 和合之务,复其讯息
可靠之系统,乃由可控之失效暴露而成。
何以此架构为效
此架构之坚韧,在于其预设变故之将至。
盖因终将:
- 供者或溃
- 队列或骤增
- 重试或频发
- 网络或失稳
系之存续,盖因可靠已内蕴于架构之骨。
由汇:
- 队列
- 不增性
- 重试次数
- 备用服务提供商
- 调解任务
- 可观测性
…平台虽逢局部停摆、流峰汹涌,犹能持续运行
且于金融科技,可靠非独指基建之质
实系用户信之根基
技栈之例
| 组件 | 建议之技 |
|---|---|
| 队列 | Redis之流 / Kafka / SQS |
| 工作者 | Laravel之列 / Go之工 / Node之消 |
| 缓存 | Redis |
| 数据库 | PostgreSQL |
| 监察 | 普罗米修斯加格拉菲卡 |
| 警报 | 派格达迪/斯拉克 |
| 短信 | 泰利奥/泰米 |
| 电子邮件 | 发送网格/邮件枪 |
| 推送 | Firebase FCM |
最终思考
多数通知系统于寻常流量时运作。
非其难也。
其难在存续:
- 供者之废弛
- 重试之复现
- 偏败之不彰
- 流量的骤增
此乃架构始显其效之时也。
盖用户鲜记其有效之警示也。
彼忆其时,沟通于要事之际而失。












