如何灰度 1% 用户?

解读

国内互联网面试中,“灰度 1% 用户”并不是让你真的去改 CouchDB 源码,而是考察候选人能否在分布式、多主、离线优先的 CouchDB 体系里,安全、可控、可回滚地把新视图、新设计文档或新同步逻辑只暴露给 1% 的终端用户,同时保证国内移动端网络波动、应用商店审核、合规审计三大现实约束不被打破。
一句话:让 1% 的真实用户“无感知”地命中新逻辑,其余 99% 继续走老逻辑,且随时可秒级回滚。

知识点

  1. CouchDB 无服务器端路由层,灰度决策必须放在同步网关业务网关里完成,不能依赖数据库自身。
  2. 国内合规要求:用户标识必须脱敏,不能用明文手机号做哈希,需走国密 SM3 散列后取模
  3. 多主复制场景下,灰度开关必须以文档形式写进 _global_changes,保证所有节点 0 延迟感知,避免“部分节点灰度”导致数据分叉。
  4. 离线优先场景下,灰度策略必须随设计文档一起同步到本地 PouchDB,否则用户断网后重启 App 会丢失灰度标志。
  5. 可回滚:灰度文档带expire_at 字段,TTL 一到自动回滚,避免凌晨故障无人值守。

答案

生产级方案分四层:
① 流量入口层:在阿里云 API 网关或自研 BFF 层,统一注入灰度头 x-couch-gray。国内 App 一般已有统一网络库,直接对用户 ID 取 SM3 后 16 进制转 long,再对 100 取模,余 0 即命中 1%。
② 同步网关层:使用 CouchDB 官方推荐的couchdb-sync-gateway(国内蘑菇街、小红书已落地),在on_before_push钩子里读取 x-couch-gray 头,把灰度标志写进本地_doc 的gray_tag字段。
③ 视图层:新建设计文档_design/v2_gray,里面包含新视图 map/reduce。在validate_doc_update里强制校验:如果gray_tag===true才允许写新字段,否则返回 403,防止 99% 用户误写新字段导致数据污染
④ 回滚层:灰度设计文档里加expire_at: unix_timestamp+7200,CouchDB 的_db_updates feed 会实时捕获,过期后自动删除设计文档,1% 用户立即回退到旧视图;同时阿里云 SLS 日志里打印 gray=off,方便审计。

全链路对 CouchDB 本身零侵入,只依赖其MVCC 与 _changes feed能力,符合国内“数据库只存数据,逻辑上移”的架构规范。

拓展思考

  1. 如果 1% 灰度后需要按省份再细拆 10%,可在灰度文档里加region_hash字段,利用 CouchDB 的filtered replication,让华东节点只同步region_hash in (shanghai,jiangsu,zhejiang)的文档,节省 30% 跨省流量费
  2. 国内监管要求个人信息不出境,若使用 CouchDB 3.x 的q=8 分片,需把灰度文档放在q=0分片,确保该分片部署在境内可用区,其余分片可放海外,实现“灰度数据境内留痕,全量数据全球同步”
  3. 面试常追问:灰度过程中主键冲突怎么办?提前在设计文档里加_id: userId::gray=1的命名空间,利用 CouchDB 的_id 唯一性天然隔离,回滚时直接批量_delete 带 gray=1 的 _id 即可,无需写脚本扫表。