电商数仓5.0 用户行为数据流传递流程以及实现

概要

学完一系列前置知识(hadoop/spark/kafka/zookeeper/maxwell/flume),这周开始着手项目,将知识点串联并实践起来。
这周开一个文章系列 分解尚硅谷 大数据项目 电商数仓5.0版本。
这篇文章将实现一下流程:
在这里插入图片描述

整体架构流程

由于该项目数据是模拟出来的,当我们使用jar包模拟出用户行为数据时,是生成在linux服务器指定路径下的app.*日志文件,但是我们最终想在hdfs文件系统上使用该数据,那么其中就需要使用一些工具将数据传给hdfs。
在这里插入图片描述

从该流程图可以看到,获得日志文件后,需要使用flume1将数据传给kafka集群,然后通过flume2传递给hdfs。
flume内部是由 source channel sink三个组件组成。但是使用flume传递数据存在一个问题,即数据漂移,什么是数据飘移?例如一个日志文件创建时间是2020-06-01 23:59:59,在通过flume1传递到kafka的过程中花费了几秒钟,当flume2从kafka拿到数据时,因为flume里数据单元是event,在event的header里保存的时间戳是数据传进来给source那一时间的,就可能存在误差,比如这里flume2拿到数据的时候生成的时间戳变成了2020-06-02 00:00:02 哪怕偏差只有几秒中 对数据保存的影响是非常大的。
PS:为什么需要时间戳,以及时间戳是如何生成的,是因为如果我们想通过flume传递数据给hdfs,并且hdfs保存数据的path,使用数据创建的时间做文件目录,就需要flume开启时间戳,flume创建时间戳就是当数据从外部传递给上游(source)那一时间。

日志数据–>flume1–>kafka集群

明白了流程和需要注意的点,接下来开始实现!
第一步:实现本地日志数据通过flume1传给Kafka集群 设定topic为:topic_log

# define servelet tools of flume
# 定义 flume1 的组件 这里我们选择 kafkachannel 就可以直接将source的数据传给kafka 不需要再设定sink了
a1.sources = r1
a1.channels = c1

# config source
# 配置source 这里选用的source是taildir类型 可以实现断点续传 / 监控多个本地文件目录
a1.sources.r1.type = TAILDIR
# 如果是监控多个文件目录 可以写为:
# a1.sources.r1.filegroups = f1,f2,f3,...fn
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /usr/local/applog/log/app.*
# a1.sources.r1.filegroups.f2 = /xxx/xxx/xxx/xxx.*
# a1.sources.r1.filegroups.f3 = /xxx/xxx/xxx/xxx.*
# a1.sources.r1.filegroups.fn = /xxx/xxx/xxx/xxx.*
# positionFile 即设定断电续传的文件偏移量的保存文件 
# source能监控目标路径下的文件就是通过这个偏移量文件 每次从里面读取上次保存文件的偏移量,然后从偏移量开始往下读取文件 来判断文件是否有更新
a1.sources.r1.positionFile = /usr/local/flume/taildir_position.json

# config channel
# 配置channel 这里选用kafkachannel直接连接kafka集群 所以需要设定有关Kafka集群的配置
a1.channels.c1.type = org.apache.flume.channel.kafka.KafkaChannel
# kafka集群的host 和 端口号
a1.channels.c1.kafka.bootstrap.servers = hadoop01:9092,hadoop02:9092,hadoop03:9092
# 数据保存在kafka集群的主题
a1.channels.c1.kafka.topic = topic_log
# 这里是设定 传递的数据是否被解析为flume的数据单元event
# 需要设定为false 因为我们需要的数据格式就是生成的日志数据本身的json格式 不需要被解析为event
a1.channels.c1.parseAsFlumeEvent = false

# component
# 连接 flume1各组件 source channel
a1.sources.r1.channels = c1

启动flume然后运行模拟数据的jar包 观察数据是否传递到kafka集群
在这里插入图片描述
Kafka集群成功收到topic数据!

kafka集群–>flume2–>hdfs

当前kafka以及接收到了数据,现在需要使用flume2将kafka数据传递给hdfs,对于flume2,他的source需要匹配kafka,他的sink需要匹配hdfs,所以flume2的配置文件里source选取kafka source,sink选取hdfs sink。

# define servlet
# 配置 flume2 组件 source channel sink
a1.sources = r1
a1.channels = c1
a1.sinks = k1

# config source
# 配置source 这里选取kafkasource 即对接kafka数据
a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource
# 指定kafka集群 host:port
a1.sources.r1.kafka.bootstrap.servers = hadoop01:9092,hadoop02:9092,hadoop03:9092
# Kafka主题
a1.sources.r1.kafka.topics = topic_log
# kafka 消费者组
a1.sources.r1.kafka.consumer.group.id = topic_log
a1.sources.r1.batchSize = 2000
a1.sources.r1.batchDurationMillis = 1000

# 自定义拦截器 因为需要实现时间戳与数据生成的时间对应 而不是和flume接收到数据的时间对应
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = wrz.timestampintercept$Builder

# config channels
# 配置 channel 这里选取 file channel 支持持久化存储 
a1.channels.c1.type = file
# 设定持久化文件路径
a1.channels.c1.checkpointDir = /usr/local/flume/checkpoint/d1
# 设定数据保存路径
a1.channels.c1.dataDirs = /usr/local/flume/data/d1

# config sinks
# 配置 sink 这里选取 hdfs sink
a1.sinks.k1.type = hdfs
# 设定 hdfs sink 在hdfs平台上保存文件的路径
# 这里动态指定文件路径为时间戳 
a1.sinks.k1.hdfs.path = /origin_data/gmail/log/topic_log/%Y-%m-%d
# 设定 生成文件的前缀
a1.sinks.k1.hdfs.filePrefix = log
a1.sinks.k1.hdfs.round = false
# 设定生成文件回滚的一些参数 
# 基于回滚时间范围 和 回滚文件大小
# 即当时间满足 / 文件累计大小满足 即创建新的文件保存数据
a1.sinks.k1.hdfs.rollInterval = 10
a1.sinks.k1.hdfs.rollSize = 134217700
a1.sinks.k1.hdfs.rollCount = 0
#component
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

可能遇到的问题

Exception in thread “main” java.lang.NoSuchMethodError: org.apache.commons.cli.Options.hasShortOption(Ljava/lang/String;)Z
在这里插入图片描述
定位到这个jar包 在flume的lib目录下
在这里插入图片描述
一启动flume2就报错NoSuchMethodError,报错的类是org.apache.commons.cli,说里面Options没有hasShortOption方法,好嘛直接官网搜这个类:
在这里插入图片描述
发现flume2里的jar包是1.5.0版本的,直接升级到最新版本1.8.0,替换一下jar包重新运行,发现报错CommandLine找不到Builder,但是里面明明有bulider:
在这里插入图片描述
佛了,最后使用1.6.0版本jar包替换后成功运行!
在这里插入图片描述
拦截器启动成功,hdfs保存目录名成功变为数据生成的时间戳~
在这里插入图片描述

总结

这个步骤实现下来难度不在于代码,在于不同版本直接的冲突,不匹配是最麻烦的,因为报的错误稀奇古怪,而且搜不到案例,可能别人不选你这个版本就不会有这个错误。PS:写拦截器的时候一开始使用的jdk17,结果我linux里jdk版本是1.8,直接不让运行,我把linux里jdk换成17后报错jvm内存溢出,更麻烦了,然后重新打包换成1.8jdk编译…

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值