Fork me on GitHub

数据仓库| 1.1 集群环境搭建| 行为数据采集

 

用户行为数据

1、数据的生成

1. 目标数据

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

页面、事件、曝光、启动、错误等数据,还有公共信息:

common

  "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版本号
  }

① 页面 page:

 

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

比如JSON格式如下:

  "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"    -- 页面来源类型
  }

字段名称

字段描述

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

动作时间

② 事件 (动作) actions

  

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

"actions": [                     --动作(事件)  
    {
      "action_id": "favor_add",  --动作id
      "item": "3",               --动作目标id
      "item_type": "sku_id",     --动作目标类型
      "ts": 1585744376605        --动作时间
    }
  ]

字段名称

字段描述

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

动作时间

③ 曝光 displays

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

  "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
    }
  ]

字段名称

字段描述

displayType

曝光类型

promotion("商品推广"),

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

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

activity("促销活动");

item_type

曝光对象类型

sku_id("商品skuId"),

activity_id("活动id");

item

曝光对象id

order

曝光顺序

④ 启动 start

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

 

  "start": {                --启动信息   
    "entry": "icon",        -- 启动入口 
    "loading_time": 18803,  -- 启动加载时间
    "open_ad_id": 7,        -- 开屏广告id
    "open_ad_ms": 3449,     -- 广告播放时间
    "open_ad_skip_ms": 1989 -- 用户跳过广告时间
  }

字段名称

字段描述

entry

启动入口

icon("图标"),

notification("通知"),

install("安装后启动");

loading_time

启动加载时间

open_ad_id

开屏广告id

open_ad_ms

广告播放时间

open_ad_skip_ms

用户跳过广告时间

ts

启动时间

⑤ 错误 err

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

"err":{                     -- 错误日志 
    "error_code": "1234",   -- 错误码
    "msg": "***********"    -- 错误信息
}

字段名称

字段描述

error_code

错误码

msg

错误信息

2. 数据埋点

主流埋点方式(了解)

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

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

OnClick 函数里面调用SDK提供的数据发送接口,来发送数据。

可视化埋点只需要研发人员集成采集 SDK,不需要写埋点代码,业务人员就可以通过访问分析平台的“圈选”功能,来“圈”出需要对用户行为进行捕捉的控件,并对该事件进行命名。圈

选完毕后,这些配置会同步到各个用户的终端上,由采集 SDK 按照圈选的配置自动进行用户行为数据的采集和发送。

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

埋点数据日志结构

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

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

应用信息等,即下边的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  -- 跳入时间
}
View Code

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 -- 启动时间
}
View Code

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

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

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

3. 模拟数据

Linux环境变量配置:

(1)修改/etc/profile文件:所有用户的Shell都有权使用这些环境变量。
(2)修改~/.bashrc文件:针对某一个特定的用户,如果你需要给某个用户权限使用这些环境变量,你只需要修改其个人用户主目录下的.bashrc文件就可以了。
(3)配置登录远程服务器立即source一下环境变量

[kris@hadoop101 ~]$ cat /etc/profile >> .bashrc
[kris@hadoop102 ~]$ cat /etc/profile >> .bashrc
[kris@hadoop103 ~]$ cat /etc/profile >> .bashrc

 

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

[kris@hadoop101 module]$ mkdir applog

2)配置文件

(1)application.properteis文件

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

[kris@hadoop101 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
View Code

(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 }

]
View Code

(3)日志生成命令

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

[kris@hadoop101 applog]$ java -jar gmall2020-mock-log-.jar

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

集群日志生成脚本

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

[kris@hadoop101 ~]$ echo $PATH

/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/kris/.local/bin:/home/kris/bin

       1)在/home/kris/bin目录下创建脚本lg.sh

#!/bin/bash

 

for i in hadoop101 hadoop102; do

    echo "========== $i =========="

    ssh $i "cd /opt/module/applog/; java -jar gmall2020-mock-log.jar >/dev/null 2>&1 &"

