3. 回放数据采集:请求/响应日志采集、消息队列(Kafka)接入、数据脱敏与存储策略

回放对比的基石是高质量、低延迟的流量采集。本章聚焦于生产环境下的数据采集链路:如何无侵入地捕获请求/响应日志、如何通过 Kafka 实现削峰填谷、以及如何在采集阶段完成合规脱敏与分层存储。

3.1 请求/响应日志采集:从网关到日志管道

风控网关通常基于 OpenResty、Kong、Spring Cloud Gateway 或自研 Netty 网关。采集层需要做到“业务零侵入”与“全量捕获”。

采集维度 典型字段 采集方式 注意事项
请求元数据 traceId、userId、deviceId、IP、User-Agent 网关拦截器/Filter 提取 traceId 必须在入口处生成,透传至下游
请求体 POST JSON、表单、文件上传元信息 Body 缓存 + 异步写入 大 body 需截断(默认 64KB),防止 OOM
响应体 HTTP 状态码、响应 JSON、错误码 响应包装 ResponseWrapper 仅记录非文件流响应,避免二进制污染
时间戳 请求到达时间、响应完成时间、耗时 ms System.nanoTime() 打点 使用 monotonic clock,避免 NTP 跳变
上下文标签 风控版本号、策略命中标签、降级标记 ThreadLocal / 请求上下文注入 标签必须在响应前完成赋值
采集原则: 日志采集必须放在网关过滤器的最后一个执行位(Post Filter),确保所有风控标签、降级标记都已写入上下文。不要在业务 Controller 中采集,避免漏采。

3.2 消息队列(Kafka)接入:高吞吐削峰

生产环境网关 QPS 可达数万至数十万,直接写入数据库或 Elasticsearch 会导致写入瓶颈。Kafka 作为日志总线,承担“缓冲 + 解耦”的核心角色。

3.2.1 架构位置

Kafka 日志采集架构 风控网关实例 风控网关实例 风控网关实例 Kafka 集群 topic: risk-traffic-raw partitions: 12 日志清洗 Worker 回放对比服务 离线归档任务

3.2.2 生产者配置(网关侧)

# 网关 logback-spring.xml 配置 Kafka Appender
<appender name="KAFKA" class="com.github.danielwegener.logback.kafka.KafkaAppender">
    <encoder>
        <pattern>%msg%n</pattern>
    </encoder>
    <topic>risk-traffic-raw</topic>
    <keyingStrategy>org.apache.kafka.clients.producer.internals.DefaultPartitioner</keyingStrategy>
    <deliveryStrategy>async</deliveryStrategy>
    <producerConfig>
        <key>bootstrap.servers</key>
        <value>kafka01:9092,kafka02:9092,kafka03:9092</value>
    </producerConfig>
    <producerConfig>
        <key>acks</key>
        <value>1</value>  <!-- 网关日志允许丢失少量,选 acks=1 提升吞吐 -->
    </producerConfig>
    <producerConfig>
        <key>compression.type</key>
        <value>snappy</value>
    </producerConfig>
    <producerConfig>
        <key>max.request.size</key>
        <value>1048576</value>  <!-- 1MB -->
    </producerConfig>
</appender>
关键参数说明:
  • acks=1:只要 Leader 确认即返回,适合日志场景;不要用 acks=all,会大幅增加网关延迟。
  • compression.type=snappy:CPU 开销低,压缩比约 3~5x,减少网络带宽。
  • max.request.size=1MB:防止超大 body 导致 Kafka 报错,超限 body 应截断或丢弃。

3.2.3 消费者配置(回放服务侧)

spring:
  kafka:
    consumer:
      bootstrap-servers: kafka01:9092,kafka02:9092,kafka03:9092
      group-id: risk-replay-consumer
      auto-offset-reset: earliest
      enable-auto-commit: false
      max-poll-records: 500
      fetch-max-bytes: 52428800  # 50MB
      properties:
        isolation.level: read_committed
    listener:
      type: batch
      concurrency: 6  # 与分区数一致
消费策略: 使用 Batch 监听 + 手动 commit。每批 500 条,处理完成后批量写入回放存储。如果某批处理失败,不 commit,等待重试或死信队列。避免单条 ack 带来的性能开销。

3.3 数据脱敏与存储策略

回放数据包含用户手机号、身份证、银行卡等敏感字段。在采集阶段必须完成脱敏,避免明文落入存储层。

3.3.1 脱敏规则

敏感字段 脱敏方式 示例(脱敏前 → 脱敏后) 备注
手机号 保留前3后4,中间掩码 13812345678 → 138****5678 长度不变,便于索引
身份证号 保留前6后4,中间掩码 110101199001011234 → 110101****1234 保留出生地编码
银行卡号 保留前6后4,中间掩码 6222021234567890 → 622202****7890 保留发卡行标识
姓名 保留姓氏,名字掩码 张三丰 → 张** 二字姓名保留首字
邮箱 @前保留首字符,其余掩码 test@example.com → t***@example.com 保留域名
密码/Token 直接丢弃 — 回放不需要密码

3.3.2 脱敏执行时机

脱敏执行链路 网关原始日志 脱敏过滤器 Kafka 生产 存储(脱敏后) 脱敏必须在网关内完成,Kafka 和存储层只接收脱敏后的数据
最佳实践: 在网关 Filter 中注册一个 DesensitizationFilter,在日志序列化之前遍历 JSON 字段,匹配敏感 key 后执行掩码。使用 JSON Path 或正则匹配,避免反射性能开销。

3.3.3 存储策略:分层与生命周期

存储层 数据内容 保留周期 存储引擎 索引策略
热存储 最近 7 天全量回放日志 7 天 Elasticsearch 按 traceId、userId、时间范围建索引
温存储 7~30 天聚合回放日志 30 天 ClickHouse 按天分区,按 userId 分片
冷存储 30 天以上归档 180 天或按合规要求 HDFS / 对象存储 S3 按年月分区,Parquet 列存

3.3.4 存储写入代码示例(ES 批量写入)

// 使用 Spring Data Elasticsearch 批量写入
@Autowired
private ElasticsearchRestTemplate esTemplate;

public void batchSaveReplayLogs(List<ReplayLog> logs) {
    List<IndexQuery> queries = logs.stream()
        .map(log -> new IndexQueryBuilder()
            .withId(log.getTraceId())
            .withObject(log)
            .build())
        .collect(Collectors.toList());

    esTemplate.bulkIndex(queries, IndexCoordinates.of("risk-replay-logs"));
}
存储避坑:
  • 不要使用 _update 或 upsert,回放日志只追加不修改。
  • ES 索引设置 number_of_shards=3,number_of_replicas=1,避免过多分片导致写入变慢。
  • ClickHouse 冷数据使用 TTL 自动迁移,减少维护成本。

3.4 本章小结

  • 采集层:网关 Filter 全量捕获请求/响应,异步写入 Kafka,避免阻塞业务线程。
  • 消息队列:Kafka 作为日志总线,生产者 acks=1 + snappy 压缩,消费者 batch 拉取 + 手动 commit。
  • 脱敏:在网关内完成,手机号/身份证/银行卡按规则掩码,密码直接丢弃。
  • 存储:热 ES(7天)、温 ClickHouse(30天)、冷 HDFS/S3(180天),分层降低成本。
下一阶段预告: 第 4 章将讲解回放数据标准化——如何将采集到的异构日志转换为统一的回放事件模型,为对比引擎提供干净的输入。