写点什么

我们是怎么做到每小时推送百万级通知的

  • 2019-12-03
  • 本文字数:2085 字

    阅读完需:约 7 分钟

我们是怎么做到每小时推送百万级通知的

推送通知是让用户立即接收到事件的一个非常有效的工具。在 Gojek,我们每天需要处理 300 多万个订单,跨 20 多款产品。


可以想象的是,我们每天推送的通知数量有多大——大概每小时 1 百万个。这篇文章将介绍我们在处理如此体量的推送通知时所面临的挑战,以及我们的解决方案。


体量大还只是其中的一个方面,在 Gojek,我们还需要面对一些独有的问题。

多个应用程序

Gojek 不只有一个 App,除了用户 App,我们还有 GoLife、司机 App、商家 App,还有服务商 App。



当我们的系统要推送通知,要么是推给某个用户的 App(例如,推给 GoLife 的通知不会被推到 Gojek 上),要么是推给所有的 App(例如促销通知)。


我们的系统需要足够灵活,能够在广播和单独推送之间自由地选择。

多个通知服务提供商

因为我们的用户 App 需要支持 iOS 和 Android 两个平台,所以也需要支持多个通知系统。


Android 平台我们使用了 FCM(Firebase Cloud Messaging)和 GCM(Google Cloud Messaging),iOS 平台我们使用了 APNS(Apple Push Notification Service)。



每一个通知服务提供商都为不同的 App 提供了不同的 API 秘钥和令牌。例如,GoLife 和 Gojek 使用的 FCM API 秘钥就不一样。

一个用户多个设备

我们允许一个用户同时登录多个设备,所以通知需要被推送给用户已登录的所有设备上,这就存在之前的两个问题:


  1. 用户可以在单个设备上登录多个 App(Gojek 和 GoLife);

  2. 用户可能会登录多个设备,每个设备需要使用不同的通知服务提供商。例如,用户可以在 Android 设备和 iOS 设备上登录 Gojek。

多个需要推送通知的服务

Gojek 采用了微服务架构,我们想要让每个服务都能推送通知,不需要操心多设备和多服务提供商问题。



为了解决上述问题,并尽可能保持 API 简单,我们的通知系统被分为三个组件:


  1. 通知服务器——提供通知推送 API,并将通知推送到作业队列中;

  2. 令牌存储——保存已登录用户的设备和设备令牌数据;

  3. 通知处理器——处理作业队列中的消息,并将消息发送给通知服务提供商。



每个组件都解决了上述的一部分问题,接下来,我们来深入介绍这些组件。

令牌存储

用户在登录 App 后,App 会使用设备令牌和 App ID 调用令牌存储 API。



在用户退出时,这些记录会被删除。


令牌存储用于决定向用户的哪些设备推送通知。

通知服务器

这是 HTTP 服务器,提供用于推送通知的 API。


为了简单起见,API 要求把用户 ID 和 App ID 放在 HTTP 头部,把通知信息放在请求体里:


POST http://<base_url>/notificationuser_id: <user_id>application_id: <application_id>{  "payload": {},  "title": "You driver is here",  "message": "Please meet your driver at the pickup point"}
复制代码


服务器从令牌存储获取所有的用户设备信息,然后为每个用户设备安排一个调度作业。


通知服务器为系统提供了外部接口,需要推送通知的服务只要通过用户 ID 来调用它的 API,剩下的事情由通知服务负责处理。

作业队列

我们使用 RabbitMQ 作为作业队列,并为每一种 App ID 和通知类型创建了单独的队列。



分配单独的队列是很重要的,因为我们要为每一种 App 和通知类型做好故障隔离。例如,如果 com.gojek.app 的 FCM 令牌过期,就不会影响到 com.gojek.life 或者 com.gojek.driver.bike 的作业。

通知处理器

处理器进程从作业队列里拉取消息,把它们发送给对应的通知服务提供商。


为了保持代码简单,并能够支持不同的服务提供商,我们定义了统一接口:


type PushService interface {  Push(ctx context.Context, m PushRequest) (PushResponse, error)}
复制代码


Push 方法接收一个请求对象,并返回一个响应对象。


请求对象包含了与接收方和通知(比如过期时间、标题和文本)有关的信息。


