【数仓_01】用户行为采集平台

  • 1、数仓基础知识
    • 1.1 描述
    • 1.2 需求分析
    • 1.3 选型考虑因素
    • 1.4 项目流程设计
    • 1.5 具体版本
    • 1.6 集群规模
  • 2、用户行为数据生成
    • 2.1 目标数据
    • 2.2 埋点
  • 3、模拟数据
    • 3.1 使用说明
    • 3.2 集群日志生成脚本
  • 4、用户行为数据采集模块
    • 4.1 数据通道
    • 4.2 环境准备
      • 4.2.1 集群所有进程查看脚本
    • 4.3 Hadoop项目经验
      • 4.3.1 项目经验之HDFS存储多目录
      • 4.3 2 项目经验之集群数据均衡
      • 4.3.3 项目经验之支持LZO压缩配置
      • 4.3.4 项目经验之LZO创建索引
      • 4.3.5 项目经验之Hadoop参数调优
    • 4.4 消费Kafka数据Flume
      • 4.4.1 FileChannel和MemoryChannel的区别
      • 4.4.2 消费者flume配置分析
      • 4.4.3 ETL与时间戳拦截器
      • 4.4.4 消费者flume启动停止脚本
      • 4.4.5 采集通道启动停止脚本

1、数仓基础知识

1.1 描述

数据仓库是为企业决策提供数据支撑的,进行存储、分析与计算。

数据仓库的数据来源有:业务数据、用户行为数据、爬虫数据等。

  • 业务数据:就是各行业在处理事务过程中产生的数据。比如用户在电商网站中登录、下单、支付等过程中,需要和网站后台数据库进行增删改查交互,产生的数据就是业务数据。业务数据通常存储在MySQL、Oracle等数据库中。
  • 用户行为数据:用户在使用产品过程中,通过埋点收集与客户端产品交互过程中产生的数据,并发往日志服务器进行保存。比如页面浏览、点击、停留、评论、点赞、收藏等。用户行为数据通常存储在日志文件中。
  • 爬虫数据:通常是通过技术手段获取其他公司网站的数据。

【数仓_01】用户行为采集平台_第1张图片

1.2 需求分析

(1)项目需求

1、用户行为数据采集平台搭建
2、业务数据采集平台搭建
3、数据仓库维度建模
4、分析,设备、会员、商品、地区、活动等电商核心主题,统计的报表指标近100个。
5、采用即席查询工具,随时进行指标分析
6、对集群性能进行监控,发生异常需要报警。【监控每一个框架的进程的好坏】
7、元数据管理
8、质量监控【监控的是数据的异常变化,例如能够实时监控今天的指标和昨天的指标的差异变化】
9、权限管理

需要考虑的问题:
1、项目技术如何选型?
2、框架版本如何选型(Apache、CDH、HDP)
3、服务器使用物理机还是云主机?
4、如何确定集群规模?(假设每台服务器8T硬盘)

1.3 选型考虑因素

技术选型主要考虑因素:数据量大小、业务需求、行业内经验、技术成熟度、开发维护成本、总成本预算

  • 数据采集传输: Flume,Kafka,Sqoop ,Logstash,DataX,
  • 数据存储:MySQL,HDFS,HBase,Redis,MongoDB>
  • 数据计算:Hive,Tez,Spark,Flink,Storm
  • 数据查询:Presto,Kylin ,Impala,Druid,ClickHouse,Doris
  • 数据可视化: Echarts,Superset,QuickBI,DataV
  • 任务调度:Azkaban,Oozie,DolphinScheduler,Airflow
  • 集群监控:Zabbix,Prometheus
  • 元数据管理: Atlas

1.4 项目流程设计

数仓流程架构图:

【数仓_01】用户行为采集平台_第2张图片

