电商数仓(用户行为数据采集)

第1章 数据仓库概念

第2章 项目需求及架构设计

2.1 项目需求分析

2.2 项目框架

2.2.1 技术选型

2.2.2 系统数据流程设计

2.2.3 框架版本选型

2.2.4 服务器选型

2.2.5 集群资源规划设计

2)测试集群服务器规划

整体原则

Ø 资源均衡

Ø 有依赖的服务需要在同一个节点,例如Azkanba的Executor调度hive或者sqoop,需要在一个节点

服务名称

子服务

服务器

hadoop102

服务器

hadoop103

服务器

hadoop104

HDFS

NameNode

DataNode

SecondaryNameNode

Yarn

NodeManager

Resourcemanager

Zookeeper

Zookeeper Server

Flume(采集日志)

Flume

Kafka

Kafka

Flume(消费Kafka)

Flume

Hive

Hive

MySQL

MySQL

Sqoop

Sqoop

Presto

Coordinator

Worker

Azkaban

AzkabanWebServer

AzkabanExecutorServer

Kylin

Hbase

HMaster

HRegionServer

Superset

Atlas

Solr

Jar

服务数总计

18

8

8

第3章 数据生成模块

3.1 目标数据

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

3.1.1 页面

页面数据主要记录一个页面的用户访问情况,包括访问时间、停留时间、页面路径等信息。

字段名称

字段描述

page_id

页面id

home("首页"),

category("分类页"),

discovery("发现页"),

top_n("热门排行"),

favor("收藏页"),

search("搜索页"),

good_list("商品列表页"),

good_detail("商品详情"),

good_spec("商品规格"),

comment("评价"),

comment_done("评价完成"),

comment_list("评价列表"),

cart("购物车"),

trade("下单结算"),

payment("支付页面"),

payment_done("支付完成"),

orders_all("全部订单"),

orders_unpaid("订单待支付"),

orders_undelivered("订单待发货"),

orders_unreceipted("订单待收货"),

orders_wait_comment("订单待评价"),

mine("我的"),

activity("活动"),

login("登录"),

register("注册");

last_page_id

上页id

page_item_type

页面对象类型

sku_id("商品skuId"),

keyword("搜索关键词"),

sku_ids("多个商品skuId"),

activity_id("活动id"),

coupon_id("购物券id");

page_item

页面对象id

sourceType

页面来源类型

promotion("商品推广"),

recommend("算法推荐商品"),

query("查询结果商品"),

activity("促销活动");

during_time

停留时间(毫秒)

ts

跳入时间

3.1.2 事件

事件数据主要记录应用内一个具体操作行为,包括操作类型、操作对象、操作对象描述等信息。

0

字段名称

字段描述

action_id

动作id

favor_add("添加收藏"),

favor_canel("取消收藏"),

cart_add("添加购物车"),

cart_remove("删除购物车"),

cart_add_num("增加购物车商品数量"),

cart_minus_num("减少购物车商品数量"),

trade_add_address("增加收货地址"),

get_coupon("领取优惠券");

注:对于下单、支付等业务数据,可从业务数据库获取。

item_type

动作目标类型

sku_id("商品"),

coupon_id("购物券");

item

动作目标id

ts

动作时间

3.1.3 曝光

曝光数据主要记录页面所曝光的内容,包括曝光对象,曝光类型等信息。

字段名称

字段描述

displayType

曝光类型

promotion("商品推广"),

recommend("算法推荐商品"),

query("查询结果商品"),

activity("促销活动");

item_type

曝光对象类型

sku_id("商品skuId"),

activity_id("活动id");

item

曝光对象id

order

曝光顺序

3.1.4 启动

启动数据记录应用的启动信息。

字段名称

字段描述

entry

启动入口

icon("图标"),

notification("通知"),

install("安装后启动");

loading_time

启动加载时间

open_ad_id

开屏广告id

open_ad_ms

广告播放时间

open_ad_skip_ms

用户跳过广告时间

ts

启动时间

3.1.5 错误

错误数据记录应用使用过程中的错误信息,包括错误编号及错误信息。

字段名称

字段描述

error_code

错误码

msg

错误信息

3.2 数据埋点

3.2.1 主流埋点方式(了解)

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

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

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

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

3.2.2 埋点数据日志结构

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

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

1)普通页面埋点日志格式

