得物客户端基础架构热招android、ios、后端架构。微信:familyhappyli
背景
得物、Lazada、Daraz都存在各自历史问题。Lazada和Daraz由于技术积累原因,线上可用时长都不高。采用阿里成熟技术栈进行系统可用性提升、稳定性提升、迭代效率提升。采用了切流的方式对整个系统进行锐变。得物也是存在历史欠债。业务跑的太快,前期太多兼容逻辑,后续开发越来越痛苦。 导致牵一发而动全身,线上问题越来越多。整个交易的重构对交易db进行分拆。同时采用DDD领域模型提升系统可塑性,为后续更复杂的业务承载做基础准备。虽然经历过lazada和daraz的4次切流,但是得物碰到的问题还是不同的。比如lazada、daraz对服务切流采用一刀切不存在新老共存情况。得物由于是部分系统改造,因此整个切流方案得物更复杂。lazada和daraz由于是整个服务一刀切,因此受影响的业务更广,对数据迁移比得物更复杂。当然lazada和daraz还有海外团队协作沟通的问题(团队成员包括了俄罗斯、越南、巴基斯坦、印度)。不同的应用都有各自的切流细节。下面将详细介绍整个得物切流方案的技术选型过程以及与lazada和daraz的主要区别。
切流主要过程
- App切流前版本支持强制升级版本发布
- App支持强制升级的版本进行发布,提前3个月进行版本发布,保证最大化覆盖率
- 各域发版本前独立预演切流
- App&小程序提前进行线上环境切流预演,预演的流程包括
- 线上预演
- 旧功能可用 -> 旧功能停服 -> 旧功能还原可用
- 线上切流
- 切流期间的用户:旧功能可用 -> 旧功能停服 -> 开启切流路由切换到新功能
- 切流后的用户:旧功能可用 -> 开启切流路由切换到新功能
- 线上预演
- slb停服预演
- 确保无外部流量进入,白名单接口可访问
- 数据同步
- 数据增量迁移,验证数据准确性
- App&小程序提前进行线上环境切流预演,预演的流程包括
- App切流版本发布
- App共存俩套代码。切流前线上逻辑,切流后使用新代码
- 提前3周以上时间发布,确保切流版本的覆盖率,减少强升用户的影响范围。
- 测试会优先验证App相关功能
- 小程序带切流UI发布
- 与客户端的区别是单套代码,通过再次发版本替换为新的切流版本
- 提前上线的版本是带上停服UI能力的版本
- 切流前提前一周能保证覆盖率
- 线上预演
- 此阶段模拟旧功能可用 -> 旧功能停服 -> 旧功能还原可用,时间在1:00-6:00
- 提前准备包各个系统SOP的操作步骤包括执行人、执行时间、验证人等
- 后端新改造服务已上线(内部可用)内部通过dns方式进行验证
- 涉及到验证客户端&小程序&H5停服,slb流量拦截、slb白名单接口可行、 数据库锁表可读,开启白名单接口可访问,数据增量迁移,数据校验,内部切流后新功能验证,切流预演后端配置还原等(在后续详细SOP步骤列出)
- 复盘
- 统计线上预演发现的问题以及sop过程中失败或者执行超时的任务进行总结优化
- 数仓脏数据复盘总结,确保无线上污染数据进入
- UAT&压测
- 产品、运营、测试、开发集中对App进行切流后的功能验证
- 根据UAT的问题来决定是否发Hotfix版本
- 后端持续进行单接口&全链路压测
- 线上切流
- 切流期间的用户:旧功能可用 -> 旧功能停服 -> 开启切流路由切换到新功能。时间在1:00-7:00
- 和预演相比不用进行线上状态还原,但要执行真正的线上流量切换
- 进行线上环境核心P0 case验证 (其它步骤和预演类似)
- 小程序切流后新版本发布
- 客户端热修
- 根据线上切流期间反馈的问题决定是否进行热修复发布
- 监控
- 持续监控线上切流后稳定性,观察各项业务指标是否正常。
- 前端默认切流版本发布
- 切流后下个版本下线切流逻辑,默认开启切流后的功能,并有计划的开始下线老代码
切流方案
得物
切流项目名:五彩石
主要目标交易线重构包括DB拆分、DDD领域模型引入、支持业务高可编排。客户端引入哥伦布项目增强前端动态化能力
客户端
客户端切流架构图