框架发行版本选择:

  • 如何选择Apache/CDHHDP版本?【免费】
    (1) Apache:运维麻烦,组件间兼容性需要自己调研。(一般大厂使用,技术实力雄厚,有专业的运维人员)(建议使用)
    (2)CDH:国内使用最多的版本,但CM不开源,今年开始收费,一个节点1万美金/年。
    (3)HDP:开源,可以进行二次开发,但是没有CDH稳定,国内使用较少

  • 云服务选择【收费】
    (1)阿里云的EMR、MaxCompute、DataWorks
    (2)亚马逊云EMR
    (3)腾讯云ENMR
    (4)华为云EMR

1.5 具体版本

  • apache版本
    【数仓_01】用户行为采集平台_第3张图片
    注意事项:框架选型尽量不要选择最新的框架,选择最新框架半年前左右的稳定版。

服务器选择:

  • 服务器选择物理机还是云主机?
    1)物理机:
    以128G内存,20核物理CPU,40线程,8THDD和2TSSD硬盘,戴尔品牌
    单台报价4W出头。一般物理机寿命5年左右。
    需要有专业的运维人员,平均一个月1万。电费也是不少的开销。
    2)云主机:
    云主机:以阿里云为例,差不多相同配置,每年5W。很多运维工作都由阿里云完成,运维相对较轻松
  • 企业选择
    金融有钱公司和阿里没有直接冲突的公司选择阿里云
    中小公司、为了融资上市,选择阿里云,拉倒融资后买物理机。有长期打算,资金比较足,选择物理机。

1.6 集群规模

【数仓_01】用户行为采集平台_第4张图片
集群资源规划设计:

在企业中通常会搭建一套生产集群和一套测试集群。生产集群运行生产任务,测试集群用于上线前代码编写和测试。

  • 生产集群
    (1)消耗内存的分开
    (2)数据传输数据比较紧密的放在一起(Kafka 、Zookeeper)
    (3)客户端尽量放在一到两台服务器上,方便外部访问
    (4)有依赖关系的尽量放到同一台服务器(例如:Hive和mysql)

2、用户行为数据生成

2.1 目标数据

我们要收集和分析的数据主要包括页面数据、事件数据、曝光数据、启动数据和错误数据。

1、页面浏览记录
页面浏览记录,记录的是访客对页面的浏览行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息及页面信息等。

【数仓_01】用户行为采集平台_第5张图片
2、动作记录
动作记录,记录的是用户的业务操作行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息 及动作目标对象信息等。
【数仓_01】用户行为采集平台_第6张图片

3、曝光记录
曝光记录,记录的是曝光行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息及曝光对象信息等。
【数仓_01】用户行为采集平台_第7张图片

4、启动记录
启动记录,记录的是用户启动应用的行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息、启动类型及开屏广告信息等。

【数仓_01】用户行为采集平台_第8张图片

5、错误记录
启动记录,记录的是用户在使用应用过程中的报错行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息、以及可能与报错相关的页面信息、动作信息、曝光信息和动作信息。

2.2 埋点

用户行为日志的内容,主要包括用户的各项行为信息以及行为所处的环境信息。收集这些信息的主要目的是优化产品和为各项分析统计指标提供数据支撑。收集这些信息的手段通常为埋点

目前主流的埋点方式,有代码埋点(前端/后端)、可视化埋点、全埋点等。

  • 代码埋点是通过调用埋点SDK函数,在需要埋点的业务逻辑功能位置调用接口,上报埋点数据。例如,我们对页面中的某个按钮埋点后,当这个按钮被点击时,可以在这个按钮对应的 OnClick 函数里面调用SDK提供的数据发送接口,来发送数据。

  • 可视化埋点只需要研发人员集成采集 SDK,不需要写埋点代码,业务人员就可以通过访问分析平台的“圈选”功能,来“圈”出需要对用户行为进行捕捉的控件,并对该事件进行命名。圈选完毕后,这些配置会同步到各个用户的终端上,由采集 SDK 按照圈选的配置自动进行用户行为数据的采集和发送。

  • 全埋点是通过在产品中嵌入SDK,前端自动采集页面上的全部用户行为事件,上报埋点数据,相当于做了一个统一的埋点。然后再通过界面配置哪些数据需要在系统里面进行分析。

