大数据-225 离线数仓 会员指标实战:Flume Taildir HDFS ODS/DWD/DWS/ADS 全链路落地

20 阅读9分钟

TL;DR

  • 场景:用启动日志/事件日志在离线数仓统计新增、活跃(DAU/WAU/MAU)、留存。
  • 结论:采集侧用 Flume 1.8+ Taildir 监控日志落 HDFS 分区,数仓分层承接口径与聚合。
  • 产出:一套可复用的 Taildir→HDFS Sink 配置模板 + 指标口径对齐要点 + 常见故障排查清单。

大数据-225 离线数仓 会员指标实战:Flume Taildir HDFS ODS/DWD/DWS/ADS 全链路落地

离线数仓架构图

需求分析

会员数据是后期营销的很重要的数据,网店会专门针对会员进行一系列营销活动,电商会员一般门槛较低,注册网站即可加入,有些电商平台的高级会员具有时效性,需要购买的VIP会员卡或一年内消费达到多少才能成为高级会员。 计算指标 新增会员:每次新增会员数 活跃会员:每日、每周、每月的活跃会员数 会员留存:1、2、3日会员的留存数,1、2、3日的会员留存率

指标口径业务逻辑

会员统计指标详解

会员识别标准

  • 会员定义:以移动设备为唯一识别标准,每台独立设备视为一个会员。具体识别方式:
    • Android系统:通过设备IMEI号(国际移动设备识别码)进行识别,每部Android设备具有唯一的15位IMEI编码
    • iOS系统:通过OpenUDID(开放统一设备标识符)进行识别,这是iOS设备的通用唯一标识符
    • 特殊情况处理:同一用户的多台设备会分别计算为不同会员;设备刷机或恢复出厂设置后仍视为同一会员

活跃会员定义

  • 日活跃会员(DAU):在自然日内(00:00-23:59)至少打开应用一次的独立设备,无论打开次数多少都计为1个活跃会员
    • 示例:某设备在一天内打开应用5次,仍只计为1个DAU
  • 周活跃会员(WAU):在自然周(周一至周日)内至少启动应用一次的独立设备
    • 统计周期:以ISO标准的周计算方式为准
  • 月活跃会员(MAU):在自然月(1日至月末)内至少启动应用一次的独立设备
    • 跨月统计:每月1日重新计算

会员活跃率计算

  • 日活跃率(DAU率):计算公式 = 日活跃会员数 ÷ 总注册会员数 × 100%
    • 应用场景:衡量每日用户参与度
  • 周活跃率(WAU率):计算公式 = 周活跃会员数 ÷ 总注册会员数 × 100%
    • 特点:反映用户的中期粘性
  • 月活跃率(MAU率):计算公式 = 月活跃会员数 ÷ 总注册会员数 × 100%
    • 行业基准:通常MAU率在10-20%为健康水平

新增会员统计

  • 新增会员定义:设备首次安装并启动应用的会员
    • 防重复计算机制:
      • 卸载后重装不计为新会员
      • 换机但登录同一账号不计为新会员
  • 统计维度
    • 日新增:自然日内首次使用的设备数
    • 周新增:自然周内首次使用的设备数
    • 月新增:自然月内首次使用的设备数
  • 数据应用:用于评估渠道推广效果

留存分析

  • 留存会员:在初始时间段(如某日/周/月)新增的会员,在后续时间段仍保持活跃
    • 示例:1月1日新增100个会员,1月8日仍有40个活跃,则这40个为7日留存会员
  • 留存率计算
    • 计算公式 = 留存会员数 ÷ 初始新增会员数 × 100%
    • 常见指标:
      • 次日留存:第一天新增用户在第二天仍活跃的比例
      • 7日留存:第一周新增用户在第二周仍活跃的比例
      • 30日留存:第一个月新增用户在第二个月仍活跃的比例
  • 分析意义:衡量产品粘性和用户忠诚度的重要指标

已知条件是:

  • 明确了需求
  • 输入:启动日志、事件日志
  • 输出:新增会员、活跃会员、留存会员
  • 日志文件:ODS、DWD、DWS、ADS(输出)

下一步做什么? 数据采集:日志文件 到 Flume 到 HDFS 到 ODS

日志数据采集

原始日志数据(一条启动日志)

2020-07-30 14:18:47.339 [main] INFO com.ecommerce.AppStart - {"app_active":{"name":"app_active","json":{"entry":"1","action":"1","error_code":"0"},"time":1596111888529},"attr":{"area":"泰安","uid":"2F10092A9","app_v":"1.1.13","event_type":"common","device_id":"1FB872-9A1009","os_type":"4.7.3","channel":"DK","language":"chinese","brand":"iphone-9"}}

数据采集的流程: 离线数仓 Flume 选择Flume作为采集日志数据的工具:

  • Flume1.6 无论是 Spooling Directory Source、Exec Source均不能很好的满足动态实时收集的需求
  • Flume1.8+提供了一个非常好的Taildir Source,使用该Source可以监控多个目录,对目录中写入的数据进行实时采集。

taildir source

taildir source特点

  • 使用正则表达式匹配目录中的文件名
  • 监控的文件中,一旦有数据写入,Flume就会将信息写入到指定的Sink
  • 高可靠,不会丢失数据
  • 不会对跟踪文件有任何处理,不会重命名也不会删除
  • 不支持Windows,不能读二进制文件,支持按行读取文本文件

tail source配置

  • positionFile:配置检查点文件的路径,检查点文件会以JSON格式保存已经读取文件的位置,解决断点续传的问题
  • filegroups:指定filegroups,可以有多个,以空格分隔(taildir source可以同时监控多个目录中的文件)
  • filegroups.f1:配置每个filegroup的文件绝对路径,文件名可以用正则表达式匹配