done
View Code

注:

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

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

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

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

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

将jar包及配置文件上传至hadoop102/opt/module/applog/路径

2、数据采集-集群搭建模块

集群所有进程查看脚本 xcall.sh  jps

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

[kris@hadoop101 bin]$ vim xcall.sh

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

集群时间同步修改脚本

在/home/kris/bin目录下创建脚本dt.sh
[kris@hadoop101 bin]$ vim dt.sh
#!/bin/bash
log_date=$1
for i in hadoop101 hadoop102 hadoop103
do
        ssh $i "sudo date -s $log_date"
done        
修改脚本执行权限
[kris@hadoop101 bin]$ chmod 777 dt.sh
启动脚本
[kris@hadoop101 bin]$ dt.sh 2019-2-10
    
View Code

Hadoop安装

            服务器hadoop101    服务器hadoop102    服务器hadoop103
HDFS           NameNode      DataNode          DataNode        
            DataNode                SecondaryNameNode
--------------------------------------------------------------------------- Yarn        NodeManager Resourcemanager   NodeManager
                       NodeManager

https://www.cnblogs.com/shengyang17/p/10274391.html

Hadoop的优化措施

① 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>

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

② 集群数据均衡

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.json

(3)查看当前均衡任务的执行情况
    hdfs diskbalancer -query hadoop103

(4)取消均衡任务
    hdfs diskbalancer -cancel hadoop103.plan.json

③ 压缩

1)方式一 支持LZO压缩配置

输入端采用压缩DEFLATE(deflate)压缩

mapper输出之后采用LZO或snappy

reducer输出之后gzip或bzip2

1)下载后的文件名是hadoop-lzo-master,它是一个zip格式的压缩包,先进行解压,然后用maven编译。生成hadoop-lzo-0.4.202)将编译好后的hadoop-lzo-0.4.20.jar 放入hadoop-2.7.2/share/hadoop/common/
  [kris@hadoop101 software]$ mv hadoop-lzo-0.4.20.jar /opt/module/hadoop-2.7.2/share/hadoop/common/
  [kris@hadoop101 common]$ ls
    hadoop-lzo-0.4.20.jar
3)同步hadoop-lzo-0.4.20.jar到hadoop102、hadoop103
  [kris@hadoop101 common]$ xsync hadoop-lzo-0.4.20.jar

4)core-site.xml增加配置支持LZO压缩
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<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到hadoop102、hadoop103
  [kris@hadoop101 hadoop]$ xsync core-site.xml

2)方式二 配置Hadoop支持Snappy压缩

(1)将编译后支持Snappy压缩的Hadoop jar包解压缩,并将lib/native目录中所有文件上传到hadoop101的/opt/module/hadoop-2.7.2/lib/native目录。

(2)重新启动Hadoop。

(3)检查支持的压缩方式

[kris@hadoop101 native]$ hadoop checknative
hadoop:  true /opt/module/hadoop-2.7.2/lib/native/libhadoop.so
zlib:    true /lib64/libz.so.1
snappy:  true /opt/module/hadoop-2.7.2/lib/native/libsnappy.so.1
lz4:     true revision:99
bzip2:   false

两种压缩方式配置一种即可。

④ LZO创建索引

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

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

比如添加如下的索引:
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
添加完索引再执行,切片数就会变多。

异常情况的处理:

如果以上任务,在运行过程中报如下异常
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 :
解决办法:在hadoop101的/opt/module/hadoop-3.1.3/etc/hadoop/yarn-site.xml文件中增加如下配置,然后分发到hadoop102、hadoop103服务器上,并重新启动集群。
<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是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>
View Code

⑤ 基准测试

1) 测试HDFS写性能

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