埋点数据上报时机:本次项目采用方式一埋点。

  • 埋点数据上报时机包括两种方式。
    方式一,在离开该页面时,上传在这个页面产生的所有数据(页面、事件、曝光、错误等)。优点,批处理,减少了服务器接收数据压力。缺点,不是特别及时。
    方式二,每个事件、动作、错误等,产生后,立即发送。优点,响应及时。缺点,对服务器接收数据压力比较大。

埋点数据日志结构:

我们的日志结构大致可分为两类,一是普通页面埋点日志,二是启动日志。

  • 普通页面日志结构的每条日志包含了,当前页面的页面信息,所有事件(动作)、所有曝光信息以及错误信息。除此之外,还包含了一系列公共信息,包括设备信息,地理位置,应用信息等,即下边的common字段。

普通页面埋点日志格式如下:

{
	"common": {                     -- 环境信息
		"ar": "230000",             -- 地区编码
		"ba": "iPhone",             -- 手机品牌
		"ch": "Appstore",           -- 渠道
		"is_new": "1",              -- 是否首日使用,首次使用的当日,该字段值为1,过了24:00,该字段置为0。
		"md": "iPhone 8",           -- 手机型号
		"mid": "YXfhjAYH6As2z9Iq",  -- 设备id
	"os": "iOS 13.2.9",         -- 操作系统
		"uid": "485",               -- 会员id
		"vc": "v2.1.134"            -- app版本号
	},
	"actions": [{                   -- 动作(事件)
		"action_id": "favor_add",   -- 动作id
		"item": "3",                -- 目标id
		"item_type": "sku_id",      -- 目标类型
		"ts": 1585744376605         -- 动作时间戳
	    }
	],
	"displays": [{                  -- 曝光
			"displayType": "query", -- 曝光类型
			"item": "3",            -- 曝光对象id
			"item_type": "sku_id",  -- 曝光对象类型
			"order": 1,             -- 出现顺序
			"pos_id": 2             -- 曝光位置
		},
		{
			"displayType": "promotion",
			"item": "6",
			"item_type": "sku_id",
			"order": 2,
			"pos_id": 1
		},
		{
			"displayType": "promotion",
			"item": "9",
			"item_type": "sku_id",
			"order": 3,
			"pos_id": 3
		},
		{
			"displayType": "recommend",
			"item": "6",
			"item_type": "sku_id",
			"order": 4,
			"pos_id": 2
		},
		{
			"displayType": "query ",
			"item": "6",
			"item_type": "sku_id",
			"order": 5,
			"pos_id": 1
		}
	],
	"page": {                          -- 页面信息
		"during_time": 7648,           -- 持续时间毫秒
		"item": "3", 	               -- 目标id
		"item_type": "sku_id",         -- 目标类型
		"last_page_id": "login",       -- 上页类型
		"page_id": "good_detail",      -- 页面ID
		"sourceType": "promotion"      -- 来源类型
	},                   
	"err": {                           --错误
			"error_code": "1234",          --错误码
			"msg": "***********"           --错误信息
		},                                 
		"ts": 1585744374423                --跳入时间戳
	}

启动页面埋点日志格式如下:

{
  "common": {
    "ar": "370000",
    "ba": "Honor",
    "ch": "wandoujia",
    "is_new": "1",
    "md": "Honor 20s",
    "mid": "eQF5boERMJFOujcp",
    "os": "Android 11.0",
    "uid": "76",
    "vc": "v2.1.134"
  },
  "start": {   
    "entry": "icon",         --icon手机图标  notice 通知   install 安装后启动
    "loading_time": 18803,  --启动加载时间
    "open_ad_id": 7,        --广告页ID
    "open_ad_ms": 3449,    -- 广告总共播放时间
    "open_ad_skip_ms": 1989   --  用户跳过广告时点
  },
"err":{                     --错误
"error_code": "1234",      --错误码
    "msg": "***********"       --错误信息
},
  "ts": 1585744304000
}