{ "common": { -- 公共信息 "ar": "230000", -- 地区编码 "ba": "iPhone", -- 手机品牌 "ch": "Appstore", -- 渠道 "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 -- 曝光顺序 }, { "displayType": "promotion", "item": "6", "item_type": "sku_id", "order": 2 }, { "displayType": "promotion", "item": "9", "item_type": "sku_id", "order": 3 }, { "displayType": "recommend", "item": "6", "item_type": "sku_id", "order": 4 }, { "displayType": "query ", "item": "6", "item_type": "sku_id", "order": 5 } ], "page": { -- 页面信息 "during_time": 7648, -- 停留时间(毫秒) "page_item": "3", -- 页面对象id "page_item_type": "sku_id", -- 页面对象类型 "last_page_id": "login", -- 上页id "page_id": "good_detail", -- 页面ID "sourceType": "promotion" -- 页面来源类型 }, "err":{ -- 错误 "error_code": "1234", -- 错误码 "msg": "***********" -- 错误信息 }, "ts": 1585744374423 -- 跳入时间 }

2)启动日志格式

启动日志结构相对简单,主要包含公共信息,启动信息和错误信息。

{ "common": { "ar": "370000", "ba": "Honor", "ch": "wandoujia", "md": "Honor 20s", "mid": "eQF5boERMJFOujcp", "os": "Android 11.0", "uid": "76", "vc": "v2.1.134" }, "start": { "entry": "icon", -- 启动入口 "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.2.3 埋点数据上报时机

埋点数据上报时机包括两种方式。

方式一,在离开该页面时,上传在这个页面发生的所有事情(页面、事件、曝光、错误等)。优点,批处理,减少了服务器接收数据压力。缺点,不是特别及时。

方式二,每个事件、动作、错误等,产生后,立即发送。优点,响应及时。缺点,对服务器接收数据压力比较大

3.3 服务器和JDK准备

3.3.1 服务器准备

安装如下文档配置步骤,分别安装hadoop102、hadoop103、hadoop104三台主机。

尚硅谷大数据技术之hadoop.docx

3.3.2 JDK准备

1)卸载现有JDK(3台节点)

[atguigu@hadoop102 opt]# sudo rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps [atguigu@hadoop103 opt]# sudo rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps [atguigu@hadoop104 opt]# sudo rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps

2)用SecureCRT工具将JDK导入到hadoop102的/opt/software文件夹下面

3) “alt+p”进入sftp模式

4)选择jdk1.8拖入工具

5)在Linux系统下的opt目录中查看软件包是否导入成功

[atguigu@hadoop102 software]# ls /opt/software/

看到如下结果:

jdk-8u212-linux-x64.tar.gz

6)解压JDK到/opt/module目录下

[atguigu@hadoop102 software]# tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/

7)配置JDK环境变量

(1)新建/etc/profile.d/my_env.sh文件

[atguigu@hadoop102 module]# sudo vim /etc/profile.d/my_env.sh

添加如下内容,然后保存(:wq)退出

#JAVA_HOME export JAVA_HOME=/opt/module/jdk1.8.0_212 export PATH=$PATH:$JAVA_HOME/bin

(2)让环境变量生效

[atguigu@hadoop102 software]$ source /etc/profile.d/my_env.sh

8)测试JDK是否安装成功

[atguigu@hadoop102 module]# java -version

如果能看到以下结果、则Java正常安装

java version "1.8.0_212"

9)分发JDK 

[atguigu@hadoop102 module]$ xsync /opt/module/jdk1.8.0_212/

10)分发环境变量配置文件

[atguigu@hadoop102 module]$ sudo /home/atguigu/bin/xsync /etc/profile.d/my_env.sh

11)分别在hadoop103、hadoop104上执行source

[atguigu@hadoop103 module]$ source /etc/profile.d/my_env.sh [atguigu@hadoop104 module]$ source /etc/profile.d/my_env.sh

3.4 模拟数据

3.4.1 使用说明

1)将application.properties、gmall2020-mock-log-2020-04-01.jar、path2.json上传到hadoop102的/opt/module/applog目录下

[atguigu@hadoop102 module]$ mkdir applog

[atguigu@hadoop102 applog]$ ls application.properties gmall2020-mock-log-2020-04-01.jar path2.json

2)配置文件

(1)application.properteis文件

可以根据需求生成对应日期的用户行为日志。

[atguigu@hadoop102 applog]$ vim application.properties

修改如下内容

logging.level.root=info #业务日期 注意:并不是生成日志的日期 mock.date=2020-06-14 #启动次数 mock.startup.count=100 #设备最大值 mock.max.mid=50 #会员最大值 mock.max.uid=500 #商品最大值 mock.max.sku-id=10 #页面平均访问时间 mock.page.during-time-ms=20000 #错误概率 mock.error.rate=3 #日志发送延迟 mock.log.sleep=100 #商品详情来源 用户查询,商品推广,智能推荐, 促销活动 mock.detail.source-type-rate=40:25:15:20

(2)path2.json,该文件用来配置访问路径

根据需求,可以灵活配置用户点击路径。

[ {"path":["home","good_list","good_detail","cart","trade","payment"],"rate":20 }, {"path":["home","good_list","good_detail","login","good_detail","cart","trade","payment"],"rate":50 }, {"path":["home","mine","orders_unpaid","trade","payment"],"rate":10 }, {"path":["home","mine","orders_unpaid","good_detail","good_spec","comment","trade","payment"],"rate":10 }, {"path":["home","mine","orders_unpaid","good_detail","good_spec","comment","home"],"rate":10 }, {"path":["home","mine","orders_undelivered"],"rate":20 }, {"path":["home","mine","orders_unreceipted"],"rate":20 }, {"path":["home","mine","orders_unreceipted","orders_wait_comment"],"rate":20 }, {"path":["home","mine","orders_all","orders_wait_comment"],"rate":20 }, {"path":["home","mine","favor","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","mine","favor","good_detail","favor","mine"],"rate":20 }, {"path":["home","cart","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","cart","login","top_n","good_detail","home"],"rate":20 }, {"path":["home","login","top_n","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","search","good_list","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","search","good_list","good_detail","home"],"rate":20 }, {"path":["home","category","activity","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","category","activity","category","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","category","activity","category","home"],"rate":20 }, {"path":["home","category","home"],"rate":20 }, {"path":["home","discovery","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","discovery","good_detail","good_spec","comment","good_detail","discovery","home"],"rate":20 }, {"path":["home","discovery","home"],"rate":20 }, {"path":["home","activity","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","activity","good_detail","good_spec","comment","good_detail","activity","home"],"rate":20 }, {"path":["home","activity","home"],"rate":20 }, {"path":["home","search","top_n","good_detail","good_spec","comment","trade","payment"],"rate":20 }, {"path":["home","search","top_n","good_detail","good_spec","comment","good_detail","top_n","search"],"rate":20 }, {"path":["home","search","good_list","good_detail","good_spec","comment","good_detail","good_list","search"],"rate":20 }, {"path":["home","search","good_list","good_detail","good_spec","comment","trade","payment"],"rate":20 } ]