哥伦布动态化方案


切流SDK

- 客户端采用不同场景拉取数据源,包括网关接口404错误码触发 (根据lazada的经验未考虑额外用push,用接口能满足需求)
- 控制全局路由参数保证路由进行新老切换
- 日志上报实时监控切流情况
切流UI
- 切流ui分为停服中,升级中。停服中主要是后端做数据迁移服务上线。升级中属于客户端内部数据迁移做清理缓存等操作。

切流流程图

- 数据源可以来自多个并发接口返回,不同切流状态控制端上按时序进行队列处理
- 切流一旦成功重新拉起app,保证走的新的路由
报表监控(结尾会补图)
- 要求分钟级刷新
- 数据要求android、ios、版本过滤
- 报表展现包括
- 切流成功率:根据当前设备最后切流状态去重计算DAU / 总DAU
- 切流耗时:切流过程中花费的时间
- 切流用户体验耗时:包括切流耗时以及用户升级页面耗时
- 切流接口UV成功率: 切流接口拉取成功DAU / 总DAU
- 切流接口PV成功率: 切流接口拉取成功次数/ 总次数
- 切流接口耗时:http status code = 200统计耗时
- 切流接口http status code占比:status code占比
路由映射
- 新老页面,由于入参以及路由path发生了变化。需要梳理新老页面路由映射关系,需要同步到后端进行接口、活动模板、push消息、历史存量数据同步更新。客户端如果能做老路由自动转化新路由的兼容一定要做,避免后端数据遗漏。
客户端&H5联调
- 切流后App分享出去的url必须是H5的新url
- App打开站内H5硬编码URL需要缓存新URL
- H5跳转App必须替换为新的URL
- App通过jsbridge调用H5,需要使用H5新的参数
- H5通过jsbridge调用App,需要使用客户端新的参数
小程序
小程序切流逻辑和客户端类似,相对来说简化。考虑到小程序覆盖率会比App容易很多,方案如下。
| 发布时间 | 切流前 | 停服中 | 切流后 |
|---|---|---|---|
| 小程序切流前代码+切流sdk | 切流前 | 可用 | 停服中 |
| 小程序切流后代码+切流sdk | 后端切流完成后上线 | 不可用 | 停服中 |
切流SDK包括停服中ui以及不可用状态

H5
- 切流UI只存在停服中
- 切流后:部分老的H5链接需要充定向到新的服务
- 切流期间,内部测试阶段。通过种入cookie让切流sdk不生效。可以达到内部可用,外部用户继续停服中。种入cookie通过提前写好一个H5页面以扫码方式进入
后端
后端切流方案变迁过程只能说开始想像太美满,现实很残酷。经过几次讨论迭代后的方案
新老服务完全隔离(理想中的状态)
切流前
线上用户正常访问

停服前

- 所有外部请求进行拦截,并返回统一404错误码
- 对“白名单列表”不进行拦截
数据同步完毕,内部测试阶段

- 新交易平台已上线,内部测试包通过替换测试域名能够访问网关
预演切流后 或 切流失败回滚

- 关闭所有流量拦截配置
- 关闭测试阶段网关
切流成功后

- 交易线老接口返回通用错误码
- 其它接口放开访问权限
- 关闭测试阶段网关
实际落地情况由于存在index这种聚合等服务,服务未考虑部署俩套。在请求url相同情况下slb无法区分是访问是新服还是旧服。因此此方案放弃
DNS方案

- DNS方案在切流前解析到老的slb的ip地址,保证访问的是老的交易线服务。切流后通过dns切换slb ip,让前端访问到新的交易平台
- 移动设备在系统层面存在dns缓存,此方案上线可能会导致切流后一部分用户无法使用得物APP。因此此方案放弃
SLB切换方案
切流前线上与内部验证阶段

- 公司内网用户安装内部开发包,通过配置内网dns。可以将内部流量导入到CS-PRD环境,使之与线上环境完全隔离
- CS-PRD 和线上环境一致。但是使用了影子数据库,避免对线上服务环境造成脏数据污染
停服前(数据迁移完毕可以进行内网测试)

预演切流后 或 切流失败回滚
- PRD环境还原
- SLB放开流量
- 白名单接口主要包括客户端像app升级接口、切流接口、热修接口等必须放开线上用户访问的接口
切流成功后

