电商数仓项目----笔记三(用户行为数据同步)

在前面的笔记一和笔记二中,我们已经分别将用户行为数据和业务数据采集到kafka中了:

在实时数仓中,由于Flink会从kafka中读取数据,也无需我们再同步数据了,因此同步数据是我们离线数仓的事。

离线数仓同步数据

        对于用户行为数据,由Flume从Kafka直接同步到HDFS,没错,又来一个Flume...... 按照规划,该Flume需将Kafka中topic_log的数据发往HDFS。并且对每天产生的用户行为日志进行区分,将不同天的数据发往HDFS不同天的路径。这里我们用天作为粒度区分。此处的Flume我们选择KafkaSource、FileChannel、HDFSSink (这里也是,关于Source,Channel和Sink专门写一篇文章详细说)。

这里Flume的配置文件就不放全了,但有几点需要注意:

a1.sinks.k1.hdfs.rollInterval = 10
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0

        如果使用官方默认的这三个参数配置写入HDFS后会产生小文件,默认情况下MR会对每个小文件启用一个Map任务计算,非常影响计算性能。同时也影响磁盘寻址时间。基于以上hdfs.rollInterval=3600,hdfs.rollSize=134217728,hdfs.rollCount =0几个参数综合作用,使得文件在达到128M时会滚动生成新文件,文件创建超3600秒时会滚动生成新文件,这样既减少了小文件的可能,又不会因为新的文件迟迟不来而浪费时间,属于是折中的办法。

数据漂移

       在上游flume配置中,我们设置parseAsEvent=false;意思是不以flume event方式来进行存储,所以在上游kafkachannel写入kafka的数据只有body,没有header。那么现在下游flume再从kafka读数据,它也不会把上游的header拿过来,而是自己封装一个header,发送到hdfsink。

        好了,那么既然header是它自己封装的,那么header就没有自己的时间,当我们的数据23:59:59的数据从文件到Kafka再经过Flume采集,又过了几秒钟,变成第二天的时间,结果放入HDFS第二天的数据分区了,那不就乱套了吗?因此需要在source阶段编写日期拦截器,注意这里不能直接将kafkachannel数据写到hdfsink中,因为没有source我们就写不了拦截器。

package com.atguigu.gmall.flume.interceptor;

import com.alibaba.fastjson.JSONObject;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public class TimestampInterceptor implements Interceptor {
    

    @Override
    public void initialize() {

    }

    @Override
    public Event intercept(Event event) {

		//1、获取header和body的数据
        Map<String, String> headers = event.getHeaders();
        String log = new String(event.getBody(), StandardCharsets.UTF_8);

		//2、将body的数据类型转成jsonObject类型(方便获取数据)
        JSONObject jsonObject = JSONObject.parseObject(log);

		//3、header中timestamp时间字段替换成日志生成的时间戳(解决数据漂移问题)
        String ts = jsonObject.getString("ts");
        headers.put("timestamp", ts);

        return event;
    }

    @Override
    public List<Event> intercept(List<Event> list) {
        for (Event event : list) {
            intercept(event);
        }
        return list;
    }

    @Override
    public void close() {

    }

    public static class Builder implements Interceptor.Builder {
        @Override
        public Interceptor build() {
            return new TimestampInterceptor();
        }

        @Override
        public void configure(Context context) {
        }
    }
}

重新打包

将打好的包放入到hadoop104的/opt/module/flume/lib文件夹下面。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值