(3)日志生成命令

在/opt/module/applog路径下执行日志生成命令。

[atguigu@hadoop102 applog]$ java -jar gmall2020-mock-log-2020-04-01.jar

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

[atguigu@hadoop102 log]$ ll

3.4.2 集群日志生成脚本

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

[atguigu@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

[atguigu@hadoop102 bin]$ vim lg.sh

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

#!/bin/bash for i in hadoop102 hadoop103; do echo "========== $i ==========" ssh $i "cd /opt/module/applog/; java -jar gmall2020-mock-log-2020-04-01.jar >/dev/null 2>&1 &" done

注:

(1)/opt/module/applog/为jar包及配置文件所在路径

(2)/dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。

标准输入0:从键盘获得输入 /proc/self/fd/0

标准输出1:输出到屏幕(即控制台) /proc/self/fd/1

错误输出2:输出到屏幕(即控制台) /proc/self/fd/2

3)修改脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x lg.sh

4)将jar包及配置文件上传至hadoop103的/opt/module/applog/路径

5)启动脚本

[atguigu@hadoop102 module]$ lg.sh

6)分别在hadoop102、hadoop103的/opt/module/applog/log目录上查看生成的数据

[atguigu@hadoop102 logs]$ ls app.2020-06-14.log [atguigu@hadoop103 logs]$ ls app.2020-06-14.log

第4章 数据采集模块

4.1 集群所有进程查看脚本

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

[atguigu@hadoop102 bin]$ vim xcall.sh

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

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

3)修改脚本执行权限

[atguigu@hadoop102 bin]$ chmod 777 xcall.sh

4)启动脚本

[atguigu@hadoop102 bin]$ xcall.sh jps

4.2 Hadoop安装

详见:尚硅谷大数据技术之Hadoop(入门)

0

1)集群规划:

服务器hadoop102

服务器hadoop103

服务器hadoop104

HDFS

NameNode

DataNode

DataNode

DataNode

SecondaryNameNode

Yarn

NodeManager

Resourcemanager

NodeManager

NodeManager

注意:尽量使用离线方式安装

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

1)生产环境服务器磁盘情况

2)在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 </value> </property>

注意:因为每台服务器节点的磁盘情况不同,所以这个配置配完之后,不需要分发

4.2.2 集群数据均衡

1)节点间数据均衡

开启数据均衡命令:

start-balancer.sh -threshold 10

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

停止数据均衡命令:

stop-balancer.sh

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

2)磁盘间数据均衡

(1)生成均衡计划(我们只有一块磁盘,不会生成计划)

hdfs diskbalancer -plan hadoop103

(2)执行均衡计划

hdfs diskbalancer -execute hadoop103.plan.jsonI

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

hdfs diskbalancer -query hadoop103

(4)取消均衡任务

hdfs diskbalancer -cancel hadoop103.plan.json

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

1)hadoop本身并不支持lzo压缩,故需要使用twitter提供的hadoop-lzo开源组件。hadoop-lzo需依赖hadoop和lzo进行编译,编译步骤如下。

hadoop-lzo编译.txt

2)将编译好后的hadoop-lzo-0.4.20.jar 放入hadoop-3.1.3/share/hadoop/common/

[atguigu@hadoop102 common]$ pwd /opt/module/hadoop-3.1.3/share/hadoop/common [atguigu@hadoop102 common]$ ls hadoop-lzo-0.4.20.jar

3)同步hadoop-lzo-0.4.20.jar到hadoop103、hadoop104

[atguigu@hadoop102 common]$ xsync hadoop-lzo-0.4.20.jar

4)core-site.xml增加配置支持LZO压缩

<configuration> <property> <name>io.compression.codecs</name> <value> org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.BZip2Codec, org.apache.hadoop.io.compress.SnappyCodec, com.hadoop.compression.lzo.LzoCodec, com.hadoop.compression.lzo.LzopCodec </value> </property> <property> <name>io.compression.codec.lzo.class</name> <value>com.hadoop.compression.lzo.LzoCodec</value> </property> </configuration>

5)同步core-site.xml到hadoop103、hadoop104

[atguigu@hadoop102 hadoop]$ xsync core-site.xml

6)启动及查看集群

[atguigu@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh [atguigu@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh

4.2.4 项目经验之LZO创建索引

1)创建LZO文件的索引,LZO压缩文件的可切片特性依赖于其索引,故我们需要手动为LZO压缩文件创建索引。若无索引,则LZO文件的切片只有一个。

hadoop jar /path/to/your/hadoop-lzo.jar com.hadoop.compression.lzo.DistributedLzoIndexer big_file.lzo

2)测试

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

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

(2)执行wordcount程序