[kris@hadoop101 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,我们测试虚拟机就按照实际的物理内存-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的文件

[kris@hadoop101 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)删除测试生成数据
  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大小的二进制随机数
     hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar randomwriter random-data

 (2)执行Sort程序
     hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar sort random-data sorted-data

 (3)验证数据是否真正排好序了
     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

⑥ 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=20 × loge(Cluster Size),比如集群规模为8台时,此参数设置为41。可通过简单的python代码计算该值,代码如下。

>>> 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)。

Zookeeper安装

              服务器hadoop101    服务器hadoop102    服务器hadoop103
Zookeeper            Zookeeper        Zookeeper         Zookeeper

详细安装见:

https://www.cnblogs.com/shengyang17/p/10325484.html

zookeeper集群启动脚本;

chmod 777 zk.sh

[kris@hadoop101 bin]$ vim zk.sh 
#!/bin/bash
case $1 in
"start"){
        for i in hadoop101 hadoop102 hadoop103
        do
        ssh $i "/opt/module/zookeeper-3.4.10/bin/zkServer.sh start"
        done
};;
"stop"){
        for i in hadoop101 hadoop102 hadoop103
        do
        ssh $i "/opt/module/zookeeper-3.4.10/bin/zkServer.sh stop"
        done
};;
esac
View Code

Kafka安装

详细安装见:

https://www.cnblogs.com/shengyang17/p/10443115.html

kafka启动关闭脚本:

#!/bin/bash
case $1 in
"start"){
        for i in hadoop101 hadoop102 hadoop103
        do
           echo "------------启动 $i kafka----------------"
        ssh $i "export JMX_PORT=9988 && /opt/module/kafka/bin/kafka-server-start.sh -daemon /opt/module/kafka/config/serve
r.properties"
        done
};;
"stop"){
        for i in hadoop101 hadoop102 hadoop103
        do
           echo "------------停止 $i kafka----------------"
        ssh $i "/opt/module/kafka/bin/kafka-server-stop.sh stop"
        done
};;
esac
~              
View Code

注意:启动Kafka时要先开启JMX端口,是用于后续KafkaManager监控。

Kafka Manager安装

详细见:

https://www.cnblogs.com/shengyang17/p/10459101.html

启动KafkaManager

[kris@hadoop101 kafka-manager-1.3.3.22]$ 
nohup bin/kafka-manager   -Dhttp.port=7456 >/opt/module/kafka-manager-1.3.3.22/start.log 2>&1 &

在浏览器中打开 http://hadoop101:7456 ,至此,就可以查看整个Kafka集群的状态,包括:Topic的状态、Brokers的状态、Cosumer的状态。

在kafka的/opt/module/kafka-manager-1.3.3.22/application.home_IS_UNDEFINED 目录下面,可以看到kafka-manager的日志。

Kafka Manager启动停止脚本

1)在/home/kris/bin目录下创建脚本km.sh; chmod +x km.sh

[kris@hadoop101 bin]$ vim km.sh

#!/bin/bash
case $1 in
"start"){
        echo "---------启动KafkaManager---------"
        nohup /opt/module/kafka-manager/bin/kafka-manager -Dhttp.port=7456 >/opt/module/kafka-manager/start.log 2>&1 &
};;
"stop"){
        echo "---------停止KafkaManager---------"
        ps -ef | grep ProdServerStart | grep -v grep | awk '{print $2}' | xargs kill
};;
esac
View Code
查看所有Kafka Topic
  bin/kafka-topics.sh --zookeeper hadoop101:2181 --list   #查看kafka中都有哪些主题
  bin/kafka-topics.sh --delete --zookeeper hadoop101:2181,hadoop102:2181,hadoop103:2181 --topic topic_log  ##删除主题
生产消息
  bin/kafka-console-producer.sh \
  --broker-list hadoop101:9092 --topic test
 >hello world
 >kris  kris

消费消息
  bin/kafka-console-consumer.sh \
   --bootstrap-server hadoop101:9092 --from-beginning --topic test

Kafka优化措施

① Kafka压测

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

kafka-consumer-perf-test.sh

