第一章:Golang小程序开放平台灰度发布体系概览
在高并发、强一致性的小程序开放平台场景中,灰度发布是保障服务稳定性与功能验证闭环的核心机制。本平台基于 Golang 构建的微服务架构,将灰度能力深度集成至网关层、配置中心与业务服务三者协同链路中,实现流量染色、策略路由、动态降级与实时观测的一体化支撑。
核心设计原则
- 无侵入性:业务代码无需修改即可接入灰度,依赖统一中间件(
gray-middleware)自动解析请求头中的X-Gray-Id与X-Release-Tag; - 多维分流能力:支持按用户 ID 哈希、OpenID 白名单、地域 IP 段、小程序版本号等维度组合匹配;
- 配置即代码:灰度规则以 YAML 文件形式托管于 GitOps 仓库,并通过 Watcher 实时同步至 etcd 集群。
灰度流程关键环节
- 请求进入 API 网关(基于 Gin + custom middleware),自动提取灰度标识;
- 网关查询
gray-rule-service获取匹配规则,决定路由至stable或canary版本实例; - 目标服务启动时向注册中心上报
version=1.2.0-canary标签,供网关识别; - 全链路日志自动注入
gray:true字段,便于 ELK 聚合分析。
快速启用示例
以下为服务端启用灰度中间件的最小代码片段:
func main() {
r := gin.Default()
// 注册灰度中间件(自动读取环境变量 GRAY_ENABLE=true)
r.Use(gray.Middleware())
r.GET("/api/user/info", func(c *gin.Context) {
// 业务逻辑无需感知灰度状态
c.JSON(200, gin.H{"data": "ok"})
})
r.Run(":8080")
}
该中间件会自动完成请求染色透传、上下文携带及指标打点,开发者仅需确保部署时设置 GRAY_ENABLE=true 与 SERVICE_VERSION=1.2.0-canary 即可参与灰度集群。
| 组件 | 作用 | 是否可选 |
|---|---|---|
| Gray Gateway | 流量分发与策略执行 | 必选 |
| Config Sync | 同步灰度规则至本地内存缓存 | 必选 |
| Canary Probe | 主动探测 canary 实例健康状态 | 推荐启用 |
| Trace Export | 上报灰度请求链路至 Jaeger/OTLP | 可选 |
第二章:Kubernetes基础设施层的灰度支撑能力构建
2.1 多命名空间与资源隔离策略在小程序多租户场景下的实践
在小程序多租户架构中,命名空间(Namespace)是实现逻辑隔离的核心机制。每个租户独占一个命名空间前缀,避免集合、云函数、数据库权限交叉。
数据库命名空间隔离示例
// 云函数中动态拼接租户专属集合名
const tenantId = event.headers['X-Tenant-ID'] || 'default';
const collectionName = `${tenantId}_orders`; // 如:t_abc123_orders
该方式将租户ID嵌入集合名,配合数据库安全规则(如 resource.collection == auth.token.namespace + '_orders'),实现读写级硬隔离。
隔离策略对比
| 策略类型 | 隔离粒度 | 运维成本 | 扩展性 |
|---|---|---|---|
| 命名空间前缀 | 集合级 | 低 | 高 |
| 独立环境实例 | 应用级 | 高 | 低 |
权限控制流程
graph TD
A[小程序请求] --> B{解析X-Tenant-ID}
B --> C[路由至对应命名空间云函数]
C --> D[DB规则校验collection前缀]
D --> E[执行租户专属数据操作]
2.2 Deployment滚动更新与Pod就绪探针的精细化控制
就绪探针(readinessProbe)的核心作用
确保流量仅路由至真正可服务的Pod,避免新实例在初始化未完成时接收请求。
滚动更新中的关键参数协同
apiVersion: apps/v1
kind: Deployment
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多额外创建1个Pod
maxUnavailable: 0 # 更新期间0个Pod不可用(强可用保障)
template:
spec:
containers:
- name: nginx
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5 # 启动后5秒开始探测
periodSeconds: 10 # 每10秒探测一次
failureThreshold: 3 # 连续3次失败才标记为NotReady
maxUnavailable: 0强制Kubernetes先扩容再缩容,配合readinessProbe实现零损更新;initialDelaySeconds需大于应用冷启动耗时,否则探针过早失败导致Pod反复重启。
探针状态与Service流量分发关系
| Pod状态 | Service是否转发流量 | 原因说明 |
|---|---|---|
| Running + Ready | ✅ 是 | Endpoints列表中包含该Pod IP |
| Running + NotReady | ❌ 否 | 被从Endpoints中临时移除 |
更新流程可视化
graph TD
A[开始滚动更新] --> B[创建新Pod]
B --> C{readinessProbe成功?}
C -->|否| D[保持Pending/NotReady]
C -->|是| E[加入Endpoints]
E --> F[逐步终止旧Pod]
2.3 基于Label Selector与Node Affinity的流量亲和性调度
在微服务架构中,将特定流量(如灰度请求)调度至带标签的节点,需协同使用 labelSelector 与 nodeAffinity。
核心机制对比
| 特性 | Label Selector | Node Affinity |
|---|---|---|
| 作用层级 | Pod 级标签匹配(Service/Ingress 后端筛选) | 调度器级节点约束(Pod 创建时绑定) |
| 执行时机 | 流量转发阶段 | Pod 调度阶段 |
| 灵活性 | 动态可变(无需重启) | 静态声明(需重新调度生效) |
实践示例:灰度节点亲和调度
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In
values: ["gray"] # 仅调度到标记 env=gray 的节点
逻辑分析:
requiredDuringSchedulingIgnoredDuringExecution表示硬性约束——若无匹配节点,Pod 将处于Pending状态;key: env对应节点标签kubectl label nodes node-1 env=gray;operator: In支持多值匹配,增强灰度集群扩展性。
调度协同流程
graph TD
A[Ingress 按 header 匹配 labelSelector] --> B[路由至 gray-service]
B --> C[gray-service 的 Pod 由 nodeAffinity 确保运行于 gray 节点]
C --> D[流量闭环于灰度资源池]
2.4 ConfigMap/Secret热更新机制与小程序配置动态生效验证
小程序后端常通过挂载 ConfigMap/Secret 实现配置外置化。Kubernetes 默认不主动通知容器配置变更,需依赖应用层轮询或文件系统 inotify 监听。
数据同步机制
Pod 中挂载的 ConfigMap 以 subPath 方式注入时不触发热更新;而整卷挂载(volumeMounts + volumes)则支持自动更新(延迟约10s),底层由 kubelet 定期同步 etcd 中的版本。
# 推荐:整卷挂载,启用热更新
volumeMounts:
- name: app-config
mountPath: /etc/config
readOnly: true
volumes:
- name: app-config
configMap:
name: wx-miniprogram-config
逻辑分析:
subPath使文件成为静态符号链接,绕过 kubelet 的文件监听;整卷挂载则让 kubelet 将/etc/config/视为可监控目录,检测到resourceVersion变更后重写文件并触发inotify IN_MODIFY事件。
验证流程关键指标
| 指标 | 值 | 说明 |
|---|---|---|
| 更新延迟(中位数) | 9.2s | 从 ConfigMap 更新到文件就绪 |
| 小程序配置生效耗时 | ≤1200ms | 应用层监听+解析+缓存刷新 |
| 失败重试间隔 | 3s | 文件监听失败后的退避策略 |
graph TD
A[ConfigMap 更新] --> B[kubelet 检测 resourceVersion 变更]
B --> C[重写挂载目录下文件]
C --> D[inotify 通知应用进程]
D --> E[应用解析新配置并 reload]
E --> F[小程序 API 返回最新配置值]
2.5 Horizontal Pod Autoscaler与灰度流量突增的弹性响应实测
为验证HPA在灰度发布期间对突发流量的真实响应能力,我们在Kubernetes 1.28集群中部署了基于CPU和自定义指标(QPS)的双触发策略。
实验配置要点
- 使用
kubectl autoscale创建HPA,目标CPU利用率设为60%,QPS阈值设为120 req/s - 灰度服务启用Prometheus Adapter暴露
http_requests_total指标 - 模拟流量由
hey -z 30s -q 50 -c 10发起,持续注入渐进式突增负载
HPA配置示例
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Pods
pods:
metric:
name: http_requests_total
target:
type: AverageValue
averageValue: 120
该配置启用双指标协同决策:CPU反映资源饱和度,QPS直接关联业务吞吐。averageValue对Pods类型指标采用滑动窗口均值计算,避免瞬时毛刺误扩;minReplicas: 2保障灰度基线稳定性。
响应延迟对比(单位:秒)
| 流量增幅 | CPU触发扩容耗时 | QPS触发扩容耗时 | 首次副本就绪时间 |
|---|---|---|---|
| +80% | 42 | 28 | 19 |
| +200% | 38 | 23 | 17 |
扩容决策流程
graph TD
A[Metrics Server采集] --> B{CPU > 60% ?}
A --> C{QPS > 120 ?}
B -->|Yes| D[触发扩容]
C -->|Yes| D
D --> E[计算期望副本数]
E --> F[调用API Server更新ReplicaSet]
实验表明:QPS指标比CPU更早触发扩容,平均快14秒,更适合灰度场景下对用户体验敏感的弹性需求。
第三章:Istio服务网格层的流量治理深度集成
3.1 VirtualService+DestinationRule实现小程序API级AB分流模型
小程序后端需对 /api/v1/user/profile 接口实施灰度发布,将 5% 流量导向新版本服务 user-service-v2。
核心资源协同机制
DestinationRule 定义子集(subsets),VirtualService 基于 HTTP header 或权重路由至对应子集:
# DestinationRule:声明两个服务子集
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service-dr
spec:
host: user-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
此配置使 Istio 识别带
version: v1/v2标签的 Pod;subsets是路由目标的基础抽象,无此定义则 VirtualService 无法引用v1/v2。
# VirtualService:按权重分流(95%→v1,5%→v2)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-api-vs
spec:
hosts:
- user-service
http:
- route:
- destination:
host: user-service
subset: v1
weight: 95
- destination:
host: user-service
subset: v2
weight: 5
weight总和必须为 100;Istio 网关或 Sidecar 按此比例分发请求;注意:仅对匹配的 HTTP 路由生效,不作用于 TCP 流量。
分流能力对比表
| 维度 | 传统 Nginx AB 测试 | Istio VirtualService+DR |
|---|---|---|
| 粒度 | 域名/路径级 | API 路径 + Header + Query + 权重多维组合 |
| 动态调整 | 需重载配置 | CRD 实时生效(秒级) |
| 依赖基础设施 | 侵入业务网关 | 与业务代码完全解耦 |
流量决策流程(mermaid)
graph TD
A[Ingress Gateway] --> B{HTTP Host / Path Match?}
B -->|Yes| C[Apply VirtualService Rules]
C --> D[Header/Query 匹配?]
D -->|Yes| E[路由至指定 subset]
D -->|No| F[按 weight 分流]
F --> G[DestinationRule 查找对应 label Pod]
G --> H[Envoy 发起上游调用]
3.2 Envoy Filter扩展自定义Header透传与小程序OpenID上下文注入
在微服务网关层统一注入小程序用户上下文,是保障后端服务无感鉴权的关键。Envoy 的 HTTP_FILTER 扩展能力可精准拦截请求,在入口处解析 X-WX-Code 或 X-WX-Signature,调用微信后台接口换取 openid,并注入标准化 Header。
Header 注入策略
- 优先复用
x-user-id与x-openid双 Header,兼容现有鉴权中间件 - 若原始请求含
x-envoy-force-trace,自动附加x-trace-openid用于链路对齐 - 超时或调用失败时降级为透传原始
x-wx-code,避免阻断流程
Envoy WASM Filter 核心逻辑(Rust 片段)
// 从请求头提取微信临时码
let code = headers.get("x-wx-code").and_then(|h| h.to_str().ok());
if let Some(c) = code {
let openid = fetch_openid_from_wechat(c).await; // 异步调用微信 OAuth2 接口
headers.add("x-openid", HeaderValue::from_str(&openid).unwrap());
}
该逻辑在 on_request_headers 阶段执行,fetch_openid_from_wechat 封装了带重试、缓存(LRU)、限流的 HTTP 客户端,避免网关成为微信接口瓶颈。
OpenID 注入流程
graph TD
A[Client Request] --> B{Has x-wx-code?}
B -->|Yes| C[Call WeChat API]
B -->|No| D[Pass-through]
C --> E{Success?}
E -->|Yes| F[Inject x-openid]
E -->|No| G[Log + Forward original header]
F & G --> H[Upstream Service]
3.3 Kiali+Grafana联合观测小程序灰度链路成功率与延迟热力图
数据同步机制
Kiali 通过 Istio 的 istio-telemetry(现为 istiod 内置遥测)实时拉取服务网格指标,Grafana 则对接同一 Prometheus 实例,确保时序数据源一致。
热力图构建关键配置
# grafana-dashboard.json 片段:灰度标签过滤
targets:
- expr: |
histogram_quantile(0.95, sum(rate(istio_request_duration_milliseconds_bucket{
reporter="destination",
destination_workload_namespace="miniapp-prod",
destination_workload=~"miniapp-v1|miniapp-v2"
}[5m])) by (le, destination_workload, request_protocol))
legendFormat: "{{ destination_workload }}-p95-{{ request_protocol }}"
此查询按灰度版本(
miniapp-v1/v2)和协议维度聚合 P95 延迟;rate(...[5m])消除瞬时抖动,histogram_quantile还原直方图分位数,保障热力图纵轴为真实延迟分布。
Kiali 与 Grafana 协同视图对比
| 维度 | Kiali 主要用途 | Grafana 补充能力 |
|---|---|---|
| 链路拓扑 | 实时服务依赖关系渲染 | 不直接支持 |
| 成功率热力图 | 仅支持表格/折线聚合 | 支持 XY 热力图(X=时间,Y=版本,颜色=成功率) |
| 标签下钻 | 支持 canary、stage 等自定义标签过滤 |
依赖 Prometheus label 保留完整性 |
联动诊断流程
graph TD
A[小程序请求打标] --> B{Istio Sidecar 注入}
B --> C[Envoy 生成 metrics + trace]
C --> D[Kiali 展示灰度拓扑与错误率]
C --> E[Prometheus 存储分位延迟]
E --> F[Grafana 渲染版本×时间热力图]
D & F --> G[交叉定位 v2 版本在 14:00 出现延迟尖峰]
第四章:自定义路由规则引擎与AB测试闭环落地
4.1 基于Go Plugin机制的动态路由策略加载与热插拔设计
Go 的 plugin 包(仅支持 Linux/macOS,需 buildmode=plugin)为运行时加载策略模块提供了原生支持,规避了进程重启开销。
核心约束与前提
- 插件必须导出符合约定接口的函数(如
NewRouter()) - 主程序与插件需使用完全一致的 Go 版本与依赖哈希,否则
plugin.Open()失败
策略插件接口定义
// plugin/router.go —— 插件需实现此接口
type Router interface {
Route(req *http.Request) string // 返回目标服务名
Name() string // 策略标识符
}
逻辑分析:
Route()是核心调度入口,接收原始请求并返回逻辑服务名(如"payment-v2");Name()用于运行时注册与日志追踪。参数*http.Request提供完整上下文(Header、URL、Body 可读取),但注意 Body 需提前ioutil.ReadAll并重置req.Body。
插件加载流程
graph TD
A[读取插件路径] --> B[plugin.Open]
B --> C{加载成功?}
C -->|是| D[Lookup Symbol NewRouter]
C -->|否| E[记录错误并跳过]
D --> F[调用 NewRouter 构造实例]
F --> G[注册至路由策略中心]
支持的策略类型
| 类型 | 触发条件 | 示例 |
|---|---|---|
| HeaderRoute | X-Canary: true |
灰度流量分流 |
| PathPrefix | /api/v2/ |
版本路由 |
| WeightedRandom | 权重配置(如 v1:70%, v2:30%) |
A/B 测试 |
热插拔通过 os.Notify(os.Interrupt) 捕获信号,触发插件卸载(需插件自身释放资源)与新版本重新加载。
4.2 小程序用户分群标签(地域/版本/设备/行为)的实时路由匹配实践
为支撑千人千面的精准运营,需在毫秒级完成多维标签组合的实时路由决策。
标签匹配引擎架构
// 基于 Redis Sorted Set + Lua 脚本实现低延迟匹配
-- Lua script: match_user_tags.lua
local uid = ARGV[1]
local geo = ARGV[2] -- 如 "shanghai"
local ver = ARGV[3] -- 如 "3.8.0"
local os = ARGV[4] -- "ios" / "android"
local act = tonumber(ARGV[5]) -- 最近7日活跃次数
-- 查询预计算的标签规则桶(ZSET key: rule:bucket:{geo}:{ver}:{os})
local candidates = redis.call('ZRANGEBYSCORE', 'rule:bucket:'..geo..':'..ver..':'..os, act, '+inf')
return candidates
该脚本将地域、版本、设备三重静态标签作为规则索引前缀,行为指标(如活跃频次)转为动态评分维度,通过 ZRANGEBYSCORE 实现 O(log N) 范围匹配,规避全量遍历。
匹配策略优先级表
| 维度 | 示例值 | 权重 | 是否可变 |
|---|---|---|---|
| 地域 | beijing |
3 | 否 |
| 版本 | 3.9.1+ |
2 | 是 |
| 设备 | ios-16.4+ |
2 | 是 |
| 行为 | pay_count≥2 |
4 | 是 |
数据同步机制
graph TD A[小程序端上报原始事件] –> B{标签计算服务} B –> C[Redis 实时写入用户最新标签快照] B –> D[MySQL 归档用于回溯分析] C –> E[路由网关按需拉取并执行匹配]
4.3 AB测试指标埋点、数据采集与Statistical Significance自动判定
埋点规范统一化
前端通过 trackEvent 标准接口上报行为,关键字段包括 experiment_id、variant、metric_name 和 value,确保跨端语义一致。
自动化显著性判定流程
from statsmodels.stats.power import zt_ind_solve_power
from scipy import stats
def auto_significance(control, treatment, alpha=0.05):
# 计算两组均值、标准差与样本量
n_ctrl, n_treat = len(control), len(treatment)
effect_size = (np.mean(treatment) - np.mean(control)) / np.std(control + treatment)
# 使用Z检验(大样本)估算统计功效
power = zt_ind_solve_power(effect_size=effect_size, nobs1=n_ctrl, alpha=alpha)
p_val = stats.ttest_ind(control, treatment, equal_var=False).pvalue
return {"p_value": round(p_val, 4), "is_significant": p_val < alpha, "power": round(power, 3)}
该函数基于独立双样本 t 检验计算 p 值,并结合 Cohen’s d 效应量与样本量反推统计功效;alpha=0.05 为默认显著性阈值,power > 0.8 视为结果可信。
实时数据采集链路
graph TD
A[客户端埋点] --> B[Kafka实时队列]
B --> C[Flink实时清洗]
C --> D[ClickHouse指标宽表]
D --> E[Python判定服务]
常见指标置信状态参考
| 指标类型 | 最小样本量/组 | 推荐检验方法 | 显著性延迟 |
|---|---|---|---|
| 点击率(CTR) | 1000 | 卡方检验 | ≤15分钟 |
| 平均停留时长 | 500 | Welch’s t-test | ≤30分钟 |
4.4 灰度开关熔断机制与一键回滚SOP在生产环境的压测验证
在真实大促压测中,我们通过注入120%流量冲击核心订单服务,触发熔断阈值后自动降级灰度开关状态。
熔断策略配置示例
# application-prod.yml
resilience4j.circuitbreaker.instances.order-service:
failure-rate-threshold: 60 # 连续失败率超60%即开启熔断
minimum-number-of-calls: 20 # 最小采样请求数
wait-duration-in-open-state: 30s # 熔断保持30秒
automatic-transition-from-open-to-half-open-enabled: true
该配置确保异常突增时5秒内完成状态切换,避免雪崩扩散;minimum-number-of-calls防止冷启动误判,half-open机制支持渐进式恢复验证。
一键回滚执行流程
graph TD
A[压测告警触发] --> B{灰度开关状态检查}
B -->|异常持续>30s| C[自动关闭灰度开关]
B -->|人工确认| D[执行rollback.sh脚本]
D --> E[拉取上一版镜像+回滚ConfigMap]
E --> F[滚动重启Pod,<90s完成]
| 阶段 | 平均耗时 | 验证指标 |
|---|---|---|
| 开关熔断响应 | 4.2s | P99 |
| 镜像回滚 | 78s | 服务可用性 ≥ 99.99% |
| 配置同步 | 2.1s | ConfigMap热更新生效 |
第五章:开源SDK发布与生态共建倡议
发布流程标准化实践
我们于2024年3月正式发布 CloudBridge-SDK v1.2.0,覆盖 Android、iOS、Web(TypeScript)及 Python 四大平台。整个发布流程严格遵循 GitHub Actions 自动化流水线:代码合并至 main 分支后,自动触发单元测试(覆盖率 ≥85%)、静态扫描(SonarQube)、跨平台构建验证,并生成带 SHA256 校验值的归档包。所有版本均同步推送至 Maven Central、npmjs.org、PyPI 与 Cocoapods 官方仓库,确保开发者可通过标准包管理器一键集成。发布清单包含完整 API 变更日志(BREAKING CHANGES 显式标注)、迁移指南(含 v1.1.x → v1.2.0 的补丁脚本),以及各平台最小兼容版本声明(如 iOS ≥13.0、Android minSdkVersion=21)。
社区贡献激励机制
为降低参与门槛,我们设立三级贡献通道:
- 文档类:提交 PR 修正 README 错误、补充中文示例或新增 FAQ 条目,经审核合并后发放 $20 美元 GitCoin 补贴;
- 代码类:修复已标记
good-first-issue的 Bug 或实现enhancement标签功能,奖励 $50–$200 不等; - 生态类:开发并开源适配插件(如 Vue3 Composition API 封装、Flutter Bridge Wrapper),通过 CI 验证后授予“生态共建者”徽章并列入官网致谢名单。截至2024年6月,已有 37 名外部开发者提交有效 PR,其中 12 项被合入主线,包括一个由深圳某 IoT 创业公司贡献的 LoRaWAN 设备配置模块。
生态共建成果可视化
graph LR
A[SDK 核心仓库] --> B[官方插件库]
A --> C[社区镜像站]
B --> D[Vue3 Adapter]
B --> E[React Native Bridge]
C --> F[国内加速 CDN]
C --> G[离线安装包集]
D --> H[已接入 89 家企业项目]
E --> I[下载量 12.4k/月]
多语言 SDK 版本对齐策略
为保障行为一致性,我们采用“单源协议定义”模式:所有平台 SDK 的网络通信协议、错误码体系、加密算法参数均源自统一的 OpenAPI 3.0 规范文件(spec/cloudbridge-core.yaml)。CI 流程中嵌入 openapi-generator-cli 自动校验各语言生成代码是否符合该规范——若 Python SDK 解析响应字段与 TypeScript 定义不一致,构建将立即失败。该机制在 v1.2.0 中拦截了 3 次潜在协议漂移风险,避免下游应用出现静默数据截断问题。
开源许可证合规审计
SDK 采用 Apache License 2.0,但依赖项需逐层扫描。我们使用 license-checker --onlyAllow 'Apache-2.0,MIT,ISC' 在每次发布前执行依赖树检查,并生成 THIRD-PARTY-LICENSES.md。当检测到某次构建引入含 GPL-2.0 的间接依赖时,团队立即替换为 MIT 许可的替代库(crypto-js → subtle-crypto-polyfill),并在 CHANGELOG 中明确披露替换原因与安全影响评估结论。
企业级支持通道建设
面向金融、政务类客户,我们提供白名单 SDK 分发服务:客户可申请专属构建流水线,定制禁用遥测上报、启用国密 SM4 加密通道、嵌入私有证书链。该能力已在某省级医保平台落地,其 SDK 构建产物经等保三级渗透测试验证,满足《GB/T 35273-2020》对第三方 SDK 的数据最小化采集要求。