[atguigu@hadoop102 module]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -Dmapreduce.job.inputformat.class=com.hadoop.mapreduce.LzoTextInputFormat /input /output1

0

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

[atguigu@hadoop102 module]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/common/hadoop-lzo-0.4.20.jar com.hadoop.compression.lzo.DistributedLzoIndexer /input/bigtable.lzo

(4)再次执行WordCount程序

[atguigu@hadoop102 module]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -Dmapreduce.job.inputformat.class=com.hadoop.mapreduce.LzoTextInputFormat /input /output2

3)注意:如果以上任务,在运行过程中报如下异常

Container [pid=8468,containerID=container_1594198338753_0001_01_000002] is running 318740992B beyond the 'VIRTUAL' memory limit. Current usage: 111.5 MB of 1 GB physical memory used; 2.4 GB of 2.1 GB virtual memory used. Killing container. Dump of the process-tree for container_1594198338753_0001_01_000002 :

解决办法:在hadoop102的/opt/module/hadoop-3.1.3/etc/hadoop/yarn-site.xml文件中增加如下配置,然后分发到hadoop103、hadoop104服务器上,并重新启动集群。

<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是true --> <property> <name>yarn.nodemanager.pmem-check-enabled</name> <value>false</value> </property> <!--是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认是true --> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property>

4.2.5 项目经验之基准测试

1) 测试HDFS写性能

测试内容:向HDFS集群写10个128M的文件

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -write -nrFiles 10 -fileSize 128MB 2020-04-16 13:41:24,724 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write 2020-04-16 13:41:24,724 INFO fs.TestDFSIO: Date & time: Thu Apr 16 13:41:24 CST 2020 2020-04-16 13:41:24,724 INFO fs.TestDFSIO: Number of files: 10 2020-04-16 13:41:24,725 INFO fs.TestDFSIO: Total MBytes processed: 1280 2020-04-16 13:41:24,725 INFO fs.TestDFSIO: Throughput mb/sec: 8.88 2020-04-16 13:41:24,725 INFO fs.TestDFSIO: Average IO rate mb/sec: 8.96 2020-04-16 13:41:24,725 INFO fs.TestDFSIO: IO rate std deviation: 0.87 2020-04-16 13:41:24,725 INFO fs.TestDFSIO: Test exec time sec: 67.61

注意:nrFiles n为生成mapTask的数量,生产环境一般可通过8088端口查看cpu核数,设置为cpu核数-1

Number of files:生成mapTask数量,一般是集群中CPU核数-1,我们测试虚拟机就按照实际的物理cpu-1分配即可

Total MBytes processed:单个map处理的文件大小

Throughput mb/sec:单个mapTak的吞吐量    

计算方式:处理的总文件大小/每一个mapTask写数据的时间累加

集群整体吞吐量:生成mapTask数量*单个mapTak的吞吐量

Average IO rate mb/sec::单个mapTak的吞吐量  

计算方式:每个mapTask处理文件大小/每一个mapTask写数据的时间 累加/生成mapTask数量

IO rate std deviation:方差、反映各个mapTask处理的差值,越小越均衡

注意:如果测试过程中,出现异常可以在yarn-site.xml中设置虚拟内存检测为false

分发配置并重启集群

<!--是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认是true --> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property>

2)测试HDFS读性能

测试内容:读取HDFS集群10个128M的文件

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -read -nrFiles 10 -fileSize 128MB 2020-04-16 13:43:38,857 INFO fs.TestDFSIO: ----- TestDFSIO ----- : read 2020-04-16 13:43:38,858 INFO fs.TestDFSIO: Date & time: Thu Apr 16 13:43:38 CST 2020 2020-04-16 13:43:38,859 INFO fs.TestDFSIO: Number of files: 10 2020-04-16 13:43:38,859 INFO fs.TestDFSIO: Total MBytes processed: 1280 2020-04-16 13:43:38,859 INFO fs.TestDFSIO: Throughput mb/sec: 85.54 2020-04-16 13:43:38,860 INFO fs.TestDFSIO: Average IO rate mb/sec: 100.21 2020-04-16 13:43:38,860 INFO fs.TestDFSIO: IO rate std deviation: 44.37 2020-04-16 13:43:38,860 INFO fs.TestDFSIO: Test exec time sec: 53.61

3)删除测试生成数据

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar TestDFSIO -clean

4)使用Sort程序评测MapReduce

(1)使用RandomWriter来产生随机数,每个节点运行10个Map任务,每个Map产生大约1G大小的二进制随机数

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar randomwriter random-data

(2)执行Sort程序

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar sort random-data sorted-data

(3)验证数据是否真正排好序了

[atguigu@hadoop102 mapreduce]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.3-tests.jar testmapredsort -sortInput random-data -sortOutput sorted-data

4.2.6 项目经验之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>

dfs.namenode.handler.count=

,比如集群规模为8台时,此参数设置为41。可通过简单的python代码计算该值,代码如下。

[atguigu@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()

2)YARN参数调优yarn-site.xml

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

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

(2)解决办法:

内存利用率不够。这个一般是Yarn的2个配置造成的,单个任务可以申请的最大内存大小,和Hadoop单个节点可用内存大小。调节这两个参数能提高系统内存的利用率。

(a)yarn.nodemanager.resource.memory-mb

表示该节点上YARN可使用的物理内存总量,默认是8192(MB),注意,如果你的节点内存资源不够8GB,则需要调减小这个值,而YARN不会智能的探测节点的物理内存总量。

