9.2 移动端与后端的数据交换


9.2 移动端与后端的数据交换:弱网、碎片与包体

本节摘要:移动端现场的三条约束改写了 protobuf 的使用姿势:弱网与离线要求同步协议围绕"未知字段保留"设计、App 版本碎片化把枚举降级义务放大成常态、序列化库的包体与能耗进入选型视野。本节设计一套离线同步协议并逐项处理三条约束,给出移动端的选型清单。读完你应当能设计出在 3% 存活版本上不崩的同步协议。

第二现场。微服务现场的主角是"治理",移动端现场的主角是"韧性"——第 5 章的兼容机制在这里从工程纪律升级成生存条件。

约束一:弱网与离线,同步协议的形状

移动端不能假设网络可用,数据同步协议必须围绕"长时间滞后后追平"设计。协议骨架:

message SyncRequest { string device_id = 1; int64 since_version = 2; // 上次同步到游标(版本号或时间戳) bytes page_token = 3; // 断点续传游标(分页续拉) } message SyncResponse { int64 latest_version = 1; repeated ChangeOp changes = 2; // 变更操作流 string next_page_token = 3; // 空表示拉完 }

三个 protobuf 特定的设计点。其一,changes 的增量语义:整包快照(每轮发全量)实现简单但流量线性爆炸;变更流(只发差异)要靠 since_version 游标——而游标字段用 int64 存版本号时,服务端的版本单调性必须与第 2 章的类型选型对齐(值域只增不减,int64 一步到位)。其二,分页续传:弱网下大响应中途断掉是常态,page_token 的 bytes 类型装不透明的续传凭据,服务端不用理解只回传——这是 6.3 节"信封哲学"的微型应用。其三,设备间合并的未知字段义务:离线期间多设备各自产生变更,合并发生在客户端时——合并代码必须走运行时 Clone/Merge(第 5.3 节保真纪律),否则用户设备上的新字段(App 新版本写入的)被旧代码的合并路径剥掉,数据静默丢失且无法追责。

约束二:版本碎片化,降级义务的常态化

微服务群的服务升级以天计,移动端 App 的版本存活以月计——发布两年后仍有 3% 的用户跑在古早版本上。第 5.2 节的枚举降级义务在移动端是常态而非例外:

服务端义务:所有响应里的枚举值默认"最老在线版本不认识"——给每条 enum 值标注"引入版本",发布检查器(第 6.1 节 option 的又一个消费场景)比对"最老存活 App 版本认识哪些值",越界即拦截发布。这是第 4.3 节"契约元数据摊到 CI"模式的移动端版。

客户端义务:switch 枚举的 default 分支是产品逻辑而不是错误处理——遇到不认识的枚举值(服务端新版本发的)按"通用展示态"渲染(未知态显示占位图标而非崩溃或丢弃数据)。第 1.2 节 0 值盲区在这里也有移动端变体:UNSPECIFIED 枚举值渲染为中性态,别让它悄悄等于第一个业务态。

未知字段的存储链路:App 缓存同步数据到本地(后续章节:SQLite 或文件),缓存层若做了 proto→自有模型的转换,未知字段到这里为止——缓存层必须原样存 protobuf 字节(或经 Clone 保真),自有模型转换只发生在渲染层。多版本 App 共用同一缓存(升级覆盖安装)时,这是新旧数据无声混居的唯一安全通道。

约束三:包体与能耗,序列化库的移动端选型

服务端选库看吞吐,移动端先看三样:包体增量(运行时加生成代码给 APK/IPA 增加的体积——跨语言实现差异可达数倍,反射重的实现(如某些 JVM 系方案)在移动端是禁区)、启动开销(生成代码的注册与初始化发生在 App 冷启动路径上还是懒加载)、每消息能耗(移动 CPU 上单条编解码的耗时直接乘电池——第 7.1 节的基准方法原样适用,只是口径从吞吐换成单位消息能耗)。

选型判据表:

维度 服务端优先级 移动端优先级
编解码吞吐 第一 第三(够用即可)
包体增量 无所谓 第一
冷启动开销 无所谓 第二
反射支持(第6章功能) 重要 尽量避免(体积与能耗双税)
平台覆盖 按服务语言 iOS/Android 双端(含跨端框架)

移动端要第 6 章的反射与动态消息功能时优先自问:是不是服务端做掉更合适——把动态性留在服务端、把静态生成的精简代码发到端上,是包体与灵活性的常见折中。

实战案例:一个离线优先笔记应用的同步层

背景:笔记应用,离线可编辑、多设备同步,后端 Go、客户端 Android(Java/Kotlin 混合)与 iOS(Swift),两年存续期。操作:同步协议按本节骨架实现,变更流带 since_version 游标与 bytes 续传凭据;合并策略——服务端权威合并(客户端只上报本地操作,复杂合并不上端)绕开多端合并的保真雷区,缓存层原样存 protobuf 字节,渲染层才转视图模型;枚举纪律——操作类型枚举的每个值标注引入版本,发布门禁比对最老存活 App;版本演练——每次发版前用"两年前的老 App + 最新后端"过一遍冒烟集(同步、未知枚举、未知字段全链路)。结果:两年里协议演进 14 次(含两次字段类型级迁移走双写),线上零起"老版本数据丢失"事故;一起"新字段消失"的客诉定位到某低端机缓存层私自重建消息(违反保真纪律),修复后该机型下发版清缓存。解读:移动端韧性的全部来源可以压缩成一句话——让老版本永远能安全地"不理解"新东西:枚举有中性态、字段有未知容器、缓存保原始字节;三条全部是第 3、5 章机制在端上的投影。变式:若应用是强实时协作(多人同时编辑、冲突高频),服务端权威合并的延迟不可接受,端上合并不可避免——此时合并层必须用官方运行时的 DeepClone/Merge 并配 5.3 节的往返保真 CI 用例,把"端上合并"的保真纪律机器化。

本节要点回顾

  • 同步协议三件:版本游标(int64 单调)、断点续传凭据(bytes 不透明回传)、变更流代替全量快照;
  • 端上合并是保真雷区:官方 Clone/Merge 或原样字节,手写搬运必丢未知字段;
  • 降级义务常态化:枚举值标注引入版本进发布门禁,客户端 default 是产品逻辑;
  • 缓存存原始字节:新旧版本 App 的数据混居通道,渲染层才转模型;
  • 移动端选库三看:包体、冷启动、单位能耗——反射重的实现是禁区。

移动端收工。下一个现场把频率推到极限:游戏同步的百毫秒广播与状态存档的长周期二进制治理。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U