数据迁移
- 数据迁移
- 需要理顺所有业务改造前的表结构设计,以及改造后新的表结构设计
- 数据需要进行字段映射,比如有些存在spuid不发生变化、订单不同状态映射
- 单库向多库多表迁移、多表向单表转换等
- 定期全量数据同步
- 切流停服期间增量数据同步
- 迁移过程数据幂等,多次迁移像主键id等不能受影响
- 数仓统计按新表方式调整统计
- 数据校验
- BI根据新老表报表进行数据对比,验证数据迁移正确性
- 对业务数据总条数进行数量对比
- 自定义脚本进行数据内容比对。对业务数据进行逐条校验,如订单等
- 测试验证
- 数据订正
- 对于流量已经切割完毕,对于存在部分迁移出错需要快速进行数据筛选并进行数据再次订正后回流更新
Lazada
- 切流项目名:Voyager
- Lazada主要东南亚6国,涉及到的团队包括俄罗斯、越南、国内的开发
- Lazada整体切流方案是完全废弃Lazada原有服务,用阿里基架全部重写(包括客户端和后端)。整体影响的业务范围比得物广,开发周期更长。但得物是新老服务混合在一起,得物在切流方案上更复杂点。Lazada 6个国家分三批进行切流,对不同国家都有各自的定制化。
客户端
V1
- 客户端基础架构改造,包括Atlas bundle化以及阿里全家桶,整体迭代节奏如下:

分三条线
- 海外团队:根据老版本进行bugfix,持续迭代进行版本发布。以及强升逻辑准备,配置从firebase拉取
- 基础架构:基于老代码开始进行基础能力改造。包括bundle化,多工程git,数仓等阿里集团sdk并入
- 国内业务线:开始进行新的首页以及搜索模块开发(此处开发的模块只会产生只读的业务,未对lazada原有服务进行数据写的操作)
拆分后的项目渐渐开始有模块化的雏形

V2
- 交易能力上线(真正能切流的版本)当然也是通过切流sdk控制,上线先继续使用老功能。远程切流后切换到新的交易线。和得物一样提前上线提升APP升级覆盖率
- 新的架构如下