(b)yarn.scheduler.maximum-allocation-mb

单个任务可申请的最多物理内存量,默认是8192(MB)。

4.3 Zookeeper安装

4.3.1 安装ZK

详见:尚硅谷大数据技术之Zookeeper

集群规划

服务器hadoop102

服务器hadoop103

服务器hadoop104

Zookeeper

Zookeeper

Zookeeper

Zookeeper

4.3.2 ZK集群启动停止脚本

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

[atguigu@hadoop102 bin]$ vim zk.sh

在脚本中编写如下内容

#!/bin/bash case $1 in "start"){ for i in hadoop102 hadoop103 hadoop104 do echo ---------- zookeeper $i 启动 ------------ ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start" done };; "stop"){ for i in hadoop102 hadoop103 hadoop104 do echo ---------- zookeeper $i 停止 ------------ ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop" done };; "status"){ for i in hadoop102 hadoop103 hadoop104 do echo ---------- zookeeper $i 状态 ------------ ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status" done };; esac

2)增加脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x zk.sh

3)Zookeeper集群启动脚本

[atguigu@hadoop102 module]$ zk.sh start

4)Zookeeper集群停止脚本

[atguigu@hadoop102 module]$ zk.sh stop

4.4 Kafka安装

4.4.1 Kafka集群安装

详见:尚硅谷大数据技术之Kafka

集群规划:

服务器hadoop102

服务器hadoop103

服务器hadoop104

Kafka

Kafka

Kafka

Kafka

4.4.2 Kafka集群启动停止脚本

1)在/home/atguigu/bin目录下创建脚本kf.sh

[atguigu@hadoop102 bin]$ vim kf.sh

在脚本中填写如下内容

#! /bin/bash case $1 in "start"){ for i in hadoop102 hadoop103 hadoop104 do echo " --------启动 $i Kafka-------" ssh $i "/opt/module/kafka/bin/kafka-server-start.sh -daemon /opt/module/kafka/config/server.properties" done };; "stop"){ for i in hadoop102 hadoop103 hadoop104 do echo " --------停止 $i Kafka-------" ssh $i "/opt/module/kafka/bin/kafka-server-stop.sh stop" done };; esac

2)增加脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x kf.sh

3)kf集群启动脚本

[atguigu@hadoop102 module]$ kf.sh start

4)kf集群停止脚本

[atguigu@hadoop102 module]$ kf.sh stop

4.4.3 Kafka常用命令

1)查看Kafka Topic列表

[atguigu@hadoop102 kafka]$ bin/kafka-topics.sh --zookeeper hadoop102:2181/kafka --list

2)创建Kafka Topic

进入到/opt/module/kafka/目录下创建日志主题

[atguigu@hadoop102 kafka]$ bin/kafka-topics.sh --zookeeper hadoop102:2181,hadoop103:2181,hadoop104:2181/kafka --create --replication-factor 1 --partitions 1 --topic topic_log

3)删除Kafka Topic

[atguigu@hadoop102 kafka]$ bin/kafka-topics.sh --delete --zookeeper hadoop102:2181,hadoop103:2181,hadoop104:2181/kafka --topic topic_log

4)Kafka生产消息

[atguigu@hadoop102 kafka]$ bin/kafka-console-producer.sh \ --broker-list hadoop102:9092 --topic topic_log >hello world >atguigu atguigu

5)Kafka消费消息

[atguigu@hadoop102 kafka]$ bin/kafka-console-consumer.sh \ --bootstrap-server hadoop102:9092 --from-beginning --topic topic_log

--from-beginning:会把主题中以往所有的数据都读取出来。根据业务场景选择是否增加该配置。

6)查看Kafka Topic详情

[atguigu@hadoop102 kafka]$ bin/kafka-topics.sh --zookeeper hadoop102:2181/kafka \ --describe --topic topic_log

4.4.4 项目经验之Kafka压力测试

1)Kafka压测

用Kafka官方自带的脚本,对Kafka进行压测。Kafka压测时,可以查看到哪个地方出现了瓶颈(CPU,内存,网络IO)。一般都是网络IO达到瓶颈。 

kafka-consumer-perf-test.sh

kafka-producer-perf-test.sh

2)Kafka Producer压力测试

(1)在/opt/module/kafka/bin目录下面有这两个文件。我们来测试一下

[atguigu@hadoop102 kafka]$ bin/kafka-producer-perf-test.sh  --topic test --record-size 100 --num-records 100000 --throughput -1 --producer-props bootstrap.servers=hadoop102:9092,hadoop103:9092,hadoop104:9092

说明:

record-size是一条信息有多大,单位是字节。

num-records是总共发送多少条信息。

throughput 是每秒多少条信息,设成-1,表示不限流,可测出生产者最大吞吐量。

(2)Kafka会打印下面的信息

100000 records sent, 95877.277085 records/sec (9.14 MB/sec), 187.68 ms avg latency, 424.00 ms max latency, 155 ms 50th, 411 ms 95th, 423 ms 99th, 424 ms 99.9th.

参数解析:本例中一共写入10w条消息,吞吐量为9.14 MB/sec,每次写入的平均延迟为187.68毫秒,最大的延迟为424.00毫秒。

3)Kafka Consumer压力测试

Consumer的测试,如果这四个指标(IO,CPU,内存,网络)都不能改变,考虑增加分区数来提升性能。

