淘宝客户端安全生产体系建设
作者:秦静超(非台)
“ 本文主要讲述了淘宝客户端的安全生产,即在阿里内外成熟的技术方案的基础上,淘宝客户端是如何来建设自身的安全生产体系,从研发、构建、发布、应急四个阶段再次推动效率和用户体验不断得到升级。 ”
安全生产
首先我们将“客户端安全生产”定义为:为预防客户端研发生命周期过程中发生体验相关的事故,而采取的一系列措施和活动。
为此淘宝客户端建立了“‘研发、构建、发布、应急’一整套规范化流程及平台”。
图 1 安全生产架构图
淘宝客户端安全生产,主要分四个阶段:研发期、构建期、发布期和应急态,同时沉淀开发过程数据,围绕数据线上线下异常复盘,为提升代码质量、提升开发能力,进一步完善平台做数据支持,从而提升开发的良好研发环境,保障线上用户使用体验。
研发期:这一阶段主要是指开发同学把需求开发的阶段,往往是单模块的开发,这一阶段主要关注模块自身的质量,这一阶段安全生产平台主要通过需求管理、代码分支管理、单测管理、Code Review、测试请求|审批,一站式的方式为开发同学提供便利;
构建期:这一阶段主要是指开发同学把已经通过测试的代码,将代码提交到集成区做代码的集成测试,这一阶段安全生产平台主要通过质量卡口、包大小分析、产物校验来确保集成进来的模块是否满足集成标准(重复的资源文件、代码等或高危的隐私 API、调试代码等或不合理的组件导出、DEBUG 代码等),通过前置风险分析,防止风险代码集成;
发布期:这一阶段主要在通过测试后发布(灰度、正式)完整的 APP、配置变更、活动上线下线,这一阶段需关注 APP 稳定性数据、性能数据、业务数据与舆情数据(端到云的监控方案),确保发布的 APP 满足用户的体验要求;
应急态:前三个阶段主要是规避线上风险线,这一阶段则是在线上 APP 无法满足用户正常使用时所进入的状态,线上核心指标波动,会触发及时告警,从而通过钉钉快速组建应急小队,对线上问题进行处理,分析问题及问题背后的原因,快速给出解决方案,通过预案回滚、降级处理等手段快速化解线上风险,从而避免风险升级,防止故障产生。
另外为了确保线上 APP 的高可用体验,淘宝端架构专门成立了“端侧日常保障”小组,主要从事版本值班、大促保障、应急处理、复盘优化等工作,从日常工作中不断的发现问题、总结思考、优化流程、改进研发环境,不断把部分需要人工介入的流程自动化、数据化、平台化,从而提高“研发、构建、发布、应急”阶段的研发体验和研发效率,最终把人力从重复的、低效的工作中释放出来,通过过程数据不断优化安全生产平台体验,从而保障上层业务健康持续发展。让开发有更多的时间和精力从事更高维度的研发工程,提升开发的成就感。
研发期
研发期主要是开发同学开发为主,这里平台提供了代码覆盖率(单测),核心模块中间件的单测代码覆盖率需要满足 80%及以上,核心变更需要双人 CR(含 TL),非核心变更需要技术专家及以上 CR。
构建期
质量卡口
随着淘宝业务不断扩张,线上问题时有发生,淘系的场景非常丰富,本地的测试、Review、Monkey、甚至灰度等手段都不能覆盖到所有的场景。但问题一旦到了线上,所花费的成本都急剧增加。
经过对历史线上问题进行一些分析,发现其中的相当一部分问题,可以通过 “静态代码分析”, “二进制产物分析” 等方法提前发现,那么为什么不能用技术的手段来提前发现问题,阻断它们溜到线上呢。例如:
同名 Category 方法冲突问题, 导致手淘很多功能异常;
@{} 初始化没判空问题;
oc block 持有 c++ this 指针导致 User After Free 问题;
objc_msgSend 发送 alloc 导致内存泄露问题;
一些系统 api 不再安全,比如 vm_remap;
组件导出;
线程泄漏;
......
这些问题上线后可能就引起很难定位的问题,但是在代码阶段,通过静态分析等手段就可以阻断他们的发生。因此客户端质量卡口平台应运而生,将手淘客户端已有问题扫描工具和规则整合,结合 DevSecOps 卡口设计的开放卡口接入平台,形成完整的客户端线下问题发现、治理推动和集成卡口的能力,减少线上问题。
技术方案上,在 Android Lint+Spotbugs+Clang Static Analyzer(Android),OCLint(iOS)+Clang Static Analyzer 基础上结合淘系具体平台和具体问题进行改进,以满足淘系的技术需求(如扫描线程原生接口使用,辅助淘系整体线程架构迁移)。
包大小
包大小是客户端的非常重要的性能指标。从用户视角看,同样的功能和服务,用户倾向于选择安装包比较小的 App,可以让用户用更少的流量下载和更新,一定程度提高用户的下载率和更新升级率,对于推广和新增都会有较为重要的影响;从技术视角看,安装包中的每个文件都在瘦身的范围,对不同的文件类型,需要有针对性的瘦身方案,所以瘦身是一个大工程,包含了很多方面的技术。
Android 采用了图片压缩(TinyPng,Webp),重复资源合并、shrinkResource 严格模式、分包、Proguard、ARSC 瘦身、下无用代码(代码插桩分析)、无用业务下线、远端 so、检测 so 调试信息。
iOS 采用了图片压缩(TinyPng,Webp)、编译优化(不导出符号、oz、lto)、selectorRef 无用资源下线,剔除重复代码、业务下线、共享动态库技术(<iOS9)、Ld 链接器压缩。
产物校验
产物校验发生在 APP 发布前的最后一个环节,主要来分析本次发布与上一次发布核心变更存在哪些具体的差异,来确保本次发布的正确性。这一环节主要进行了核心代码变更分析(启动、CrashSDK、监控 SDK),需要关注核心代码变更带来的可能的风险;组件导出分析,防止不必要的组件导出,受到外部攻击;签名校验,防止签名出错导致 APP 无法正常上架;等等。
发布期
监控告警
淘系高度重视手机用户的稳定性和性能,通过高可用的度量指标的建立,稳定性和性能的治理,自动化和数据平台的建设,开发了一套系统化的解决方案及平台 EMAS-MOTU,全方位的提升手机淘宝稳定性和性能。
变更管控
淘系是一个高频活动运营 APP 集,我们发现有一些故障是由变更导致的(含活动上线,配置上线等),具有强相关性。因此淘系沉淀了变更管控平台,变更管控平台主要作用是监控分析平台发现的异常数据(Crash、ANR、卡断、泄漏等)与变更的相关性。
变更管控平台的核心思路是为每一次变更产生一个唯一的变更 ID,并在本次变更下发的过程中,将变更 ID 加入到监控信息的变更 ID 集里,当监控信息上报时会带上所有的变更 ID,服务可以对变更 ID 进行聚类分析,通过相关性确认相同聚类问题是由哪些变更 ID 产生的,并对具体的变更留观或回滚,防止风险升级。
通过精确的变更相关灰度染色数据,管控相关灰度和全量发布,及时卡住异常发布,避免发布引起故障,同时也是提高发布效率的核心手段。
应急态
定位
追踪、度量、日志
随着客户端功能不断细化与完善,模块化、跨团队的协同开发方式已经成为了客户端开发标准的开发方式,模块化、跨团队的协同开发方式的诞生极大提升了客户端交付与部署的效率,但同时可以看到这种模块化、跨团队的架构背后,原先运维与诊断的需求也变得越来越复杂。为了适应客户端日益增长的功能需求,需实现面向用户视角的标准化的 DevSecOps 诊断与分析系统,包括追踪(Tracing),度量(Metrics),日志(Logging)。
Tracing :用于记录客户端行为范围内的信息,它在单次请求的范围内,处理信息。任何的数据、元数据信息都被绑定到系统中的单个事务上。例如,用户进入页面,到数据渲染的过程。它是我们排查客户端问题的利器;
Metrics :用于记录可聚合的数据。他们具有原子性,每个都是一个逻辑计量单元,或者一个时间段内的柱状图。例如:队列的当前深度可以被定义为一个计量单元,在写入或读取时被更新统计;输入 HTTP 请求的数量可以被定义为一个计数器,用于简单累加;请求的执行时间可以被定义为一个柱状图,在指定时间片上更新和统计汇总。例如,从客户端发起的网络请求数,与正确收到网络数据的接受。它是我们衡量业务宏观质量的利器;
Logging :用于记录离散的事件。例如,应用程序的调试信息或错误信息。它是我们诊断问题的依据。
基于追踪(Tracing),度量(Metrics),日志(Logging)的设计原则,淘系借鉴了 OpenTracing 实现了全日志平台 TLog。通过漏斗模型、对比模型通过数据横向对比可以快速发现自身的性能瓶颈,缩小范围,提升排查效率。
全景定位
淘系是一个高频活动运营 APP 集,我们发现一些故障是由变更导致的(含活动上线,配置上线等),具有强相关性。因此淘系沉淀了全景定位平台,全景定位平台主要作用是监控分析线上的变更。全景定位平台的核心思路是当线上风险产生时,全景定位平台会主动去收集线上变更,并按时间维度呈现出来,开发可基于全景定位平台快速查看线上变更,定位和排查线上风险与变更的相关性,对潜在风险的变更留观或回滚,直至风险消除。
全景定位与变更管控有一定的相似性,都是对线上变更的监控与分析,区别在于全景定位主要在风险发生后对变更进行分析(业务在变化,无法保障所有的变更都会接入变更管控),变更管控则主要风险发生前打标,风险发生后对变更进行分析,因此全景定位是变更管控的一种补充与保障。
恢复
“对代码功能不符合项目预期或代码不够健壮导致 App 运行时崩溃或异常的线上问题进行恢复”。恢复是淘系应对线上突发问题的重要手段,淘系目前对线上不同的场景采用了不同的恢复策略,目前主要恢复策略有降级、预案、安全模式。
降级
在淘系复杂生态的环境下,大促期间还是会出现由于各种重资源的业务叠加,导致卡顿,体验明显下降,内存水位暴涨,崩溃率也会随之飙升。因此从 2018 年开始,尝试开始对重资源、高风险业务,针对不同设备的性能情况进行多维度降级。目的是对用户体验进行分级,实现 “高端设备最炫体验,低端设备流畅优先,紧急问题快速降级” (随着时间的推移,老的设备的软硬件条件,已经无法满足所有新技术、新业务的落地,需要有一定的取舍,从而给每一个设备最佳的用户体验) 。
针对不同设备的软硬件不同特性,基于 Listwise-SmartScorer 模型,淘系对客户端设置了高、中、底三个维度,0-100(0 表示设备性能优于市场上主流的 0%的设备,100 表示设备性能优于市场上主流的 100%的设备)的动态的设备评分算法。
设备评分是个什么? 从机器学习的角度来看:它可能是一个分类问题,即设备分为高/中/低三类,我们需要区分这几个类;它可能是一个回归问题,即设备存在一个绝对的分,我们需要去拟合这个分。无论分类还是回归问题,都把设备评分定义为一个绝对的值,而在实际体验中,我们往往说“iPhone X”比“iPhone 8”快,而不是说“iPhone X” 90 分,“iPhone 8” 70 分,即设备评分是相对的,同时由于设备的损耗,它的评分也是动态的,基于此,我们把设备评分定义为一个排序问题。
在设备评分的基础上,实现统一降级平台,业务可以通过“高、中、底”或“0-100”选取相应的设备投放自身业务。
预案
什么是预案?根据评估分析或经验,对潜在的或可能发生的突发事件的类别和影响程度而事先制定的应急处置方案。预案可以降低可预估或不可预估的风险,减少损失,而当下面临大多数的风险,都来自于各类变更,还有阿里最重要的大促场景下,大流量所带来的系统、业务压力。预案有分提前预案和应急预案。
提前预案:也称定时预案,提前预估大促期间的系统状况与业务状况,为了避免大促的业务峰值影响而进行的缓存预热、机器重启、有限降级、磁盘清理或者业务下线等等,一般对业务无影响或影响可控。
应急预案: 针对可能存在的应急情况,如超出预期的异常流量、系统依赖超时及不可用、本系统的非预期不可用等采取的应急手段,一般对业务有损,同时可能会带来客诉,资损等,需要对应的技术、业务等兜底,执行需要慎重。在新增变更中,在 Code Review 环节,对代码有 “可灰度、可监控、可回滚” (稳定性三板斧)要求,即确保代码有应急预案,在线上代码出现风险时,快速回滚。
预案和降级的区别在于,预案对全部设备采取相同的策略,而降级是对不同的设备采用不同的策略。
安全模式
恢复场景,(启动阶段)未正常使用网络的崩溃问题。网络未初始化导致配置无法下载发挥作用,于是淘系开发了一个安全模式(在连续触发相同 Crash 后强制进入“安全模式”--Android 轻量级子进程,iOS 进入安全模式代码,用来在对程序恢复初始状态(清除历史产生的持久化信息),如有必要会触发配置的下载),为主进程正常启动做必要的保障。如:启动时候因为持久化数据出错,导致 APP 启动连续闪退,这时安全模式可以发挥巨大作用,弥补配置下发执行前的代码盲区,避免用户只能通过卸载重装 APP 才能解决问题。
总结
客户端安全生产是在淘系较为完善的底层基础设施上建立起来的规范化、自动化、数据化的平台。文中涉及到的技术点是借鉴了阿里内外众多开发、产品、运维等从业人员对历史问题的总结与实现,这里感谢参与安全生产小伙伴的努力与付出,同时也感谢阿里以外的开发、产品、运维对丰富客户端技术、改进用户体验的努力与付出。文中更多的是对 APP 不同阶段的问题的思考与解问题的思路,希望对大家有帮助。
参考
[1] 移动研发平台 EMAS:https://www.aliyun.com/product/emas
[2] OpenTracing:https://github.com/opentracing
[3] 安全模式:天猫 App 启动保护实践:https://juejin.cn/post/6844903437948157959
关注【阿里巴巴移动技术】官方公众号,每周 3 篇移动技术实践 &干货给你思考!
版权声明: 本文为 InfoQ 作者【阿里巴巴移动技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/6462767b83689a59f64b58f61】。文章转载请联系作者。
评论