kafka-producer-perf-test.sh

1)Kafka Producer压力测试

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

[kris@hadoop101 kafka]$ bin/kafka-producer-perf-test.sh \
--topic test \
--record-size 100 \
--num-recor 100000 \
--throughput -1 \
--producer-props bootstrap.servers=hadoop101:9092,hadoop102:9092,hadoop103:9092
[kris@hadoop101 kafka]$ bin/kafka-producer-perf-test.sh  --topic test --record-size 100 --num-recor 100000 --throughput 1000 --producer-props bootstrap.servers=hadoop101:9092,hadoop102:9092,hadoop103:9092
5000 records sent, 1000.0 records/sec (0.10 MB/sec), 2.6 ms avg latency, 183.0 max latency.
5012 records sent, 1002.4 records/sec (0.10 MB/sec), 1.0 ms avg latency, 36.0 max latency.
5001 records sent, 1000.2 records/sec (0.10 MB/sec), 0.6 ms avg latency, 8.0 max latency.
5001 records sent, 1000.2 records/sec (0.10 MB/sec), 0.4 ms avg latency, 22.0 max latency.
5001 records sent, 1000.0 records/sec (0.10 MB/sec), 0.6 ms avg latency, 45.0 max latency.
5002 records sent, 1000.2 records/sec (0.10 MB/sec), 0.3 ms avg latency, 3.0 max latency.
5001 records sent, 1000.2 records/sec (0.10 MB/sec), 0.8 ms avg latency, 27.0 max latency.
5001 records sent, 1000.0 records/sec (0.10 MB/sec), 0.5 ms avg latency, 54.0 max latency.
5001 records sent, 1000.0 records/sec (0.10 MB/sec), 0.7 ms avg latency, 60.0 max latency.
5003 records sent, 1000.4 records/sec (0.10 MB/sec), 0.4 ms avg latency, 29.0 max latency.
5000 records sent, 1000.0 records/sec (0.10 MB/sec), 0.7 ms avg latency, 50.0 max latency.
5001 records sent, 1000.2 records/sec (0.10 MB/sec), 0.9 ms avg latency, 82.0 max latency.
5003 records sent, 1000.2 records/sec (0.10 MB/sec), 0.4 ms avg latency, 32.0 max latency.
5000 records sent, 1000.0 records/sec (0.10 MB/sec), 0.8 ms avg latency, 67.0 max latency.
5002 records sent, 1000.2 records/sec (0.10 MB/sec), 0.9 ms avg latency, 80.0 max latency.
5002 records sent, 1000.0 records/sec (0.10 MB/sec), 0.4 ms avg latency, 18.0 max latency.
5000 records sent, 1000.0 records/sec (0.10 MB/sec), 0.9 ms avg latency, 75.0 max latency.
5001 records sent, 1000.2 records/sec (0.10 MB/sec), 0.5 ms avg latency, 23.0 max latency.
5003 records sent, 1000.2 records/sec (0.10 MB/sec), 0.5 ms avg latency, 26.0 max latency.
100000 records sent, 999.950002 records/sec (0.10 MB/sec), 0.72 ms avg latency, 183.00 ms max latency, 0 ms 50th, 1 ms 95th, 3 ms 99th, 44 ms 99.9th
View Code

测试生成了多少数据,消费了多少数据;每条信息大小,总共发送的条数;每秒多少条数据;

说明:

  • record-size是一条信息有多大,单位是字节。
  • num-records是总共发送多少条信息。
  • throughput 是每秒多少条信息,设成-1表不限流,可测出生产者最大吞吐量。

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毫秒。

 

2)Kafka Consumer压力测试

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

[kris@hadoop103 kafka]$ bin/kafka-consumer-perf-test.sh \
--broker-list hadoop101:9092,hadoop102:9092,hadoop103:9092 \
--topic test \
--fetch-size 10000 \
--messages 10000000 \
--threads 1 start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec 2019-03-15 00:04:21:474, 2019-03-15 00:04:21:740, 1.1851, 4.4551, 1492, 5609.0226