- 整个项目核心链路已全部重新实现, 当然阿里全家桶也齐了
- 切流控制左侧完全新开发的业务,右侧lazada原有代码逻辑
V3
- 切流成功:Lazada其它业务模块完整替换,lazada老代码全部下线
切流sdk
- lazada切流sdk和得物类似,数据源会多一些比如orange,接口等。这些得物基架构还有些缺失暂时只考虑了接口(但通过停服期间业务接口返回404增加拉取频率用于补偿切流成功率)
- 客户端需要额外进行一定的数据迁移,包括登录态切换。后端完全是俩套系统。
Lazada主要问题点
- 路由: lazada是全服务替换,因此接口域名路由全部受影响。整个路由映射变得格外复杂,特别是外链做兼容的映射成本很高。
- 稳定性&性能:V3前俩套启动任务包括阿里全家桶和海外三方sdk。俩套库对启动性能和稳定性都有极大的挑战。特此对启动任务进行了优化,集成的俩套启动任务在优化后启动耗时没有恶化。对于稳定性海外三方库的质量确实比阿里系差很多,最后采用asm修改字节码方式对第三方sdk进行了稳定性治理(为撒不升级海外sdk,亲身体验升级部分海外sdk稳定性变的更差)
- 数据回流:海外数据回流国内法律问题。碰到访问taobao的error页面,几乎是所有服务兜底页面。页面过于悠久已经没有明确负责人。后续通过hook socket进行检测有哪些直连国内域名,并挨个进行推进处理。
后端
后端停服和得物类似。由于是换域名换服务,因此在切割上会更简单更直接。但是由于业务的复杂度更高数据迁移成本也会更高。
Daraz
- 切流项目名:叫撒忘记了
- Daraz主要的服务南亚6国。涉及到的团队包括巴基斯坦、印度、越南、国内的开发
- Daraz切流相对来说最简单粗暴。App直接强升,未做中间切流sdk平滑迁移支持。到切流时间点,线上App全部不可用强制要求升级到新版本
Daraz主要问题
- 相对于lazada问题偏少。主要是基于lazada新代码快速改造,做差异化处理。包括语言、接口地址、定制化改造等
- 路由:也需要重新进行映射
切流SOP主要步骤
- 停服公告发布
- 环境准备
- 客户端内部测试包默认开启切流。在外网切流后内部用户能够验证切流后的逻辑
- 客户端老版本验证强升
- 小程序内部测试包默认切流后
- 小程序新代码提前提审不上线(预演阶段不需要)
- H5预演测试页面准备
- 发布集成冻结
- 切流前各业务系统前置准备
- 停止定时任务
- 限流等配置全局review
- 全量数据迁移,为增量做准备
- 业务kafaka、缓存清空
- 热点数据提前缓存预热
- 等等
- 正式切流
- 前端停服
- 客户端停服
- H5停服
- 小程序停服
- 旧版本APP配置强升
- SLB停服
- 开启线上白名单接口,端上需要校验切流、热修等接口是否正常
- 确保各域Job、MQ、kafaka消息消费完毕
- 各业务线进行停服操作
- 旧数据库对即将进行数据迁移的表进行readonly处理
- 数据迁移
- 进行数据增量迁移
- SLB切换到新的服务组
- 各业务线对新服进行相关配置修改
- 包括脏数据删除
- 数据迁移完毕
- 进行校验和订正
- 进行内部核心链路测试
- 使用公司局域网对全链路进行全链路测试
- 外围系统配合一起测试验证(如95分)
- 切流最后决策
- 根据测试反馈的问题判断是进行切流还是回滚
- JOB服务还原
- SLB开启外网访问流量
- 前端流量还原
- H5切换为切流后
- 客户端切换为切流后
- 小程序切换为切流后,验证线上小程序是不可用状态
- 新版小程序各渠道上线
- 线上包进行功能走查
- 线上持续监控
- 包括切流指标、crash、业务指标等
- 线上切流复盘总结
- 前端停服
前端监控指标
Android
- 报表涉及敏感数据未粘贴
- 切流成功设备趋势正常
- 停服平均耗时:6ms
- 停服到切流完成平均耗时:25ms
- 切流完成平均耗时:37ms
- 切流接口平均耗时:468ms
- 切流接口PV成功率: 99.37%
- 切流接口UV成功率:99.86%
- Http status code 200成功率:99.4%
IOS
- 报表涉及敏感数据未粘贴
- 切流成功设备趋势正常
- 停服平均耗时:0.4ms
- 停服到切流完成平均耗时:0.93ms
- 切流完成平均耗时:14.53ms
- 切流接口平均耗时:926ms
- 切流接口PV成功率: 98.76%
- 切流接口UV成功率:99.96%
- Http status code 200成功率:99.55%
小程序
- 报表涉及敏感数据未粘贴
- Http status code 200成功率:99.84%
- 切流接口平均耗时:679ms
- 切流接口PV成功率:99.83%
- 切流接口UV成功率:99.99%
其它问题
通知消息
在停服中android内部用户通过历史的通知进入了app(绕过了切流页面)。虽然slb有拦截,但这个确实是切流sdk遗漏的小细节点。相对于停服ui与功能不可用,用户体验确实差一点。
HTTP长连缓存
APP发版本前做最后切流测试,测试期间由于是俩套环境俩套slb。通过电脑代理访问新服环境,由于slb的ip发生了变化,app未重启存在长连缓存。导致app存在部分长连到老服务,就出现ui发生变化但是接口全报错。当时也是虚惊一场,实际线上切流ip是不会变的。切流sdk如果设计的更严谨点的话应该干掉所有http请求实例保证长连缓存全断开。
HTTPDNS
客户端存在基建的缺失。如果客户端早期架构接入过httpdns,后续就不需要运维进行slb进行机器组替换了。方案上至少可以多一种选择
小程序拒审
小程序提前提审切流后的版本,计划在切流成功后直接上线。由于待提审的版本访问的是新服务,同时切流开关还是切流前。小程序在切流前是不可用的。字节审核比较严格,发现无法使用直接审核失败。后续也是与字节相应同学沟通才提审成功。这里吸取教训还是不能偷懒。小程序应该和客户端一样采用俩套代码,根据切流开关进行切换。对外部不可控的因素也需要多加考虑,多个备选方案,避免埋下不可控的风险。
小结
五彩石项目还是比较顺利。整个团队180多人大家都能齐心协力为一个目标奋斗而努力,体现了整个团队高执行力。非常赞
得物客户端基础架构热招android、ios、后端架构。微信:familyhappyli