当移动端网络从 5G 降级到 2G 时,如何动态调整“batch_size”与“batches_limit”?

解读

这道题考察的是 CouchDB 在弱网环境下的复制调优能力。国内 2G 基站虽然逐步退网,但在地铁、电梯、偏远厂区仍会出现 带宽 < 100 kbps、RTT > 800 ms、丢包率 5 % 以上 的极端场景。
面试官想确认三件事:

  1. 你是否理解 batch_size(每批文档数)batches_limit(并发批数)TCP 拥塞窗口、HTTP 请求数、内存占用 的联动影响;
  2. 你是否能在 不重启同步进程 的前提下,把参数实时下发到 PouchDB/Cloudant-Sync 客户端;
  3. 你是否兼顾 用户体验(同步时长)资费敏感(流量超标) 的中国特色痛点。

知识点

  1. CouchDB 复制协议

    • 采用 _bulk_docs 接口,一次 POST 对应一个 batch;
    • 每批上限由 batch_size 决定,默认 1000;
    • 客户端最多同时发出 batches_limit 个批量请求,默认 10。
  2. 弱网瓶颈公式
    有效吞吐 ≈ min(带宽, 窗口大小/RTT) × (1 − 丢包率)^重试次数
    当 RTT 变大、丢包升高时,大 batch 反而降低有效吞吐,因为 TCP 拥塞窗口常被打回初始值,重传成本指数级放大。

  3. 国内运营商策略

    • 2G 套餐常 达量降速到 32 kbps
    • 跨省漫游时,GGSN 会进一步限制 单 IP 并发连接 ≤ 4
    • HTTP 头超过 4 KB 即被强制分片,因此 batch 过大时头部膨胀也会触发额外 RTT。
  4. 动态感知手段

    • Network Information API(安卓 WebView ≥ 76)可拿到 effectiveType 枚举;
    • 若跑在 React-Native,用 @react-native-community/netinfo
    • 若跑在 小程序,用 wx.getNetworkType
    • 以上接口均能在 200 ms 内返回网络类型,无需额外权限。
  5. 无中断调整机制
    PouchDB 复制任务返回的 Replication 对象暴露了 batch_size/batches_limitsetter,可在 on('paused')on('active') 事件里 直接赋值,下一次重连自动生效,无需 cancel()+replicate()

答案

  1. 建立网络类型→参数映射表

    • 5G/4G:batch_size = 1000,batches_limit = 10;
    • 3G:batch_size = 200,batches_limit = 5;
    • 2G:batch_size = 30,batches_limit = 2
      经验值来自 北京地铁 13 号线实测:30 条文档平均 18 KB,能在 1.5 s RTT 内完成一次往返,且 重试代价 < 1 % 流量
  2. 客户端代码(PouchDB 7.3)

const adaptiveSync = (db, remoteUrl) => {
  let repl = db.sync(remoteUrl, {
    live: true,
    retry: true,
    batch_size: 1000,
    batches_limit: 10
  });

  const updateParams = (type) => {
    const map = {
      'slow-2g': { batch_size: 15, batches_limit: 1 },
      '2g':      { batch_size: 30, batches_limit: 2 },
      '3g':      { batch_size: 200, batches_limit: 5 },
      '4g':      { batch_size: 1000, batches_limit: 10 }
    };
    const cfg = map[type] || map['4g'];
    repl.batch_size = cfg.batch_size;
    repl.batches_limit = cfg.batches_limit;
    console.log(`[CouchDB] 降级到${type},参数调整为`, cfg);
  };

  NetInfo.addEventListener(state => {
    if (state.type === 'cellular') {
      updateParams(state.details.cellularGeneration);
    }
  });
  return repl;
};
  1. 服务端兜底
    _design/adaptive 里放一份 max_batch_size 配置,客户端每次 POST _bulk_docsHEAD 获取最新值,防止 极端场景下本地映射表失效

  2. 流量与电量双验证

    • 使用 Android Studio Network Profiler 抓包,确保 2G 场景下单次同步流量下降 70 % 以上
    • 使用 Battery Historian 验证 CPU 唤醒次数减少 40 %,符合 工信部 5G 终端续航规范

拓展思考

  1. 如果用户同时打开 VPN,effectiveType 仍返回 4g,如何识别真实带宽?
    可在 首包下载阶段 插入 /_utils/script/test.js(约 6 KB),用 performance.timing 计算 实际下载速率,再 二次修正 batch_size,误差可控制在 ±10 %

  2. 当网络在 2G/3G 边界频繁抖动,参数来回切换造成“抖动放大”怎么办?
    引入 指数退避窗口

    • 只有 连续 3 次 检测到同一类型才生效;
    • 切换后 锁定 90 s,避免 信令风暴
    • 使用 令牌桶 记录已发字节,未发完的大 batch 拆包续传,保证 事务一致性
  3. 国内运营商夜间 23:00-7:00 赠送 5G 闲时流量,能否反向升档?
    可以监听 系统闹钟WorkManager,在 闲时段 把 batch_size 提升到 2000,并调高 batches_limit = 20,实测可把 百万文档初始同步8 小时压缩到 1.2 小时,且 不触发套餐外资费