3、模拟数据

  • 可以通过前端埋点,之后点击前端页面,生成日志数据,之后将日志数据发送到日志服务器。
  • 也可以自己写一个java程序,直接快速产生大量日志,并将其发送到日志服务器。

【数仓_01】用户行为采集平台_第9张图片

3.1 使用说明

1)将application.yml、gmall2020-mock-log-2021-10-10.jar、path.json、logback.xml上传到hadoop102的/home/wenxin/module/applog目录下

(1)创建applog路径

[root@hadoop102 module]$ mkdir /home/wenxin/module/applog

(2)上传文件到/opt/module/applog目录
【数仓_01】用户行为采集平台_第10张图片

3)生成日志

(1)进入到/opt/module/applog路径,执行以下命令

[root@hadoop102 applog]$ java -jar gmall2020-mock-log-2021-10-10.jar

(2)在/opt/module/applog/log目录下查看生成日志

[root@hadoop102 log]$ ll

【数仓_01】用户行为采集平台_第11张图片

3.2 集群日志生成脚本

在hadoop102的/home/atguigu目录下创建bin目录,这样脚本可以在服务器的任何目录执行。

【数仓_01】用户行为采集平台_第12张图片

[root@hadoop102 ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/atguigu/.local/bin:/home/atguigu/bin
(1)在/home/atguigu/bin目录下创建脚本lg.sh
[root@hadoop102 bin]$ vim lg.sh
(2)在脚本中编写如下内容
#!/bin/bash
for i in hadoop102 hadoop103; do
    echo "========== $i =========="
    ssh $i "cd /home/wenxin/module/applog/; java -jar gmall2020-mock-log-2021-10-10.jar >/dev/null 2>&1 &"
done 

【数仓_01】用户行为采集平台_第13张图片

4、用户行为数据采集模块

4.1 数据通道

【数仓_01】用户行为采集平台_第14张图片

4.2 环境准备

4.2.1 集群所有进程查看脚本

1)在/home/atguigu/bin目录下创建脚本xcall

[root@hadoop102 bin]$ vim xcall

2)在脚本中编写如下内容

#! /bin/bash
 
for i in hadoop102 hadoop103 hadoop104
do
    echo --------- $i ----------
    ssh $i "$*"
done

3)修改脚本执行权限

[root@hadoop102 bin]$ chmod 777 xcall

4)启动脚本

[root@hadoop102 bin]$ xcall.sh jps

【数仓_01】用户行为采集平台_第15张图片

4.3 Hadoop项目经验

4.3.1 项目经验之HDFS存储多目录

①生产环境服务器磁盘情况
【数仓_01】用户行为采集平台_第16张图片
②在hdfs-site.xml文件中配置多目录,注意新挂载磁盘的访问权限问题。

HDFS的DataNode节点保存数据的路径由dfs.datanode.data.dir参数决定,其默认值为file://${hadoop.tmp.dir}/dfs/data,若服务器有多个磁盘,必须对该参数进行修改。如服务器磁盘如上图所示,则该参数应修改为如下的值。

<property>
    <name>dfs.datanode.data.dir</name>
    <value>file:///dfs/data1,file:///hd2/dfs/data2,file:///hd3/dfs/data3,file:///hd4/dfs/data4
</property>

注意:每台服务器挂载的磁盘不一样,所以每个节点的多目录配置可以不一致。单独配置即可。因为有可能hadoop102有4块硬盘,但是hadoop103只有两块硬盘。

4.3 2 项目经验之集群数据均衡

①节点间数据均衡

开启数据均衡命令:

start-balancer.sh -threshold 10

对于参数10,代表的是集群中各个节点的磁盘空间利用率相差不超过10%,可根据实际情况进行调整。

停止数据均衡命令:

stop-balancer.sh

注意:HDFS需要启动单独的Rebalance Server来执行Rebalance操作,所以尽量不要在NameNode上执行start-balancer.sh,而是找一台比较空闲的机器。