type PushRequest struct {  DeviceID   string   Title      string  Message    string  Payload    map[string]interface{}  //其他参数}
复制代码


响应消息里包含了通知是否发送成功的信息:


type PushResponse struct {  Success         bool  ErrorMsg        string}
复制代码


然后为不同的服务提供商实现接口。例如,FCM 和 APNS 对应的实现看起来像下面这样:


type FCMProvider struct {  // 配置信息,比如API令牌和URL端点}func (p *FCMProvider) Push(ctx context.Context, m queue.Message) (notification.PushResponse, error) {  // 发送通知给FCM服务器}type APNSProvider struct {  // 配置信息,比如API令牌和URL端点}func (p *APNSProvider) Push(ctx context.Context, m queue.Message) (notification.PushResponse, error) {  // 发送通知给APNS服务器}
复制代码


通知处理器负责选择对应的通知服务提供商,并将消息发送给它们。

结论

在面对这些挑战时,我们找出其中的一些常用模式,把它们抽离成不同的服务,将一个相对复杂的问题变成了一系列简单且易于管理的服务。


每当一个核心逻辑需要不同的实现时,我们就把它抽离成单独的服务:


  • 多个设备问题通过令牌服务来解决;

  • 多个 App 问题通过统一的通知服务器接口来解决;

  • 多个通知服务提供商通过单独的作业队列和通知处理器来解决。


最终,我们构建了一个每小时能够处理 1 百多万个推送通知的系统。

原文链接

How We Manage a Million Push Notifications an Hour


2019-12-03 11:147837
用户头像
小智 让所有人认同的文字称不上表达

发布了 410 篇内容, 共 410.7 次阅读, 收获喜欢 1987 次。

关注

评论

发布
暂无评论
发现更多内容

Grafana GreptimeDB 数据源插件上线啦,全面替代 Prometheus 插件

Greptime 格睿科技

Grafana 时序数据库 Promethues

启信宝产业洞察:广东领跑低空经济,无人机产业强势崛起

合合技术团队

人工智能 算法 无人机 科技

JAVA 应用实现 APM 自动注入(主机篇)

观测云

Java

Sentieon软件快速入门指南

INSVAST

基因数据分析 生信服务 Sentieon

百度沧海·存储统一技术底座架构演进

百度Geek说

腾讯云AI代码助手

全栈若城

数字化落地过程中的研发效能治理如何开展?

思码逸研发效能

DevOps 研发管理 绩效管理 研发度量 研发效能度量

GreptimeDB 首位独立 Committer Eugene Tolbakov 是怎样炼成的?

Greptime 格睿科技

开源 时序数据库

【等保小知识】等保测评等级从高到低怎么排序?

行云管家

等保 等级保护 等保测评

探索电商平台API接入的多样路径

代码忍者

API 接口 pinduoduo API

高性能日志结构化引擎 — GreptimeDB Piepline 设计与实现技术揭秘

Greptime 格睿科技

时序数据库 日志储存 日志引擎

湖南长沙正规等保机构名单以及地址看这里!

行云管家

等保 等保测评 长沙

南开大学携手和鲸科技,以 AI 赋能交叉学科人才培养与课程建设

ModelWhale

Python 人工智能 新文科 南开大学

Reviewbot 开源 | 为什么我们要打造自己的代码审查服务?

大卡尔

DevOps Code Review 工程实践 静态代码检查

阿里云 DataWorks 正式支持 SelectDB & Apache Doris 数据源,实现 MySQL 整库实时同步

SelectDB

数据库 大数据 数据分析 数据迁移 整库同步

【JIT/极态云】技术文档--模型简介

武汉万云网络科技有限公司

低代码 开发工具

8+ 典型分析场景,25+ 标杆案例,Apache Doris 和 SelectDB 精选案例集(2024版)电子版上线

SelectDB

数据库 数据分析 经验分享 大数据 开源 案例集

王慧文回归带队美团探索 AI 应用;对话音频开源模型 Hertz-dev:120 毫秒超低延迟丨 RTE 开发者日报

RTE开发者社区

怎么自动保存ppt?3个必备的ppt使用技巧分享!

职场工具箱

人工智能 效率工具 办公软件 AIGC AI生成PPT

人工智能 | 文生图大模型

测吧(北京)科技有限公司

测试

制作并量化GGUF模型上传到HuggingFace和ModelScope

GPUStack

大模型 ModelScope LLM huggingface GGUF

在后LLM时代,关于新一代智能体的思考

澜舟孟子开源社区

人工智能 智能体 大模型

MongoDB面试专题33道解析

威哥爱编程

数据库 mongodb 面试

解析Go切片:为何按值传递时会发生改变?|得物技术

得物技术

golang 扩容 切片

《深入浅出Apache Spark》系列③:Spark SQL解析层优化策略与案例解析

数新网络官方账号

sql 大数据

压力测试,探索服务器性能瓶颈

测试人

软件测试

制作并量化GGUF模型上传到HuggingFace和ModelScope

SEAL安全

大模型 ModelScope LLM huggingface GGUF

主机上云,八仙过海?!

白洞计划

AI

GeoAI驱动土地价值重塑!中国地质大学(武汉)&和鲸社区Workshop圆满结束!

ModelWhale

Workshop 地球科学 geoai 遥感数据

我们是怎么做到每小时推送百万级通知的_架构_Soham Kamani_InfoQ精选文章