参数说明:

--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条。

 

②Kafka机器数量计算

先要预估一天大概产生多少数据,然后用Kafka自带的生产压测(只测试Kafka的写入速度,保证数据不积压),计算出峰值生产速度。再根据设定的副本数,就能预估出需要部署Kafka的数量。

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

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

比如我们采用压力测试测出写入速度是10M/S一台,峰值的业务数据生产速度是50M/s。副本数为2。

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

③ 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分区 

https://blog.csdn.net/weixin_42641909/article/details/89294698

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

Flume安装

详细安装

https://www.cnblogs.com/shengyang17/p/10405979.html

Flume拦截器

本项目中自定义了两个拦截器,分别是:日志采集Flume中的ETL拦截器(清洗日志中的脏数据)和 消费Flume的 时间戳拦截器

ETL拦截器主要用于,过滤时间戳不合法和json数据不完整的日志

时间拦截器主要用于(因为hdfs-sink落盘日志的时间是linux系统现在的时间,要将它转换为log日志中的时间。)

由于Flume默认会用Linux系统时间,作为输出到HDFS路径的时间。如果数据是23:59分产生的。Flume消费Kafka里面的数据时,有可能已经是第二天了,那么这部门数据会被发往第

二天的HDFS路径。我们希望的是根据日志里面的实际时间,发往HDFS的路径,所以下面拦截器作用是获取日志中的实际时间。

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

将依赖的包上传,将打好的包放入到hadoop101的/opt/module/flume/lib文件夹下面。

[kris@hadoop101 lib]$ ls | grep interceptor

  flume-interceptor-1.0-SNAPSHOT-jar-with-dependencies.jar

分发flume到hadoop102、hadoop103

[kris@hadoop101 module]$ xsync flume/
[kris@hadoop101 flume]$ bin/flume-ng agent --conf conf/ --name a1 --conf-file conf/file-flume-kafka.conf &

Flume组件选型

1)Source

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

TailDir Source:是Flume 1.7提供的Source组件,在1.6中并没有。断点续传、多目录。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的消息中,这显然不是我所需要的,我只是需要把内容写入即可。

 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

checkpointDirbackupCheckpointDir也尽量配置在不同硬盘对应的目录中,保证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秒时会滚动生成新文件

① 日志采集Flume

https://flume.apache.org/releases/content/1.7.0/FlumeUserGuide.html  可使用ctrl+F搜索

            服务器hadoop101    服务器hadoop102   服务器hadoop103
Flume(采集日志)    Flume          Flume    

 

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

Flume日志采集:实时生成的日志文件(applog/gmall/appxxx.log)===> Flume(TailDir Source --> LogInterceptor--> Kafka Channel) ==> Kafka (topic_log) 

两种Channel选择方案:

①memory channl 配置如下:

[kris@hadoop101 conf]$ vim file-flume-kafka.conf

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

# configure source
a1.sources.r1.type = TAILDIR
a1.sources.r1.positionFile = /opt/module/flume/log_position.json
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /tmp/logs/app.+
a1.sources.r1.fileHeader = true
a1.sources.r1.channels = c1 c2

#interceptor
a1.sources.r1.interceptors = i1 i2
a1.sources.r1.interceptors.i1.type = com.atguigu.flume.interceptor.LogETLInterceptor$Builder
a1.sources.r1.interceptors.i2.type = com.atguigu.flume.interceptor.LogTypeInterceptor$Builder

# selector
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = logType
a1.sources.r1.selector.mapping.start = c1
a1.sources.r1.selector.mapping.event = c2

# configure channel
a1.channels.c1.type = memory
a1.channels.c1.capacity=10000
a1.channels.c1.byteCapacityBufferPercentage=20