②磁盘间数据均衡

生成均衡计划 但是其实虚拟机是只有一块硬盘的,不会生成计划。

hdfs diskbalancer -plan hadoop103

执行均衡计划

hdfs diskbalancer -execute hadoop103.plan.json

查看当前均衡任务的执行情况

hdfs diskbalancer -query hadoop103

取消均衡任务

hdfs diskbalancer -cancel hadoop103.plan.json

4.3.3 项目经验之支持LZO压缩配置

这部分的详情请参考这篇博客:Hadoop支持LZO压缩配置详细(附文件)

接下来测试LZO压缩是否好用:

  • 在mapReduce当中有三个地方可以配置压缩,分别是:map输入端、map输出端以及reduce输出端。我们这里在reudce输出端配置压缩。

创建一个路径:

[root@hadoop102 hadoop-3.1.3]# hadoop fs -mkdir /input

【数仓_01】用户行为采集平台_第17张图片
上传一个文件夹到当前目录:

[root@hadoop102 hadoop-3.1.3]# hadoop fs -put README.txt  /input

执行wordCount:

[root@hadoop102 hadoop-3.1.3]# hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -Dmapreduce.output.fileoutputformat.compress=true -Dmapreduce.output.fileoutputformat.compress.codec-com.hadoop.compression.lzo.LzopCodec /input /output

4.3.4 项目经验之LZO创建索引

(1)将bigtable.lzo(200M)上传到集群的根目录

[root@hadoop102 module]$ hadoop fs -mkdir /input
[root@hadoop102 module]$ hadoop fs -put bigtable.lzo /input

(2)执行wordcount程序

[root@hadoop102 hadoop-3.1.3]# hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -Dmapreduce.job.inputformat.class=com.hadoop.mapreduce.LzoTextInputFormat /input /output1
  • 此时还不支持切片,需要创建索引

(3)对上传的LZO文件创建索引

[root@hadoop102 hadoop-3.1.3]# hadoop jar /home/wenxin/module/hadoop-3.1.3/share/

(4)再次执行wordcount程序

[root@hadoop102 hadoop-3.1.3]# hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -Dmapreduce.job.inputformat.class=com.hadoop.mapreduce.LzoTextInputFormat /input /output1

4.3.5 项目经验之Hadoop参数调优

(1)HDFS参数调优hdfs-site.xml

The number of Namenode RPC server threads that listen to requests from clients. If dfs.namenode.servicerpc-address is not configured then Namenode RPC server threads listen to requests from all nodes.
NameNode有一个工作线程池,用来处理不同DataNode的并发心跳以及客户端并发的元数据操作。
对于大集群或者有大量客户端的集群来说,通常需要增大参数dfs.namenode.handler.count的默认值10。

<property>
    <name>dfs.namenode.handler.count</name>
    <value>10</value>
</property>

【数仓_01】用户行为采集平台_第18张图片

在这里插入图片描述

