如何灰度 1% 用户?
解读
国内互联网面试中,“灰度 1% 用户”并不是让你真的去改 CouchDB 源码,而是考察候选人能否在分布式、多主、离线优先的 CouchDB 体系里,安全、可控、可回滚地把新视图、新设计文档或新同步逻辑只暴露给 1% 的终端用户,同时保证国内移动端网络波动、应用商店审核、合规审计三大现实约束不被打破。
一句话:让 1% 的真实用户“无感知”地命中新逻辑,其余 99% 继续走老逻辑,且随时可秒级回滚。
知识点
- CouchDB 无服务器端路由层,灰度决策必须放在同步网关或业务网关里完成,不能依赖数据库自身。
- 国内合规要求:用户标识必须脱敏,不能用明文手机号做哈希,需走国密 SM3 散列后取模。
- 多主复制场景下,灰度开关必须以文档形式写进 _global_changes,保证所有节点 0 延迟感知,避免“部分节点灰度”导致数据分叉。
- 离线优先场景下,灰度策略必须随设计文档一起同步到本地 PouchDB,否则用户断网后重启 App 会丢失灰度标志。
- 可回滚:灰度文档带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% 灰度后需要按省份再细拆 10%,可在灰度文档里加
region_hash字段,利用 CouchDB 的filtered replication,让华东节点只同步region_hash in (shanghai,jiangsu,zhejiang)的文档,节省 30% 跨省流量费。 - 国内监管要求个人信息不出境,若使用 CouchDB 3.x 的q=8 分片,需把灰度文档放在
q=0分片,确保该分片部署在境内可用区,其余分片可放海外,实现“灰度数据境内留痕,全量数据全球同步”。 - 面试常追问:灰度过程中主键冲突怎么办?提前在设计文档里加
_id: userId::gray=1的命名空间,利用 CouchDB 的_id 唯一性天然隔离,回滚时直接批量_delete 带 gray=1 的 _id 即可,无需写脚本扫表。