HDFS Sink配置

HDFS Sink都会采用滚动生成文件的方式,滚动生成文件的策略有:

  • 基于时间,hdfs.rollInterval 30秒
  • 基于文件大小,hdfs.rollSize 1024字节
  • 基于Event数量,hdfs.rollCount 10个event
  • 基于文件空闲时间,hdfs.idleTimeout 0
  • 0 禁用
  • minBlockReplicase,默认值与HDFS副本数一致。设为1是为了让Flume感知不到HDFS的块复制,此时其他的滚动方式配置(时间间隔、文件大小、events数量)才不会收到影响

Agent配置

我把配置放在了这里:

cd /opt/wzk
cd flume-conf
vim flume-log2hdfs1.conf

配置的内容如下所示:

a1.sources = r1
a1.sinks = k1
a1.channels = c1

# taildir source
a1.sources.r1.type = TAILDIR
a1.sources.r1.positionFile = /opt/wzk/conf/startlog_position.json
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /opt/wzk/logs/start/.*log

# memorychannel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100000
a1.channels.c1.transactionCapacity = 2000

# hdfs sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /user/data/logs/start/%Y-%m-%d/
a1.sinks.k1.hdfs.filePrefix = startlog.
a1.sinks.k1.hdfs.fileType = DataStream
# 配置文件滚动方式(文件大小32M)
a1.sinks.k1.hdfs.rollSize = 33554432
a1.sinks.k1.hdfs.rollCount = 0
a1.sinks.k1.hdfs.rollInterval = 0
a1.sinks.k1.hdfs.idleTimeout = 0
a1.sinks.k1.hdfs.minBlockReplicas = 1
# 向hdfs上刷新的event的个数
a1.sinks.k1.hdfs.batchSize = 1000
# 使用本地时间
a1.sinks.k1.hdfs.useLocalTimeStamp = true

# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

对应的截图如下所示: 离线数仓Flume配置

Flume的优化配置

使用如下的指令,启动Agent进行测试:

flume-ng agent --conf-file /opt/wzk/flume-conf/flume-log2hdfs1.conf -name a1 -Dflum
e.roog.logger=INFO,console

启动后的截图如下所示: 离线数仓 Flume 优化 查看刚才的Flume窗口: 离线数仓 Flume 日志 查看HDFS的内容: 离线数仓 HDFS 存储

错误速查

症状根因定位修复
Taildir 不采集、HDFS 无新文件filegroups 正则没匹配到文件/路径写错Flume 日志搜 TaildirSource、看监控到的文件列表;核对 /opt/wzk/logs/start/.*log 是否命中
改正绝对路径与正则;先用更宽正则验证(如 .*)再收紧
positionFile 不更新/采集断续positionFile 无权限或目录不存在看 positionFile 是否生成 JSON、是否增长;检查 Flume 运行用户权限
/opt/wzk/conf/ 写权限;确保 positionFile 路径可创建
HDFS 写入失败、反复重试HDFS 权限/NameNode 连接/路径不存在Flume 日志搜 hdfs / Permission denied / Failed;HDFS 侧看目标目录权限
创建目录并授权;修正 hdfs.path;确保 HDFS 可达与认证配置一致
文件迟迟不滚动、HDFS 目录空rollSize/rollInterval/rollCount 都被禁用或条件不触发你配置了 rollSize=32M 且 interval/count=0;低流量时难触发
低流量测试加 rollInterval(如 60/300 秒)或调小 rollSize
内存飙升/Channel OOM/吞吐抖动memory channel 容量过大、下游 HDFS 写慢导致堆积观察 channel size、GC、Sink 写入耗时;看是否持续 backlog
降低 capacity;加大 Sink 并发/优化 HDFS;必要时换 file channel 提升可靠性
数据重复/缺失(断点后异常)positionFile 被清空/回滚;日志轮转策略与 Taildir 追踪不一致对比源日志行数与 HDFS 落地行数;检查 positionFile 历史
保持 positionFile 稳定持久;避免频繁删改;日志轮转用追加模式更稳
分区日期不对(按 UTC/时间错位)时间戳来源与 useLocalTimeStamp 不一致对比写入目录日期与本地时间;检查事件时间字段
开启 hdfs.useLocalTimeStamp=true(你已开);若用事件时间分区需改用拦截器/自定义分区策略
HDFS 写入滚动行为异常(看起来不按配置)minBlockReplicas 未设导致受副本/块策略影响Flume 日志搜 minBlockReplicas 相关;检查 HDFS 副本数
hdfs.minBlockReplicas=1(你已设),并确认集群副本/安全模式状态
Agent 启动参数报错/找不到组件-name 应为 -n 或命令被换行截断(示例里 -Dflum 断行)直接看启动报错;检查命令是否被 shell 分行
使用标准启动:flume-ng agent -n a1 -c /opt/wzk/flume-conf -f /opt/wzk/flume-conf/flume-log2hdfs1.conf -Dflume.root.logger=INFO,console 并确保一行执行

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用AI工具指南! AI研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地

💻 Java篇持续更新中(长期更新)

Java-218 RocketMQ Java API 实战:同步/异步 Producer 与 Pull/Push Consumer MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务已完结,Dubbo已完结,MySQL已完结,MongoDB已完结,Neo4j已完结,FastDFS 已完结,OSS已完结,GuavaCache已完结,EVCache已完结,RabbitMQ已完结,RocketMQ正在更新... 深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈! 大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解