[root@hadoop102 ~]$ python
Python 2.7.5 (default, Apr 11 2018, 07:36:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> print int(20*math.log(8))
41
>>> quit()

【数仓_01】用户行为采集平台_第19张图片

  • 因此如果3台服务器配置21,8台服务器配置41。

(2)YARN参数调优yarn-site.xml【京东面试题】

情景描述:总共7台机器,每天几亿条数据,数据源->Flume->Kafka->HDFS->Hive

面临问题:数据统计主要用HiveSQL,没有数据倾斜,小文件已经做了合并处理,开启的JVM重用,而且IO没有阻塞,内存用了不到50%。但是还是跑的非常慢,而且数据量洪峰过来时,整个集群都会宕掉。基于这种情况有没有优化方案。这是一个典型的集群资源没有利用到位,

解决办法:

  • NodeManager内存和服务器实际内存配置尽量接近,而生产环境下,一台服务器集群的内存一般有128g ,但是NodeManager 默认内存8G,不修改该参数最多只能用8G内存,资源浪费。NodeManager使用的CPU核数和服务器CPU核数尽量接近。这里可以设置NodeManager为100G。不调到128G是因为这台服务器上还有其他服务在运行,其他服务在运行的时候也需要对应的内存。
  • 同时,NodeManager默认的CPU核数是8个CPU核数,而生产环境下服务器是20核。因此对于NodeManager的CPU核数也要提高。

yarn. nodemanager.resource.memory-mb NodeManager 使用内存数
yarn.nodemanager.resource.cpu-vcores NodeManager 使用CPU核数

4.4 消费Kafka数据Flume

4.4.1 FileChannel和MemoryChannel的区别

  • FileChannel存储在磁盘当中,可靠性较高,但效率较低。
    【数仓_01】用户行为采集平台_第20张图片

  • MemoryChannel存储在内存当中,可靠性较低,但效率较高。

在没有KafkaChannel的情况下:
1、如果是金融类公司、对钱要求非常准确的公司通常会选择FileChannel,保证数据的可靠性。
2、如果传输的是普通的日志信息,则通常选择MemoryChannel,比如一些公司每天丢100-200万条是很正常的。

4.4.2 消费者flume配置分析

  • 之前设置了一个ETL拦截器,是为了判断JSON数据格式是否完整,而下面这个时间戳拦截器,是为了解决零点漂移问题。

【数仓_01】用户行为采集平台_第21张图片

【数仓_01】用户行为采集平台_第22张图片

#定义组件
a1.sources=r1
a1.channels=c1
a1.sinks=k1
#配置source
a1.sources.r1.type=org.apache.flume.source.kafka.KafkaSource
a1.sources.r1.kafka.bootstrap.servers=hadoop102:9092,hadoop103:9092,hadoop104:9092
a1.sources.r1.kafka.topics=topic_log
a1.sources.r1.batchSize=5000
a1.sources.r1.batchDurationMillis=2000
#时间戳拦截器
a1.sources.r1.interceptors=i1
a1.sources.r1.interceptors.i1.type=com.wenxin.gmall.flume.interceptor.TimeStampIntercepter$Builder
#配置channel
a1.channels.c1.type=file
a1.channels.c1.checkpointDir=/home/wenxin/module/flume/checkpoint/behavior1
a1.channels.c1.dataDirs=/home/wenxin/module/flume/data/behavior1/

#配置sink
a1.sinks.k1.type=hdfs
a1.sinks.k1.hdfs.path=/origin_data/gmall/log/topic_log/%Y-%m-%d
a1.sinks.k1.hdfs.filePrefix=log-
a1.sinks.k1.hdfs.round=false

#控制输出文件是原生文件
a1.sinks.k1.hdfs.fileType=CompressedStream
a1.sinks.k1khdfs.codeC=lzop

#拼接组件
a1.sources.r1.channels=c1
a1.sinks.k1.channel=c1

【数仓_01】用户行为采集平台_第23张图片

4.4.3 ETL与时间戳拦截器

【数仓_01】用户行为采集平台_第24张图片

package com.wenxin.gmall.flume.interceptor;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;


import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;

public class ETLInterceptor implements Interceptor {

    @Override
    public void initialize() {

    }

    @Override
    public Event intercept(Event event) {

        //1、获取body当中的数据并转成字符串
        byte[] body = event.getBody();
        String log = new String(body, StandardCharsets.UTF_8);
        //2、判断字符串是否是一个合法的json,是:返回当前event;不是:返回null
        if (JSONUtil.isJSONValidate(log)) {
            return event;
        } else {
            return null;
        }
    }

    @Override
    public List<Event> intercept(List<Event> list) {

        Iterator<Event> iterator = list.iterator();

        while (iterator.hasNext()){
            Event next = iterator.next();
            if(intercept(next)==null){
                iterator.remove();
            }
        }

        return list;
    }

    public static class Builder implements Interceptor.Builder{

        @Override
        public Interceptor build() {
            return new ETLInterceptor();
        }
        @Override
        public void configure(Context context) {

        }

    }

    @Override
    public void close() {

    }
}
package com.wenxin.gmall.flume.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONException;

public class JSONUtil {
    /*
     * 通过异常判断是否是json字符串
     * 是:返回true  不是:返回false
     * */

    public static boolean isJSONValidate(String log){
        try {
            JSONObject.parseObject(log);
            return true;
        }catch (JSONException e){
            return false;
        }
    }
}
package com.wenxin.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;

/**
 * @author Susie-Wen
 * @version 1.0
 * @description:
 * @date 2023/12/22 10:27
 */
public class TimeStampIntercepter implements Interceptor {

    @Override
    public void initialize() {

    }

    @Override
    public Event intercept(Event event) {
        //将日志拦下来,取出header里面的key,取出body里面的对应的日志时间,将ts的值赋值给header的key timestamp

        //1 获取header头
        Map<String,String> headers=event.getHeaders();

        //2 获取body中的ts
        byte[] body=event.getBody();
        String log =new String(body, StandardCharsets.UTF_8);
        JSONObject jsonObject = JSONObject.parseObject(log);
        String ts = jsonObject.getString("ts");

        //3 将ts赋值给timestamp
        headers.put("timestamp",ts);
        return null;
    }

    @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 TimeStampIntercepter();
        }

        @Override
        public void configure(Context context) {

        }
    }
}