a1.channels.c2.type = memory
a1.channels.c2.capacity=10000
a1.channels.c2.byteCapacityBufferPercentage=20

# configure sink
# start-sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = topic_start
a1.sinks.k1.kafka.bootstrap.servers = hadoop101:9092,hadoop102:9092,hadoop103:9092
a1.sinks.k1.kafka.flumeBatchSize = 2000
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.channel = c1

# event-sink
a1.sinks.k2.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k2.kafka.topic = topic_event
a1.sinks.k2.kafka.bootstrap.servers = hadoop101:9092,hadoop102:9092,hadoop103:9092
a1.sinks.k2.kafka.flumeBatchSize = 2000
a1.sinks.k2.kafka.producer.acks = 1
a1.sinks.k2.channel = c2
View Code

②采用KafkaChannel(没有sink),效率更高

[kris@hadoop101 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 = hadoop101:9092,hadoop102:9092
a1.channels.c1.kafka.topic = topic_log
a1.channels.c1.parseAsFlumeEvent = false

#绑定source和channel以及sink和channel的关系
a1.sources.r1.channels = c1
View Code

日志采集Flume启动停止脚本

roundValue:30s数据滚动一次;开发中一般1/h滚动一次 ;  logFile日志保存30天;

 在/home/kris/bin目录下创建脚本f1.sh;并添加执行权限;chmod +x f1.sh

[kris@hadoop101 bin]$ vim f1.sh 
#!/bin/bash
case $1 in
"start"){
        for i in hadoop101 hadoop102
        do
           echo "------------启动 $i 采集flume数据-----------" 
        ssh $i "nohup /opt/module/flume/bin/flume-ng agent -f /opt/module/flume/conf/file-flume-kafka.conf -n a1 -Dflume.r
oot.logger=INFO,LOGFILE >/dev/null 2>&1 &"
        done
};;
"stop"){
        for i in hadoop101 hadoop102
        do
           echo "------------停止 $i 采集flume数据------------"
        ssh $i "ps -ef | grep file-flume-kafka | grep -v grep | awk '{print \$2}' | xargs kill"
        done
};;
esac
View Code

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

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

日志采集Flume启动停止脚本

roundValue:30s数据滚动一次;开发中一般1/h滚动一次 ;  logFile日志保存30天;

 在/home/kris/bin目录下创建脚本f1.sh;并添加执行权限;chmod +x f1.sh

[kris@hadoop101 bin]$ vim f1.sh 
#!/bin/bash
case $1 in
"start"){
        for i in hadoop101 hadoop102
        do
           echo "------------启动 $i 采集flume数据-----------" 
        ssh $i "nohup /opt/module/flume/bin/flume-ng agent -f /opt/module/flume/conf/file-flume-kafka.conf -n a1 -Dflume.r
oot.logger=INFO,LOGFILE >/dev/null 2>&1 &"
        done
};;
"stop"){
        for i in hadoop101 hadoop102
        do
           echo "------------停止 $i 采集flume数据------------"
        ssh $i "ps -ef | grep file-flume-kafka | grep -v grep | awk '{print \$2}' | xargs kill"
        done
};;
esac
View Code

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

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

②消费Kafka数据Flume

 

服务器hadoop101

服务器hadoop102

服务器hadoop103

Flume(消费Kafka)

 

 

Flume

同时也对应两种方案:

①上层数据采集Flume有sink端:

在hadoop103的/opt/module/flume/conf目录下创建kafka-flume-hdfs.conf文件

[kris@hadoop103 conf]$ vim kafka-flume-hdfs.conf   配置了不产生大量小文件!

## 组件
a1.sources=r1 r2
a1.channels=c1 c2
a1.sinks=k1 k2

## 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 = hadoop101:9092,hadoop102:9092,hadoop103:9092
a1.sources.r1.kafka.topics=topic_start