[atguigu@hadoop102 kafka]$ bin/kafka-consumer-perf-test.sh --broker-list hadoop102:9092,hadoop103:9092,hadoop104:9092 --topic test --fetch-size 10000 --messages 10000000 --threads 1

参数说明:

--zookeeper 指定zookeeper的链接信息

--topic 指定topic的名称

--fetch-size 指定每次fetch的数据的大小

--messages 总共要消费的消息个数

测试结果说明:

start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec

2019-02-19 20:29:07:566, 2019-02-19 20:29:12:170, 9.5368, 2.0714, 100010, 21722.4153

开始测试时间,测试结束数据,共消费数据9.5368MB,吞吐量2.0714MB/s,共消费100010条,平均每秒消费21722.4153条。

4.4.5 项目经验之Kafka机器数量计算

Kafka机器数量(经验公式)=2*(峰值生产速度*副本数/100)+1

先拿到峰值生产速度,再根据设定的副本数,就能预估出需要部署Kafka的数量。

比如我们的峰值生产速度是50M/s。副本数为2。

Kafka机器数量=2*(50*2/100)+ 1=3台

4.4.6 项目经验值Kafka分区数计算

1)创建一个只有1个分区的topic

2)测试这个topic的producer吞吐量和consumer吞吐量。

3)假设他们的值分别是Tp和Tc,单位可以是MB/s。

4)然后假设总的目标吞吐量是Tt,那么分区数=Tt / min(Tp,Tc)

例如:producer吞吐量=20m/s;consumer吞吐量=50m/s,期望吞吐量100m/s;

分区数=100 / 20 =5分区

如何根据数据量确定Kafka分区个数、Kafka的分区是不是越多越好、Kafak生产者分发策略,消费者负载均衡 09_https://blog.csdn.net/weixin_42641909/article/deta-CSDN博客

分区数一般设置为:3-10个

4.5 采集日志Flume

4.5.1 日志采集Flume安装

详见:尚硅谷大数据技术之Flume

尚硅谷大数据技术之flume.docx

集群规划:

服务器hadoop102

服务器hadoop103

服务器hadoop104

Flume(采集日志)

Flume

Flume

4.5.2 项目经验之Flume组件选型

1)Source

(1)Taildir Source相比Exec Source、Spooling Directory Source的优势

TailDir Source:断点续传、多目录。Flume1.6以前需要自己自定义Source记录每次读取文件位置,实现断点续传。

Exec Source可以实时搜集数据,但是在Flume不运行或者Shell命令出错的情况下,数据将会丢失。

Spooling Directory Source监控目录,支持断点续传。

(2)batchSize大小如何设置?

答:Event 1K左右时,500-1000合适(默认为100)

2)Channel

采用Kafka Channel,省去了Sink,提高了效率。KafkaChannel数据存储在Kafka里面,所以数据是存储在磁盘中。

注意在Flume1.7以前,Kafka Channel很少有人使用,因为发现parseAsFlumeEvent这个配置起不了作用。也就是无论parseAsFlumeEvent配置为true还是false,都会转为Flume Event。这样的话,造成的结果是,会始终都把Flume的headers中的信息混合着内容一起写入Kafka的消息中,这显然不是我所需要的,我只是需要把内容写入即可。

4.5.3 日志采集Flume配置

1)Flume配置分析

Flume直接读log日志的数据,log日志的格式是app.yyyy-mm-dd.log。

2)Flume的具体配置如下:

(1)在/opt/module/flume/conf目录下创建file-flume-kafka.conf文件

[atguigu@hadoop102 conf]$ vim file-flume-kafka.conf

在文件配置如下内容

#为各组件命名 a1.sources = r1 a1.channels = c1 #描述source a1.sources.r1.type = TAILDIR a1.sources.r1.filegroups = f1 a1.sources.r1.filegroups.f1 = /opt/module/applog/log/app.* a1.sources.r1.positionFile = /opt/module/flume/taildir_position.json a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = com.atguigu.flume.interceptor.ETLInterceptor$Builder #描述channel a1.channels.c1.type = org.apache.flume.channel.kafka.KafkaChannel a1.channels.c1.kafka.bootstrap.servers = hadoop102:9092,hadoop103:9092 a1.channels.c1.kafka.topic = topic_log a1.channels.c1.parseAsFlumeEvent = false #绑定source和channel以及sink和channel的关系 a1.sources.r1.channels = c1

注意:com.atguigu.flume.interceptor.ETLInterceptor是自定义的拦截器的全类名。需要根据用户自定义的拦截器做相应修改。

4.5.4 Flume拦截器

1)创建Maven工程flume-interceptor

2)创建包名:com.atguigu.flume.interceptor

3)在pom.xml文件中添加如下配置

<dependencies> <dependency> <groupId>org.apache.flume</groupId> <artifactId>flume-ng-core</artifactId> <version>1.9.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

注意:scope中provided的含义是编译时用该jar包。打包时时不用。因为集群上已经存在flume的jar包。只是本地编译时用一下。

4)在com.atguigu.flume.interceptor包下创建JSONUtils类

package com.atguigu.flume.interceptor; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; public class JSONUtils { public static boolean isJSONValidate(String log){ try { JSON.parse(log); return true; }catch (JSONException e){ return false; } }}

5)在com.atguigu.flume.interceptor包下创建LogInterceptor类

