在40岁老架构师 尼恩的读者交流群(50+)中,很多小伙伴拿到一线互联网企业如阿里、网易、有赞、希音、百度、滴滴的面试资格。
最近,尼恩指导一个小伙伴简历,需要织入亮点项目、黄金项目。
前段时间,指导小伙写了一个《高并发消息推送项目》,帮这个小伙拿到 字节/汽车之家 等优质机会,并且帮他 喜提一个 “中间件王子offer” , 尼恩还对此案例进行了全面复盘:
被裁不慌,9年小伙1个月喜提年薪60W offer,做中间件架构,爽歪了
所以说,《高并发消息推送项目》 是一个牛逼的项目。
为了帮助大家拿到更多面试机会,拿到更多大厂offer, 在此文之前,尼恩还专门有文章对 消息推送的架构进行介绍:
消息推送 架构设计
架构总是无止境的。
前段时间尼恩看到了一个非常优质的案例 《从0到1,亿级消息推送的稳定性保障》, 这个案例,是一个非常优质的案例, 也是是一个亿级推送的生产案例、工业案例。
尼恩对这个案例进行了深入研读/二次分析, 吸纳到咱们的架构体系里面来, 为大家的所用,用于尼恩指导大家做简历改造。
也一并把这个案例,收入咱们的 《尼恩Java面试宝典》V169版本《架构专题》,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取
此文的原创是得物技术的架构师暖树,并不是尼恩。 但是原文不是太好懂 ,尼恩仅仅以学习笔记的形式, 对原文做二次 学习, 把原因改造得尽量浅显易懂。
由于无法联系到作者本人,尼恩的学习和改造也没有获得作者的同意。
特别说明,如果得物技术或者作者暖树本人不同意 尼恩的学习改造, 可以发消息给尼恩, 立马就从尼恩的自媒体扯下来。
从用户的生命周期来看,消息推送对于提高 App 活跃度、提升用户粘性和用户留存率都起到了重要作用。
提升新用户次日留存,低成本促活,对平台的短期留存率影响显著。
提升老用户活跃度,push 可以通过外部提醒起到拉活的作用。
很多内容平台类 App 的用户 push 首次启动占比可达 10%以上,因此 push 对 DAU 的增量贡献不容小觑。
流失用户召回,当用户流失后,若 push 权限未关闭,通过消息推送的方式,有可能重新唤醒用户。
消息推送每天都在我们的手机上发生,如图所示,除非你的手机没有安装App或关闭了通知栏权限。
发送通知
对通知进行优先级排序
根据客户的保存偏好发送通知
支持单个/简单的通知消息和批量通知消息
各种通知的分析用例
通知消息的报告
一般来说,推送的渠道很多,包括的电子邮件、短信、聊天、钉钉、企业微信和其他公共社交应用:
聊天 - 微信Wechat/QQ
站内推送通知(移动设备和Web浏览器)
站外推送通知(移动设备,APP没有开启)
短信(如登录密码、营销活动)
电子邮件
钉钉
企业微信
注意:请点击图像以查看清晰的视图!
高性能: qps > 1W
高可用性(HA): 99.99%
低延迟: TP99 在10ms以下
高扩展:可扩展/可插拔的设计,以便添加更多适配器和提供商,与所有通知模块的API集成以及与客户端和服务提供商/供应商的外部集成
跨平台:支持Android/iOS移动设备和桌面/笔记本电脑的Web浏览器
自伸缩:可在本地(VMware Tanzu)和 AWS、GCP 或 Azure 等公共云服务上扩展负载
SLA(Service-Level Agreement),也就是服务等级协议,指的是系统服务提供者(Provider)对客户(Customer)的一个服务承诺。
SLA(Service-Level Agreement)是衡量一个大型分布式系统是否“健康”的常见方法。在开发设计系统服务的时候,无论面对的客户是公司外部的个人、商业用户,还是公司内的不同业务部门,我们都应该对自己所设计的系统服务有一个定义好的 SLA。
因为 SLA 是一种服务承诺,所以指标可以多种多样。下面是四个常见的SLA指标 ,可用性、准确性、系统容量和延迟。
可用性指的是系统服务能正常运行所占的比例。
例如我们说要搭建一个”100%“的系统服务,也就意味我们要需要保证在任何时候这个系统都能运行,都说可用的,但实际这在现实中,是非常困难的,成本也是非常的高。
对于大部分的系统而言,能保证4个9的可用性(99.99%的可用性)就可以说这个系统是高可用的。
99.99%的可用性是指一天(60×60×24秒),只有8.64秒(60×60×24×0.0001秒)为不可用,一年就是大概有52.56分钟(8.64*365/60分钟)不可用。
99.99% 一天只有8秒左右的不可能用时间,这已经可用满足大部分系统的要求了。
准确性指的是我们所设计的系统服务中,是否允许某些数据是不准确或丢失,如果允许那么允许的百分比是多少?
不同系统对准确率都会有一个衡量的指标,大部分系统可以 用错误率来衡量。
错误率怎么计算呢?可以用导致系统内部错误有效请求数除以总的有效请求数而求得。
错误率=导致系统内部错误有效请求数/总的有效请求数
系统一分钟内收到的总的有效请求为100个,其中有10个导致系统内部错误,则我们可以认为错误率为10%
下面我们看下大公司中对系统错误率的对比
Google Cloud Platform 的SLA中,有着这样的定义:
每个月的错误率超过5%的时间要少于0.1%,以每分钟为单位来计算。
亚马逊AWS云计算平台对SLA的准确性定义为:
以每5分钟为单位,错误率不会超过0.1%。
那我们可以通过哪些途径来获取系统的准确性呢?大部分情况我们可以通过软件测试或系统日志来判断。
在数据处理中,系统容量通常指的是系统能够支持的预期负载量是多少,一般会以每秒请求数为单位来表示。
我们常常听见某个系统的架构可以处理的QPS(Queries Per Second 系统每秒查询数)是多少或者RPS(Requests Per Second系统每秒请求数)是多少。
延迟指的是系统在收到用户的请求到响应这个请求的时间间隔。
在定义延迟的SLA时,我们常常看到系统的SLA会有p95或者是p99这样的延迟声明。
这里的p指的是percentile(也就是百分比的意思),假设一个p95的系统延迟是1秒,那就表示100个请求里面有95个请求的响应时间是少于1秒的,而剩下的5个大于1秒。
对于消息推送而言,我们主要关注的是消息能否及时可靠的送达给用户,也就是 SLA 中关注的延迟(Latency)、准确性(Accuracy)和可用性(Availability)的问题。
消息中心为得物 App 提供了强大、高效的用户触达渠道,推送对于得物 DAU 的贡献有可观的占比,每一条推送消息,这也就意味着都是一次与用户沟通的宝贵机会。
得物推送背景和痛点:
与用户主动点击的WEB场景不同,在推送场景,用户是被动参与的。
业务方对于推送的消息什么时候到达没有明确的心理预期。
在这里,可用性的度量是模糊的。
如何提升推送的低延迟,首先需要我们针对消息推送的链路单元耗时进行监控,然后对各个链路单元的耗时做针对性的优化,不断降低延迟。
消息推送的稳定性依赖于第三方的推送通道,而三方通道对于我们来讲就是个黑盒子。
如何提升推送的可用性(Availability),关键是要做到三方通道异常及时发现,并且及时止损,也是需要考虑的问题。
从以上两个维度来说,都需要对系统进行全面的监控。
目前消息中心针对实效性和稳定性的开发已经完成并初显成效,下面主要针对时效性和稳定性的监控做一些介绍。
监控分为三个维度:
第一维度:全链路监控
第二维度:厂商监控
厂商的监控代码要从主流程逻辑中解耦,通过旁路流程进行异步的监控。
每天有数亿的消息推送,在这种大规模推送背景下,异步的监控,就不会影响主流程的处理性能。
首先,需要对全链路进行细粒度的拆分。 在拆分之前咱们先从宏观维度,看看 得物推送后台的 消息流转流程,宏观上包括 下面的四个阶段:
具体如下图:
如何做到全链路时效性的无死角监控?
首先,对消息推送的整个流程进行深入解耦,解耦出若干个独立的、可监控单元链路单元。
整个推送流程,主要会经历:
推送鉴权
用户查询
防疲劳过滤
防重复过滤等
这些业务单元,每个单元的逻辑的处理是相互独立且无依赖的,可以按照单元进行拆分,对每一个单元进行监控。
这样就可以做到拆分无遗漏,监控无死角,拆分后的具体链路单元如下:
具体的链路单元耗时逻辑的计算如下图:
每一个链路单元,都设计多个 核心时间节点,比如 操作开始时间,操作完成时间。
既然需要监控的链路单元已经拆分明确了,那针对这些链路单元我们监控哪些指标才是有意义的呢。
目前消息推送高峰耗时较长,业务域对于消息的到达时间也没有心理预期,所以涉及另个核心指标:
链路单元的推送耗时
链路单元的推送量/阻塞量
链路单元耗时的计算公式:
这一个操作完成时间 - 上一个操作完成的时间 ,
例如
防疲劳耗时=T7(antiFatigueConsumeTime)-T6(checkrepeatConsumeTime)
链路单元阻塞量的计算:
记录链路单元消息推送的瞬时阻塞量,
例如防疲劳链路单元阻塞量 =
防疲劳的总量-防疲劳已经处理的量
链路单元的阻塞量,是度量是否有积压的核心指标,如果存在积压,就需要扩容。
当然,在大促期间,消息的推送量也会达到一个高峰,往往都存在积压问题,需要进行提前扩容。
考虑到消息推送是有优先级的并且区分单推和批量推,所以我们要针对不同的优先级和推送方式设置不同的标准,消息推送耗时的具体标准如下。
首先,要考虑高并发、高吞吐场景。
消息中心每天推送大量消息给得物用户,SLA 全链路监控,一定不嵌入主流程, 任何一个操作嵌入主流程中都可能导致消息推送的延迟。
这也就要求监控和主流程进行隔离,主流程的归主流程,SLA 的归 SLA。
SLA 监控代码从主流程逻辑中剥离出来,彻底避免 SLA 代码对主流程代码的污染。
SLA 逻辑技术方案的实现的要求:
独立于推送业务的主流程进行异步计算,防止 SLA 监控拖垮整个主流程
使用非入侵的方式,我们使用的是 Spring AOP注解的方式
SLA 逻辑技术方案的 技术方案:Spring AOP+Spring Event。
主要链路单元包括鉴权、风控、用户查询、防疲劳、防重复、厂商调用,通过链路单元拆分,一单出现指标异常,可以很快定位到异常发生的具体位置。
时效性链路单元监控:
时效性链路单元告警:
消息推送实效性监控做完之后,实现了 指标化和预警化:
指标化:关键链路单元耗时的指标化,
预警化:对服务链路单元耗时异常可以及时感知,同时也完成了预警的对接
对 厂商推送监控, 主要涉及到三个核心指标:
如果出现推送成功率跌零、回执成功率跌零、点击率的跌零, 就需要进行技术的预警,这种情况下整个推送通道都挂掉了,我们要及时通知厂商进行修复,
另外,如果没有跌零,是不是也要监控呢? 是的。
一般来说,厂商的推送成功率、回执成功率、点击率都稳定在一定的的区间。如果厂商推送的指标数据偏离这个区间则说明推送有异常,也要进行告警和排查。
厂商监控监控告警的维度大致如下:
对这些指标,可以通过 Prometheus+grafana指标平台,进行时序展示:
在落地面,监控技术方案首先不能影响主流程中处理,
因为每天有数亿的消息推送,如果影响到核心流程,那么核心流程性能会大大降低。
所以,和第一个维度链路的监控类似,厂商的监控代码要从主流程逻辑中剥离出来,避免监控拖垮主流程,同样避免监控异常影响到推送的主流程。
如何解耦呢?这里使用的是有界内存队列实现。
消息推送厂商监控上线之后,可以及时感知到厂商推送的异常信息,对于厂商推送的异常和厂商规则的更改等可以做到及时的感知。
这里涉及到业务方的调用速率、消息的发送数量(单条和批量发生)、成功比例进行监控和预警。
这里得物原文没有给出方案, 应该是有遗漏了。
监控上线后,能及时发现厂商的很多线上以上:
及时发现异常后,就可以做到了及时的止损。
并及时经梳理各大厂商文档后,发现除了多个厂商通道在未来一个月内也会有规则的更改,消息平台团队对规则进行优化及时适应了厂商规则,接入厂商系统通道,做到了及时止损。
通过全链路的有效性监控,发现了多个服务可以优化的点,
比如,发现多个厂商和推送链路单元在高峰推送时耗时较高,发现厂商推送 SDK 连接池和连接时间参数需要优化, 优化后消息推送整体的吞吐量实现了翻倍的提升。
得物推送监控上线后,带来的收益还是比较可观的,
展望未来,后续可以从以下点丰富现有监控。
后续将针对各个链路单元的推送异常、漏斗转化率、服务性能等做监控,进一步丰富消息平台的监控体系。
后续将对推送的转化率问题进行监控
后续将对卸载、屏蔽等指标也是我们需要监控的点,
总之,通过对业务指标进行扩展,及时感知推送的效果,做到精细化的管控。
推送系统,是一个很黄金的系统。
如果写入简历,并且面试的时候能对答如流,如数家珍, 面试官会被你 震惊到、吸引到。
最终,让面试官爱到 “不能自已、口水直流”。
offer, 也就来了。
在面试之前,建议大家系统化的刷一波5000页《尼恩Java面试宝典PDF》 ,里边有大量的大厂真题、面试难题、架构难题。很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
金三银四挪窝的黄金时期到了,建议大家简历上织入一个 《推送系统》, 当然如果不知道怎么织入,可以找尼恩来改简历、做帮扶。
遇到职业难题,找老架构取经, 可以省去太多的折腾,省去太多的弯路。尼恩指导了大量的小伙伴上岸,前段时间,刚指导一个40岁+被裁小伙伴,拿到了一个年薪100W的offer。
狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。
……完整版尼恩技术圣经PDF集群,请找尼恩领取
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