共计 7667 个字符,预计需要花费 20 分钟才能阅读完成。
作者 | 彭阳
导读
性能中台负责 MEG 端研发数据的接入、传输、治理、利用等各个环节。为了应答挪动应用领域中端技术的疾速迭代和线上突增问题的挑战,中台提出了实时拦挡与问题的散发机制,旨在在端上线的不同阶段及时发现并拦挡异样上线,最大水平缩小线上变更对用户体验的不良影响。本文在数据建设的时效性和准确性上进行深刻的探讨,包含:变更上线的染色过程、基于染色 ID 的性能外围数据指标的监控、线上问题实时散发至相干模块组件和人员等。
全文 7719 字,预计浏览工夫 20 分钟。
01 背景
1.1 业务背景
在疾速倒退的挪动应用领域中,继续的技术迭代是放弃 APP 竞争力的关键因素。然而,对于规模宏大、用户泛滥的 APP 利用,每一次的变更上线都存在引入线上问题的危险。APP 的各个组件模块相互交织,一旦某处出现异常,往往会像连锁反应一样影响整个零碎的稳定性,导致用户体验的降落。在以往的教训中,即使在开发和测试阶段充沛验证,也难免会有一些问题在实在用户环境中裸露进去。这些问题可能体现为解体、卡顿、性能生效等,重大影响用户的应用体验。在过来,应答这些问题通常是预先进行问题修复,然而这种形式并不能完全避免线上问题对用户体验的不良影响。因而咱们心愿在业务迭代变更上线的过程中,尽可能早的发现和拦挡问题,最大水平的升高问题对用户的影响。因而,性能中台引入了多级拦挡和问题散发的机制,这一机制旨在在变更上线的不同灰度放量阶段,对每次上线或者放量操作进行染色造成惟一染色 ID,通过对每个染色 ID 的外围性能数据指标进行监控,一旦发现异常,多级拦挡机制将会被触发,拦挡本次上线以及后续放量。同时,问题实时散发机制可能间接将问题指向导致该问题产生的模块和组件以及开发和测试人员。从而精确定位问题,并迅速修复,防止问题在更大范畴内扩散。
1.2 技术背景
实时 UV 计算:在解决异样上线的拦挡过程中,数据的实时生产以及数据的时效性的要求特地高,必须在分钟级别内实现。同时,业务方不仅须要取得异样的 PV 数,同时也须要取得在各个维度下异样影响的用户数(UV)。但实时 UV 计算不能简略地累加,这波及到同维度间用户交加的解决。例如:A 版本和 B 版本异样影响的用户数别离是 100,但整体用户数实际上可能有余 200。然而也不能间接存储用户 ID,例如通过应用 HashSet 或者 HashMap 存储所有的用户 ID 进行去重,这面对大量用户时,会占用大量的计算节点内存资源。因而,咱们采取一种计算的时效性和准确性较高的数据结构 Bitmap 来计算实时 UV。
Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保留位数组,把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 示意一个元素的二值状态。该数据结构能节约大量的存储,同时在用户群做交加和并集运算的时候也有极大的便当。例如,每个用户 ID 如果存储在 HashSet 或者 HashMap 中,须要占 4 个字节即 32bit,而一个用户在 Bitmap 中只占一个 bit。在做交并集运算时,例如,员工 1、员工 2 都是程序员,员工 1 应用苹果手机,那么如何查找应用苹果手机的程序员用户?
间接应用位运算,应用苹果手机的程序员用户:(0000000110B & 0000000010B = 0000000010B)
异样反混同:次要用于问题散发阶段。APP 厂商在公布利用程序包时,通常会对包进行混同操作,这是为了进步 APP 利用的安全性和缩小反编译的危险。混同是将源代码中的符号、名称和构造等转换为难以了解的模式,使得反编译后的代码难以还原为原始的源代码,然而 APP 上报的异样信息也被混同了。反混同操作是将混同后的异样信息还原为可读的模式,使开发人员可能更精确地剖析问题的起因,并迅速采取正确的修复措施。在 APP 产出利用程序包时,同时也会产生一份用于反混同异样信息的映射文件(密码本),通过映射文件 + 解析算法对混同的异样进行解析,即可失去已读的异样堆栈。
△异样信息反混同过程
1.3 名词解释
性能中台:性能中台是 APP 性能追踪的一站式解决方案平台,为 APP 提供全面、实时的性能剖析服务与工具链。
挪动线上品质平台: 挪动线上品质平台是挪动端 APP 发包后,用来查看、剖析包品质数据、进行外围指标监控 / 报警、变更异样拦挡。
日志中台:指端日志中台,包含端日志全生命周期的能力建设。包含打点 SDK / 打点 server/ 日志治理平台等外围组件。
Tekes 平台:App 端研发平台,提供包组件治理等基础设施。
02 零碎设计
2.1 整体流程
在以往的流程中,针对客户端上线变更,咱们通常应用大盘性能指标来进行监控,以便进行问题定位和止损。然而,在灰度用户数量较少的状况下,线上问题往往无奈在大盘性能指标中产生显著稳定。当业务决定全量上线或扩充灰度用户规模时,问题就可能显现出来了。在问题定位和解决的阶段,咱们过多地依赖人工干预和手动排查,这导致问题定位和解决的工夫较长,并可能降级为事变。因而,在旧流程中,线上问题影响面大小次要取决于灰度用户的规模以及问题排查人员对客户端各个模块和相干人员的理解水平,这是不合理的。因而,零碎设计的关键在于解决两个外围问题:首先,如何在灰度阶段拦挡问题,防止其进一步扩充;其次,一旦线上问题呈现,如何可能迅速进行问题召回与解决。
△线上异样实时拦挡与问题散发整体流程设计图
因而,在新流程中,引入了两个要害模块:” 变更拦挡模块 ” 和 ” 问题散发模块 ”。对于每次平台的上线变更,必须先在变更拦挡模块中进行注册,从而生成一个惟一的上线染色 ID。同时,将染色 ID 下发至本次变更上线的用户客户端。尔后,该数据集的用户日志将携带染色 ID 进行上报。变更拦挡模块将基于染色 ID 的粒度进行监控和拦挡,以保障在上线过程中问题的及时发现。同时,问题散发模块建设了问题主动散发机制。当一个上线变更被拦挡或者在线上呈现问题时,该模块将间接将问题指派给波及问题的模块、组件,以及相干的研发和测试人员。帮助业务方疾速精确的定位问题,人工再染指修复。
2.2 异样上线变更拦挡
异样上线变更拦挡的外围思路是:为每次上线变更生成独特的染色 ID,通过对每个染色 ID 的性能外围数据进行拦挡与监控。
△异样上线变更拦挡流程设计图
变更拦挡流程的具体步骤如下:
① 变更上线注册:针对厂内各个配置变更平台,须要在每次上线配置失效之前,将上线信息在染色通用服务进行注册。
② 获取染色 ID: 染色通用服务通过 HTTP 接口为每次上线注册生成通用的染色 ID,并将其返回给上线变更平台。
③ 下发染色配置: 在圈定的用户群范畴内,上线变更平台将新配置和染色信息同时下发到端上的业务 SDK(如 AB-SDK)中。
④ 染色日志上报:业务 SDK 会断定染色是否失效,如果失效,则在波及性能外围场景的日志中附加染色 ID 信息,而后通过 UBC-SDK 上报。这些日志会通过日志中台实时转发,并写入音讯队列。
⑤ 实时指标计算:性能中台会实时订阅音讯队列中的外围性能数据,例如解体、APP 启动次数等,而后针对每个染色 ID,依据多个维度(如产品线、APP 版本、操作系统、地区等)造成性能聚合指标,并将其写入长久存储。
⑥ 异样拦挡服务:基于存储中的染色数据,异样拦挡服务通过配置监控项来检测数据是否出现异常。一旦染色数据异样,零碎会触发拦挡措施并收回告警。
⑦ 异样止损:在触发拦挡和告警后,零碎会通过关联染色 ID 和变更上线的关系,拦挡持续放量以及告诉业务方针对本次上线的配置回滚。
针对每次线上配置的变更,都会有一段观察期。这个观察期的长短须要适度,以确保数据的可靠性。过短的观察期会影响数据的置信度,而过长则可能升高研发效率。一般而言,每次变更后须要期待 10 分钟的观察期,而后再逐渐减少线上流量。因而,变更拦挡模块对数据时效性的要求十分高,要求数据的端到端传输时效在 3 分钟以内,以确保有足够的数据累积工夫,从而晋升监控指标的可信度。同时,染色 ID 的数据指标项不仅涵盖了根底的 PV 指标(如解体次数和 APP 启动用户数),还扩大至 UV 级别的指标(如受解体影响的用户数收敛状况和 APP 用户启动数)。多个指标维度下 UV 的计算也给数据链路的时效性和准确性带来了挑战。具体的数据流设计如下所示:
△变图更拦挡数据流设计
变更拦挡的数据流次要分为两个局部:
(1)实时指标计算服务;
(2) ID 生成服务。
ID 生成服务
ID 生成服务次要用于将厂内的 CUID 生成 INT 类型的数字,从而存储到 Bitmap 的数据结构中。整个服务须要满足以下条件:
(1)CUID-ID 的的映射全局惟一,不会呈现反复的 ID,且 ID 的整体趋势递增。
(2)高并发低延时。外围数据在计算节点内存中进行产出,缩小数据库压力。
(3)高可用,服务基于云上分布式架构,即便存储 mysql 宕机,也能容忍一段时间数据库不可用。
在实时流中,在接管到原始数据时,先依据 CUID 进行 keyby 散发,将雷同的 CUID 散发到同一个计算节点。对于每个计算节点:
(1)优先查问本身内存中的缓存的映射关系,若不存在,则查问 redis。
(2)若 redis 不存在映射关系,则拜访生成新 ID 服务。
(3)服务申请 hash 到号段节点上,每次去 DB 拿固定长度的 ID List 进行散发,而后把最大的 ID 长久化下来,也就是并非每个 ID 都做长久化,仅仅长久化一批 ID 中最大的那一个。这个形式有点像游戏里的定期存档性能,只不过存档的是将来某个工夫下发给用户的 ID,这样极大地加重了 DB 长久化的压力。
(4)最终将映射关系写入到 Redis 存储中。
实时指标计算服务
在数据处理流程中,端上传的日志数据经由日志中台进行转发,进而散发到性能的各个音讯队列中。实时计算服务订阅这些音讯队列中的数据,以多级聚合形式进行维度指标的计算:
(1)数据散发与映射:首先,从音讯队列中获取原始数据。依据 CUID 进行 keyby 散发,将雷同的 CUID 散发到同一个计算节点。避免雷同的 CUID 同时拜访 ID-Mapping 服务,导致 CUID-ID 的的映射全局不惟一。
(2)本地聚合 :对数据进行解析取得指标和维度,而后在每个计算节点上进行本地窗口聚合操作,将具备雷同维度(版本、操作系统、染色 ID 等) 的 CUID 汇总成 Bitmap 格局。本地聚合的目标在于缩小后续的 keyby shuffle 阶段的数据量。
(3)全局聚合:状态服务保护实时流的运行时状态信息和历史数据的 Bitmap 后果。将实时数据与历史数据进行全局聚合,从而失去最终的后果数据。同时,新的 Bitmap 结从新写入状态服务。其中,运行时状态信息保障了在实时流断流或重启时,可能复原上次运行状态。加上可重入的数据源和幂等的数据输入,确保了数据流的不丢不重。
通过上述服务,当新的变更上线导致端上异样数据突增时,变更拦挡服务可能在分钟级内对异样上线进行监控告警以及拦挡。此外,除了向业务方披露拦挡的数据指标,咱们也心愿中台可能间接帮助业务方定位排查出问题的根因。
2.3 问题主动散发
问题主动散发的外围思路是:建设端上各个模块、组件、类办法和研发测试人员的映射关系,当产生线上问题时,通过聚类规定将通过反混同之后问题间接指向导致问题产生的组件、模块以及负责该模块的研发测试人员。
△线上问题实时主动散发数据流
问题散发的数据流次要分为四个局部:
(1)映射文件写入存储
(2)线上异样反混同
(3)端组件关系建设
(4)问题散发
其中 (1)(2) 步骤是为了将线上异样解析为可读的模式。(3)(4)步骤为将可读的堆栈进行聚类以及散发。
映射文件写入存储
在技术背景的实时反混同介绍中,为了将通过混同的异样信息复原成可读的模式,关键在于应用映射文件。映射文件分为两种:一种是针对每个 APP 发版时生成的映射文件,用于对该版本的 APP 本身的异样信息进行反混同;另一种是操作系统发版产生的映射文件,用于零碎级别的异样信息的反混同。当 APP 发版或操作系统降级时,通过配置流水线将相应的映射文件写入映射文件缓存中。
APP 的版本又有线上和线下的区别。针对线上发版的 APP 版本,其版本的特点体现为每个版本的发版周期较长,线上异样数量较多,同时对数据解析的实时性要求较高。为满足这些特点,将线上发版的映射文件存储于高性能的 Redis 集群中。对于厂内线下测试发版的 APP 版本,其版本特点体现在研发测试人员都能发版,导致版本数量绝对较多。然而,与线上环境不同的是,线下测试环境中结构的异样较少,而对数据解析的实时性要求较低。鉴于这些特点,更适宜将线下测试发版的映射文件存储于性能稍弱但更适宜存储大量数据的 Hbase 集群中。
线上异样反混同
在端产生线上异样时,端会上报两条信息流。一条是解体的指标数据流,一条是定位堆栈的文件流。指标数据流的特点是上传信息快,蕴含外围信息以及简化版的异样信息,但异样信息量不全。而文件流的特点是,上传速度偏慢,然而异样信息残缺(2M)。联合这两种信息流,能够取得残缺的线上异样信息,供业务剖析应用。然而因为两条信息流是异步上报,常常面临数据流乱序达到的问题。因而,为了解决乱序问题,咱们设计了状态服务。
△状态服务数据流设计
状态服务的次要目标是解决双流乱序的数据,以确保它们可能被正确关联。其外围流程如下:
(1)同工夫窗口数据关联:从音讯队列中订阅数据后,首先会对处于计算节点同一个工夫窗口的数据进行关联,若关联胜利,则数据间接发往上游进行计算。
(2)同历史未关联的数据关联:若未胜利,则查问状态服务中之前窗口中尚未被关联的数据进行关联,若关联胜利,发往上游,状态存储中革除关联数据。
(3)未关联数据写入状态存储:若未胜利,则将未关联的数据写入到状态存储中,期待被未来的数据进行关联。
此外,状态存储也不能有限的增长,须要有过期淘汰的策略,在该场景下,咱们设置的是 30min 的 TTL,可能关联到 99.9% 以上的数据。
在胜利关联双流数据后,紧接着是对堆栈进行反混同解析。反混同的指标是将通过混同后的异样信息还原为可读的模式。在反混同过程中,各种类型异样的解析算法工具(如腾讯 Bugly、谷歌 CrashPad)通常可能在秒级别(约 10 秒)内实现解析操作。然而,在实时数据流解决中,仅仅满足秒级的解析时效性是不够的,须要将解析速度晋升至毫秒级。因而,中台实时流中对反混同解析进行了降级,蕴含算法降级适配实时流以及多级缓存在构建。
多级缓存由计算节点内存,Redis 以及 Hbase 形成。其中,依据不同的缓存命中状况,反混同解析的性能会有所不同。如果堆栈对应的映射文件在计算节点内存中命中,解析能够在 <10ms 内实现。若在 Redis 或 Hbase 中命中,则解析工夫会略有缩短,达到秒级别(约 10 秒),那么最现实的形式是将所有的映射文件都在计算节点内存中被命中。然而,因为每个版本都有对应的映射文件,且每个线上 APP 都有数十个版本,每个映射文件大小约为 300MB,这使得无奈将线上流量所需的所有映射文件都加载到算子内存中。为了解决这一问题,咱们对解析算法进行了多级索引的优化。这种优化策略将整个映射文件进行了细粒度拆分,仅将异样堆栈命中的映射文件行信息加载到内存中。因而,解析算法当初不再须要将整个映射文件齐全存入内存。相同,它只需存储一级索引和二级索引的关系,以及命中堆栈后取得的后果数据。这一形式在显著进步内存利用效率的同时,也解决了计算节点内存不足的问题。
△多级索引查问
然而,随着线上工作长时间运行时,咱们留神到程序性能逐步降落,导致实时流工作的数据处理经常出现提早。咱们发现问题的根本原因是计算节点缓存中的映射文件被频繁替换,导致缓存命中率低。因而,咱们采纳了更为适宜业务场景的缓存代替算法 —W-TinyLFU 代替惯例的 LRU 缓存代替策略。
△W-TinyLFU 算法
相比 LRU 算法,W-TinyLFU:
1、热点数据适应性更强:在高流量的场景中,一些热点数据项可能会在短时间内被屡次拜访。与 LRU 只关注最近的拜访,W-TinyLFU 通过保护频繁拜访计数来更好地捕捉这种热点数据的特色,从而更好地适应刹时的流量变动。
2、低频数据保护:LRU 在遇到新数据时,会立刻淘汰最近起码应用的数据,这可能导致低频数据被频繁淘汰。W-TinyLFU 通过保护一个近似的频率计数,能够更好地爱护低频数据,避免它们被过早地淘汰。
3、适应性更强:W-TinyLFU 在面对拜访模式的变动时,可能更快地适应新的拜访模式。它在长时间内继续察看拜访模式,并逐步调整数据项的权重,以更好地反映最近的拜访模式。
4、写入操作思考:LRU 通常对写入操作的适应性较差,因为写入操作可能导致数据被立刻淘汰。W-TinyLFU 思考了写入操作,通过保护写入时的频繁拜访计数,能够更好地解决写入操作。
5、内存效率:W-TinyLFU 应用了一些压缩技术来存储频繁拜访计数,从而在肯定水平上缩小了内存占用。
通过对线上异样进行反混同解决后,咱们取得了可读的堆栈信息。接下来,咱们能够对这些可读的堆栈信息进行问题聚类和散发。
端组件关系建设
组件关系变更的数据起源分为两个局部:
(1)全量数据:在 APP 进行发版时,通过 EasyBox 等工具将组件、模块等关系从包中解析进去,将该版本的组件信息上传到组件治理平台,触发组件治理平台的全量同步,将组件信息写入音讯队列中。中台通过订阅组件数据,建设类办法 <-> 组件、模块、研发人员、测试人员的关系,写入到存储中。
(2)增量数据:在组件治理平台进行人为的批改,例如批改组件类的研发、测试负责人等,触发增量同步,变更的数据写入音讯队列。
通过上述数据同步,建设了类办法 <-> 人的映射。
问题散发
通过数据流的反混同解析,咱们胜利地将异样信息从二进制地址转换为可读的信息。接下来,借助聚类规定算法,咱们将不同的异样堆栈逐行遍历,并优先将其聚类到厂内保护的组件和模块中所蕴含的类中。在此过程中,咱们建设了线上问题 <-> 类之间的关系。而在端组件关系建设的流程中,咱们胜利地构建了类办法 <-> 研发测试人员之间的映射关系。将这两者的关系联合起来,咱们取得了问题 <-> 人员之间的关联。因而,当线上呈现问题时,无需人工干预,零碎能够间接将该问题指向负责该问题模块的负责人。负责人随后能够依据反混同后的异样信息,进行问题的排查和修复工作。
03 总结与瞻望
本文次要介绍了性能中台在解决异样上线过程中,针对变更拦挡和问题散发方面做的一些致力。当然,前面咱们还会持续更好的服务业务,如:
1、晋升影响力:对接更多的上线变更平台以及落地更多的 APP。
2、晋升场景覆盖度:笼罩卡顿、启动速度、网络性能、搜寻性能等更多的外围业务场景。
3、晋升问题聚类以及散发策略的准确度:将线上问题散发的更加正当与精确。
心愿,性能中台继续一直优化,为保障 APP 的品质做出奉献。
——END——
举荐浏览
极致优化 SSD 并行读调度
AI 文本创作在百度 App 发文的实际
DeeTune:基于 eBPF 的百度网络框架设计与利用
百度自研高性能 ANN 检索引擎,开源了
存储计划作为产品——Midgard 摸索