package com.atguigu.flume.interceptor; import com.alibaba.fastjson.JSON; 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) { byte[] body = event.getBody(); String log = new String(body, StandardCharsets.UTF_8); if (JSONUtils.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() { } }

6)打包

7)需要先将打好的包放入到hadoop102的/opt/module/flume/lib文件夹下面。

[atguigu@hadoop102 lib]$ ls | grep interceptor flume-interceptor-1.0-SNAPSHOT-jar-with-dependencies.jar

8)分发Flume到hadoop103、hadoop104

[atguigu@hadoop102 module]$ xsync flume/

9)分别在hadoop102、hadoop103上启动Flume

[atguigu@hadoop102 flume]$ bin/flume-ng agent --name a1 --conf-file conf/file-flume-kafka.conf & [atguigu@hadoop103 flume]$ bin/flume-ng agent --name a1 --conf-file conf/file-flume-kafka.conf &

4.5.5 日志采集Flume启动停止脚本

1)在/home/atguigu/bin目录下创建脚本f1.sh

[atguigu@hadoop102 bin]$ vim f1.sh

在脚本中填写如下内容

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

说明1:nohup,该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup就是不挂起的意思,不挂断地运行命令。

说明2:awk 默认分隔符为空格

说明3:xargs 表示取出前面命令运行的结果,作为后面命令的输入参数。

2)增加脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x f1.sh

3)f1集群启动脚本

[atguigu@hadoop102 module]$ f1.sh start

4)f1集群停止脚本

[atguigu@hadoop102 module]$ f1.sh stop

4.6 消费Kafka数据Flume

集群规划

服务器hadoop102

服务器hadoop103

服务器hadoop104

Flume(消费Kafka)

Flume

4.6.1 项目经验之Flume组件选型

1)FileChannel和MemoryChannel区别

MemoryChannel传输数据速度更快,但因为数据保存在JVM的堆内存中,Agent进程挂掉会导致数据丢失,适用于对数据质量要求不高的需求。

FileChannel传输速度相对于Memory慢,但数据安全保障高,Agent进程挂掉也可以从失败中恢复数据。

选型:

金融类公司、对钱要求非常准确的公司通常会选择FileChannel

传输的是普通日志信息(京东内部一天丢100万-200万条,这是非常正常的),通常选择MemoryChannel。

2)FileChannel优化

通过配置dataDirs指向多个路径,每个路径对应不同的硬盘,增大Flume吞吐量。

官方说明如下:

Comma separated list of directories for storing log files. Using multiple directories on separate disks can improve file channel peformance

checkpointDir和backupCheckpointDir也尽量配置在不同硬盘对应的目录中,保证checkpoint坏掉后,可以快速使用backupCheckpointDir恢复数据

3)Sink:HDFS Sink

(1)HDFS存入大量小文件,有什么影响?

元数据层面:每个小文件都有一份元数据,其中包括文件路径,文件名,所有者,所属组,权限,创建时间等,这些信息都保存在Namenode内存中。所以小文件过多,会占用Namenode服务器大量内存,影响Namenode性能和使用寿命

计算层面:默认情况下MR会对每个小文件启用一个Map任务计算,非常影响计算性能。同时也影响磁盘寻址时间。

(2)HDFS小文件处理

官方默认的这三个参数配置写入HDFS后会产生小文件,hdfs.rollInterval、hdfs.rollSize、hdfs.rollCount

基于以上hdfs.rollInterval=3600,hdfs.rollSize=134217728,hdfs.rollCount =0几个参数综合作用,效果如下:

(1)文件在达到128M时会滚动生成新文件

(2)文件创建超3600秒时会滚动生成新文件

4.6.2 Flume拦截器

由于Flume默认会用Linux系统时间,作为输出到HDFS路径的时间。如果数据是23:59分产生的。Flume消费Kafka里面的数据时,有可能已经是第二天了,那么这部门数据会被发往第二天的HDFS路径。我们希望的是根据日志里面的实际时间,发往HDFS的路径,所以下面拦截器作用是获取日志中的实际时间。

解决的思路:拦截json日志,通过fastjson框架解析json,获取实际时间ts。将获取的ts时间写入拦截器header头,header的key必须是timestamp,因为Flume框架会根据这个key的值识别为时间,写入到HDFS。

1)在com.atguigu.flume.interceptor包下创建TimeStampInterceptor类

package com.atguigu.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.ArrayList; import java.util.List; import java.util.Map; public class TimeStampInterceptor implements Interceptor { private ArrayList<Event> events = new ArrayList<>(); @Override public void initialize() { } @Override public Event intercept(Event event) { Map<String, String> headers = event.getHeaders(); String log = new String(event.getBody(), StandardCharsets.UTF_8); JSONObject jsonObject = JSONObject.parseObject(log); String ts = jsonObject.getString("ts"); headers.put("timestamp", ts); return event; } @Override public List<Event> intercept(List<Event> list) { events.clear(); for (Event event : list) { events.add(intercept(event)); } return events; } @Override public void close() { } public static class Builder implements Interceptor.Builder { @Override public Interceptor build() { return new TimeStampInterceptor(); } @Override public void configure(Context context) { } } }

2)重新打包

3)需要先将打好的包放入到hadoop102的/opt/module/flume/lib文件夹下面。

[atguigu@hadoop102 lib]$ ls | grep interceptor flume-interceptor-1.0-SNAPSHOT-jar-with-dependencies.jar