【数仓_01】用户行为采集平台_第25张图片

打包之后将其上传到hadoop104上

【数仓_01】用户行为采集平台_第26张图片
在这里插入图片描述
这个文件即包含之前写的ETL拦截器,也包含时间戳拦截器

4.4.4 消费者flume启动停止脚本

#! /bin/bash
case $1 in
"start"){
        for i in hadoop104
        do
                echo "----- 启动 $i 消费flume-----"
                ssh $i "nohup /home/wenxin/module/flume/bin/flume-ng agent --conf-file /home/wenxin/module/flume/conf/kafka-flume-
hdfs.conf --name a1 -Dflume.root.logger=INFO,LOGFILE >/home/wenxin/module/flume/log2.txt 2>&1 &"
        done
};;
"stop"){
        for i in hadoop104
        do
                echo "-----停止$i消费flume-----"
                ssh $i "ps -ef | grep kafka-flume-hdfs | grep -v grep |awk '{print \$2}' | xargs -n1 kill"
        done
};;
esac

【数仓_01】用户行为采集平台_第27张图片

4.4.5 采集通道启动停止脚本

#!/bin/bash
case $1 in
"start")
		echo "----- 启动集群 -----"
		zk.sh start
		hdp.sh start
		kf.sh start
		f1.sh start
		f2.sh start
;;
"stop")
		echo "----- 停止集群 -----"
		f2.sh stop
		f1.sh stop
		kf.sh stop
		hdp.sh stop
		zk.sh stop
;;
esac

【数仓_01】用户行为采集平台_第28张图片

[root@hadoop102 ~]$ cd $HADOOP_HOME/etc/hadoop
sbin/start-dfs.sh
sbin/start-yarn.sh

查看使用jps
hive --service metastore &
hive --service hiveserver2 &
beeline
!connect jdbc:hive2://hadoop102:10000
登录mysql:
[root@hadoop102 module]# mysql -uroot -p123456
启动zookeeper:
zookeeper在这个目录下:/home/wenxin/module
启动zookeeper:zk.sh start
停止zookeeper:zk.sh stop
查看zookeeper状态:zk.sh status 【必须要有leader和follower】
查看3台服务器的集群状态:xcall.sh jps
启动kafka:kf.sh start
停止kafka:kf.sh stop
启动flume:f1.sh start
停止flume:f1.sh stop
启动消费flume:f2.sh start
停止消费flume:f2.sh stop
生成日志:lg.sh
启动整个采集集群:cluster start
停止整个采集集群:clustar stop

你可能感兴趣的:(hadoop)