## source2
a1.sources.r2.type = org.apache.flume.source.kafka.KafkaSource
a1.sources.r2.batchSize = 5000
a1.sources.r2.batchDurationMillis = 2000
a1.sources.r2.kafka.bootstrap.servers = hadoop101:9092,hadoop102:9092,hadoop103:9092
a1.sources.r2.kafka.topics=topic_event

## channel1
a1.channels.c1.type=memory
a1.channels.c1.capacity=100000
a1.channels.c1.transactionCapacity=10000

## channel2
a1.channels.c2.type=memory
a1.channels.c2.capacity=100000
a1.channels.c2.transactionCapacity=10000

## sink1
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /origin_data/gmall/log/topic_start/%Y-%m-%d
a1.sinks.k1.hdfs.filePrefix = logstart-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 30
a1.sinks.k1.hdfs.roundUnit = second

##sink2
a1.sinks.k2.type = hdfs
a1.sinks.k2.hdfs.path = /origin_data/gmall/log/topic_event/%Y-%m-%d
a1.sinks.k2.hdfs.filePrefix = logevent-
a1.sinks.k2.hdfs.round = true
a1.sinks.k2.hdfs.roundValue = 30
a1.sinks.k2.hdfs.roundUnit = second

## 不要产生大量小文件
a1.sinks.k1.hdfs.rollInterval = 10
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0

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

## 控制输出文件是原生文件。
a1.sinks.k1.hdfs.fileType = CompressedStream 
a1.sinks.k2.hdfs.fileType = CompressedStream 

a1.sinks.k1.hdfs.codeC = lzop
a1.sinks.k2.hdfs.codeC = lzop

## 拼装
a1.sources.r1.channels = c1
a1.sinks.k1.channel= c1

a1.sources.r2.channels = c2
a1.sinks.k2.channel= c2
View Code

②上层数据采集Flume如果采用了KafkaChannel,消费Flume的配置如下:

[kris@hadoop103 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 = hadoop101:9092,hadoop102:9092,hadoop103: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
View Code

日志消费Flume启动停止脚本,在/home/kris/bin目录下创建脚本f2.sh;并chmod +x f2.sh

#! /bin/bash

case $1 in
"start"){
        for i in hadoop103
        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/log.txt   2>&1 &"
        done
};;
"stop"){
        for i in hadoop103
        do
                echo "------------停止 $i 消费flume------------"
                ssh $i "ps -ef | grep kafka-flume-hdfs | grep -v grep |awk '{print \$2}' | xargs kill -9"
        done

};;
esac
View Code

最快消费(最大吞吐量),消费> 生产;kafka可对接ES等

Flume内存优化

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

ERROR hdfs.HDFSEventSink: process failed

java.lang.OutOfMemoryError: GC overhead limit exceeded

2)解决方案步骤:

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

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

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

[kris@hadoop101 conf]$ xsync flume-env.sh

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

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

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

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

采集通道启动/停止脚本

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

[kris@hadoop101 bin]$ vim cluster.sh

#!/bin/bash
case $1 in
"start"){
        echo "-----------启动集群----------"
        /opt/module/hadoop-2.7.2/sbin/start-dfs.sh 
        ssh hadoop102 /opt/module/hadoop-2.7.2/sbin/start-yarn.sh
        zk.sh start
        f1.sh start
        kf.sh start
        sleep 4s;
        f2.sh start
        km.sh start
};;
"stop"){
        echo "------------停止集群----------------"
        km.sh stop
        f2.sh stop
        kf.sh stop
        sleep 7s;
        f1.sh stop
        sleep 3s;
        zk.sh stop
        ssh hadoop102 "/opt/module/hadoop-2.7.2/sbin/stop-yarn.sh"
        /opt/module/hadoop-2.7.2/sbin/stop-dfs.sh
};;
esac
View Code

改时间重新启动集群,因为flume和kafka会去通信看时间,时间偏差大就会挂掉

posted @ 2019-03-19 00:07  kris12  阅读(2724)  评论(2编辑  收藏  举报
levels of contents