4)分发Flume到hadoop103、hadoop104

[atguigu@hadoop102 module]$ xsync flume/

4.6.3 日志消费Flume配置

1)Flume配置分析

2)Flume的具体配置如下:

(1)在hadoop104的/opt/module/flume/conf目录下创建kafka-flume-hdfs.conf文件

[atguigu@hadoop104 conf]$ vim kafka-flume-hdfs.conf

在文件配置如下内容

## 组件 a1.sources=r1 a1.channels=c1 a1.sinks=k1 ## source1 a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource a1.sources.r1.batchSize = 5000 a1.sources.r1.batchDurationMillis = 2000 a1.sources.r1.kafka.bootstrap.servers = hadoop102:9092,hadoop103:9092,hadoop104:9092 a1.sources.r1.kafka.topics=topic_log a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = com.atguigu.flume.interceptor.TimeStampInterceptor$Builder ## channel1 a1.channels.c1.type = file a1.channels.c1.checkpointDir = /opt/module/flume/checkpoint/behavior1 a1.channels.c1.dataDirs = /opt/module/flume/data/behavior1/ a1.channels.c1.maxFileSize = 2146435071 a1.channels.c1.capacity = 1000000 a1.channels.c1.keep-alive = 6 ## sink1 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.rollInterval = 10 a1.sinks.k1.hdfs.rollSize = 134217728 a1.sinks.k1.hdfs.rollCount = 0 ## 控制输出文件是原生文件。 a1.sinks.k1.hdfs.fileType = CompressedStream a1.sinks.k1.hdfs.codeC = lzop ## 拼装 a1.sources.r1.channels = c1 a1.sinks.k1.channel= c1

4.6.4 日志消费Flume启动停止脚本

1)在/home/atguigu/bin目录下创建脚本f2.sh

[atguigu@hadoop102 bin]$ vim f2.sh

在脚本中填写如下内容

#! /bin/bash case $1 in "start"){ for i in hadoop104 do echo " --------启动 $i 消费flume-------" ssh $i "nohup /opt/module/flume/bin/flume-ng agent --conf-file /opt/module/flume/conf/kafka-flume-hdfs.conf --name a1 -Dflume.root.logger=INFO,LOGFILE >/opt/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

2)增加脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x f2.sh

3)f2集群启动脚本

[atguigu@hadoop102 module]$ f2.sh start

4)f2集群停止脚本

[atguigu@hadoop102 module]$ f2.sh stop

4.6.5 项目经验之Flume内存优化

1)问题描述:如果启动消费Flume抛出如下异常

ERROR hdfs.HDFSEventSink: process failed

java.lang.OutOfMemoryError: GC overhead limit exceeded

2)解决方案步骤:

(1)在hadoop102服务器的/opt/module/flume/conf/flume-env.sh文件中增加如下配置

export JAVA_OPTS="-Xms100m -Xmx2000m -Dcom.sun.management.jmxremote"

(2)同步配置到hadoop103、hadoop104服务器

[atguigu@hadoop102 conf]$ xsync flume-env.sh

3)Flume内存参数设置及优化

JVM heap一般设置为4G或更高

-Xmx与-Xms最好设置一致,减少内存抖动带来的性能影响,如果设置不一致容易导致频繁fullgc。

-Xms表示JVM Heap(堆内存)最小尺寸,初始分配;-Xmx 表示JVM Heap(堆内存)最大允许的尺寸,按需分配。如果不设置一致,容易在初始化时,由于内存不够,频繁触发fullgc。

4.7 采集通道启动/停止脚本

4.7.1 数据通道测试

根据需求分别生成2020-06-14和2020-06-15日期的数据

1)修改/opt/module/applog/application.properties中业务日期为2020-06-14

#业务日期 mock.date=2020-06-14

2)执行脚本,生成2020-06-14日志数据

[atguigu@hadoop102 ~]$ lg.sh

3)再次修改/opt/module/applog/application.properties中业务日期2020-06-15

#业务日期 mock.date=2020-06-15

4)执行脚本,生成2020-06-15日志数据

[atguigu@hadoop102 ~]$ lg.sh

5)在这个期间,不断观察Hadoop的HDFS路径上是否有数据

4.7.2 采集通道启动/停止脚本

1)在/home/atguigu/bin目录下创建脚本cluster.sh

[atguigu@hadoop102 bin]$ vim cluster.sh

在脚本中填写如下内容

#!/bin/bash case $1 in "start"){ echo ================== 启动 集群 ================== #启动 Zookeeper集群 zk.sh start #启动 Hadoop集群 hdp.sh start #启动 Kafka采集集群 kf.sh start #启动 Flume采集集群 f1.sh start #启动 Flume消费集群 f2.sh start };; "stop"){ echo ================== 停止 集群 ================== #停止 Flume消费集群 f2.sh stop #停止 Flume采集集群 f1.sh stop #停止 Kafka采集集群 kf.sh stop #停止 Hadoop集群 hdp.sh stop #停止 Zookeeper集群 zk.sh stop };; esac

2)增加脚本执行权限

[atguigu@hadoop102 bin]$ chmod u+x cluster.sh

3)cluster集群启动脚本

[atguigu@hadoop102 module]$ cluster.sh start

4)cluster集群停止脚本

[atguigu@hadoop102 module]$ cluster.sh stop

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值