LZ名約山炮

博客园 首页 新随笔 联系 订阅 管理

1章 数据仓库概念

   数据仓库(Data Warehouse)是为企业所有决策制定过程,提供所有系统数据支持的战略集合。通过对数据仓库中数据的分析,可以帮助企业改进业务流程、控制成本、提高产品质量等。

2章 项目需求架构设计

2.1 项目需求分析

   1)项目需求

    (1)用户行为数据采集平台搭建

    (2)业务数据采集平台搭建

    (3)数据仓库维度建模

    (4)分析,设备、会员、商品、地区、活动等电商核心主题,统计的报表指标近100个,完全对比中型公司

    (5)采用即席查询工具,随时进行指标分析

    (6)对集群性能进行监控,发生异常需要报警

    (7)元数据管理

    (8)质量监控

  2)思考

    (1)项目技术如何选型

    (2)框架版本如何选型(Apache、CDH、HDP)

    (3)服务器使用物理机还是云主机

    (4)如何确认集群规模(假设每台服务器8T硬盘)

2.2 项目框架

2.2.1 技术选型

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

  1)数据采集传输:Flume,Kafka,Sqoop,Logstash,DataX

  2)数据存储:Mysql,HDFS,HBase,Redis,MongoDB

  3)数据计算:Hive,Tez,Spark,Flink,Storm

  4)数据查询:Presto,Kylin,Impala,Druid

  5)数据可视化:Echarts,Superset,QuickBI,DataV

  6)任务调度:Azkaban、Oozie

  7)集群监控:Zabbix

  8)元数据管理:Atlas

2.2.2 系统数据流程设计

2.2.3 框架版本选型

  如何选择Apache/CDH/HDP版本?

  (1)Apache:运维麻烦,组件间兼容性需要自己调研。(一般大厂使用,技术实力雄厚,有专业的运维人员)

  (2)CDH:国内使用最多的版本,但CM不开源,今年开始要收费,一个节点1万美金

  (3)HDP:开源,开源进行二次开发,但是没有CDH稳定,国内使用较少

2.2.4 服务器选型

   服务器选择物理机还是云主机

  1)物理机:

    (1)128G内存,20核物理CPU,40线程,8THDD核2TSSD硬盘,戴尔品牌,单台报价4W出头,一般寿命在5年左右

    (2)需要专业的运维人员,平均每月1W,电费、网络、散热、机房等等开销

  2)云主机

    (1)以阿里云为例,差不多相同配置,每年5W

    (2)很多运维工作由阿里云完成,运维相对轻松

  3)企业选择

    (1)金融有钱公司和阿里没有直接冲突的公司选择阿里云

    (2)中小公司、为了融资上市,选择阿里云,拉到融资后再购买物理机

    (3)有长期打算,资金比较足,选择物理机

2.2.5 集群资源规划设计

   1)如何确定集群规模?(假设每台服务器8T磁盘,128G内存)

    (1)每天日活跃用户100万,每人一天平均100条:100万 * 100条 = 1亿条

    (2)每条日志1k左右,每天1亿条:100000000 / 1024 / 1024 = 100G(1G=1024MB,1MB=1024KB)

    (3)半年内不扩容服务器来算:100G * 180天 = 18T (1T=1024G)

    (4)保存3个副本:18T * 3 = 54T

    (5)预留20%~30%Buf :54T / 0.7 = 77T

    (6)服务器数量:77 / 8 = 10台(每台8个T)

  2)若考虑数仓分层,数据采用压缩,则需要重新进行计算

  3)测试集群服务器规划

服务名称

子服务

服务器

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

 

 

Druid

Druid

Kylin

 

 

 

Hbase

HMaster

 

 

HRegionServer

Superset

 

 

 

Atlas

 

 

 

Solr

Jar

 

 

服务数总计

 

18

9

9

3章 数据生成模块

3.1 目标数据

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

3.1.1 页面

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

  1)所有页面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("注册");

  2)所有页面对象类型如下:

sku_id("商品skuId"),
keyword("搜索关键词"),
sku_ids("多个商品skuId"),
activity_id("活动id"),
coupon_id("购物券id");

  3)所有来源类型如下:

promotion("商品推广"),
recommend("算法推荐商品"),
query("查询结果商品"),
activity("促销活动");

3.1.2 事件

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

  1)所有动作类型如下:

favor_add("添加收藏"),
favor_canel("取消收藏"),
cart_add("添加购物车"),
cart_remove("删除购物车"),
cart_add_num("增加购物车商品数量"),
cart_minus_num("减少购物车商品数量"),
trade_add_address("增加收货地址"),
get_coupon("领取优惠券");

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

  2)所有动作目标类型如下:

sku_id("商品"),
coupon_id("购物券");

3.1.3 曝光

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

  1)所有曝光类型如下:

promotion("商品推广"),
recommend("算法推荐商品"),
query("查询结果商品"),
activity("促销活动");

  2)所有曝光对象类型如下:

sku_id("商品skuId"),
activity_id("活动id");

3.1.4 启动

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

  1)所有启动入口类型如下:

icon("图标"),
notification("通知"),
install("安装后启动");

3.1.5 错误

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

3.2 数据埋点

3.2.1 主流埋点方式(了解)

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

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

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

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

3.2.2 埋点数据日志结构

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

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

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

{
  "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  --跳入时间戳
}
普通页面埋点日志格式

  2)启动日志格式(启动日志结构相对简单,主要包含公共信息,启动信息和错误信息)

{
  "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.2.3 埋点数据上报时机

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

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

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

3.3 服务器和JDK准备

3.3.1 服务器准备

  安装如下文档配置步骤,先安装hadoop102主机

  1)修改主机名

hostnamectl --static set-hostname hadoop102

  2)关闭防火墙并设置开机不自启

sudo systemctl stop firewalld
sudo systemctl disable firewalld

  3)修改主机IP、添加网关、DNS

sudo vim /etc/sysconfig/network-scripts/ifcfg-ens33
#修改如下内容
BOOTPROTO=static
ONBOOT=yes
#添加如下内容
IPADDR=192.168.1.102
GATEWAY=192.168.1.2
DNS1=192.168.1.2
DNS2=114.114.114.114
DNS3=8.8.8.8

  4)重启网络

sudo systemctl restart network

  5)配置主机映射

sudo vim /etc/hosts
#添加如下内容
192.168.1.102 hadoop102
192.168.1.103 hadoop103
192.168.1.104 hadoop104

  6)安装 vim

sudo yum install -y vim

  7)根据hadoop102克隆出hadoop103与hadoop104主机

    (1)完成后分别修改主机名

hostnamectl --static set-hostname hadoop103
hostnamectl --static set-hostname hadoop104

    (2)分别修改主机IP

sudo vim /etc/sysconfig/network-scripts/ifcfg-ens33
#修改如下内容
IPADDR=192.168.1.103
#修改如下内容
IPADDR=192.168.1.104

    (3)分别重启网络

sudo systemctl restart network

  8)设置atguigu账号并设置权限(每台主机都设置)

#添加用户
useradd atguigu
#设置密码
passwd atguigu
#赋予权限
sudo vim /etc/sudoers
#添加如下内容
%wheel  ALL=(ALL)       ALL
atguigu ALL=(ALL)       NOPASSWD: ALL

  9)配置SSH免密登录(root账号设置一次,atguigu账号设置一次,每台主机都要做)

#生成密钥(root用户)
ssh-keygen
#复制密钥至主机
ssh-copy-id root@hadoop102
ssh-copy-id root@hadoop103
ssh-copy-id root@hadoop104
#生成密钥(atguigu用户)
ssh-keygen
#复制密钥至主机
ssh-copy-id atguigu@hadoop102
ssh-copy-id atguigu@hadoop103
ssh-copy-id atguigu@hadoop104

  10)使用atguigu登录 Xshell 并在/opt 目录下创建software和module目录,然后修改两个目录的所属权限与所属组(每台主机都设置)

sudo mkdir /opt/software /opt/module
chown atguigu:atguigu /opt/software /opt/module

  11)安装 rsync 同步工具(每台主机都设置)

sudo yum install -y rsync

  12)在/home/atguigu/下创建bin目录,并编写 xsync 同步脚本且赋予其可执行权限

mkdir /home/atguigu/bin
touch xsync
chmod +x /home/atguigu/bin/xsync
#!/bin/bash
if [ $# -lt 1 ]
then 
  echo "参数个数不正确!!!"
  exit
fi

for host in hadoop102 hadoop103 hadoop104
do
  echo "-------------$host---------------------"
  for f in $@
  do
    if [ -e $f ]
    then
      pname=$(cd -P $(dirname $f); pwd)
      name=$(basename $f)
      ssh $host "mkdir -p $pname" 
      rsync -av $pname/$name $host:$pname
    else
      echo "文件不存在"
    fi
  done
done

  13)分发 xsync

xsync /home/atguigu/bin/xsync

3.3.2 JDK准备

  1卸载现有JDK每台主机都执行

sudo rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps

  2)将JDK导入到hadoop102/opt/software文件夹下面

    本博客搭建环境所需的所有资料下载地址:https://pan.baidu.com/s/1ugN13ee7LJdT-bZP8J_nTA   提取码:yuan 

  3解压JDK/opt/module目录下

tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/

  4)重命名

cd /opt/module/
mv jdk1.8.0_212 java

  5配置JDK环境变量

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

sudo vim /etc/profile.d/my_env.sh

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

#JAVA_HOME
export JAVA_HOME=/opt/module/java
export PATH=$PATH:$JAVA_HOME/bin

  (2让环境变量生效

source /etc/profile.d/my_env.sh

  6测试JDK是否安装成功

java -version

  8)分发JDK 

xsync /opt/module/java/

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

sudo /home/atguigu/bin/xsync /etc/profile.d/my_env.sh

  10)分别在hadoop103hadoop104上执行source

source /etc/profile.d/my_env.sh

3.3.3 环境变量配置说明

  Linux的环境变量可在多个文件中配置,如/etc/profile/etc/profile.d/*.sh~/.bashrc~/.bash_profile等,下面说明上述几个文件之间的关系和区别。

  bash的运行模式可分为login shellnon-login shell。

  例如,我们通过终端,输入用户名、密码,登录系统之后,得到就是一个login shell,而当我们执行以下命令ssh hadoop103 command,在hadoop103执行command的就是一个non-login shell。这两种shell的主要区别在于,它们启动时会加载不同的配置文件,login shell启动时会加载/etc/profile~/.bash_profile,~/.bashrcnon-login shell启动时会加载~/.bashrc。而在加载~/.bashrc(实际是~/.bashrc中加载的/etc/bashrc)或/etc/profile时,都会执行如下代码片段,

  因此不管是login shell还是non-login shell,启动时都会加载/etc/profile.d/*.sh中的环境变量。

3.4 模拟数据

3.4.1 使用说明

  1)将application.ymlgmall2020-mock-log-2021-01-22.jarpath.jsonlogback.xml上传到hadoop102/opt/module/applog目录下

    (1)创建applog路径

mkdir /opt/module/applog

    (2)上传文件

  2)配置文件

    (1application.yml文件,可以根据需求生成对应日期的用户行为日志。

vim application.yml
#修改业务日期为当前系统时间
mock.date: "2021-05-08"

    (2path.json,该文件用来配置访问路径,根据需求,可以灵活配置用户点击路径

    (3)logback配置文件,可配置日志生成路径,修改内容如下

<property name="LOG_HOME" value="/opt/module/applog/log" />

  3)分发

xsync /opt/module/applog

  4)生成日志

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

 java -jar gmall2020-mock-log-2021-01-22.jar

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

3.4.2 集群日志生成脚本

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

vim lg.sh

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

#!/bin/bash
for host in hadoop102 hadoop103
do
  echo "---------------------$host-------------------------"
  ssh $host "cd /opt/module/applog; nohup java -jar gmall2020-mock-log-2021-01-22.jar 1>/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)修改脚本执行权限

chmod +x lg.sh

  4)启动脚本

lg.sh

  5)分别hadoop102hadoop103/opt/module/applog/log目录查看生成的数据

4 数据采集模块

4.1 集群所有进程查看脚本

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

vim xcall.sh

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

#!/bin/bash
if [ $# -lt 1 ]
then
  echo "参数个数错误!!!"
  exit
fi

for host in hadoop102 hadoop103 hadoop104
do
  echo "---------------$host $*---------------------"
  ssh $host "$*"
done

  3)修改脚本执行权限

chmod +x xcall.sh

  4)启动脚本

xcall.sh jps

4.2 Hadoop安装

  1)集群规划:

 

服务器hadoop102

服务器hadoop103

服务器hadoop104

HDFS

NameNode

DataNode

DataNode

DataNode

SecondaryNameNode

Yarn

NodeManager

Resourcemanager

NodeManager

NodeManager

  2)上传hadoop-3.1.3.tar.gz和hadoop-lzo-0.4.20.jar至/opt/software目录下(以下操作在hadoop102上)

  3)解压hadoop-3.1.3.tar.gz至/opt/module目录

tar -zxvf /opt/software/hadoop-3.1.3.tar.gz -C /opt/module/

  4)配置环境变量

sudo vim /etc/profile.d/my_env.sh
#HADOOP_HOME
export HADOOP_HOME=/opt/module/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin

  5)source

source /etc/profile.d/my_env.sh

  6)进入/opt/module/hadoop-3.1.3/etc/hadoop修改core-site.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License. See accompanying LICENSE file.
-->

<!-- Put site-specific property overrides in this file. -->

<configuration>
    <!-- 指定NameNode的地址 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop102:8020</value>
</property>
<!-- 指定hadoop数据的存储目录 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/module/hadoop-3.1.3/data</value>
</property>

<!-- 配置HDFS网页登录使用的静态用户为atguigu -->
    <property>
        <name>hadoop.http.staticuser.user</name>
        <value>atguigu</value>
</property>

<!-- 配置该atguigu(superUser)允许通过代理访问的主机节点 -->
    <property>
        <name>hadoop.proxyuser.atguigu.hosts</name>
        <value>*</value>
</property>
<!-- 配置该atguigu(superUser)允许通过代理用户所属组 -->
    <property>
        <name>hadoop.proxyuser.atguigu.groups</name>
        <value>*</value>
</property>
<!-- 配置该atguigu(superUser)允许通过代理的用户-->
    <property>
        <name>hadoop.proxyuser.atguigu.users</name>
        <value>*</value>
</property>

<!-- 添加lzo -->
    <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>

  7)进入/opt/module/hadoop-3.1.3/etc/hadoop修改hdfs-site.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License. See accompanying LICENSE file.
-->

<!-- Put site-specific property overrides in this file. -->

<configuration>
    <!-- nn web端访问地址-->
    <property>
        <name>dfs.namenode.http-address</name>
        <value>hadoop102:9870</value>
    </property>
    
    <!-- 2nn web端访问地址-->
    <property>
        <name>dfs.namenode.secondary.http-address</name>
        <value>hadoop104:9868</value>
    </property>
    
    <!-- 测试环境指定HDFS副本的数量1 -->
    <property>
        <name>dfs.replication</name>
        <value>3</value>
    </property>
</configuration>

  8)进入/opt/module/hadoop-3.1.3/etc/hadoop修改mapred-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License. See accompanying LICENSE file.
-->

<!-- Put site-specific property overrides in this file. -->

<configuration>
    <!-- 指定MapReduce程序运行在Yarn上 -->
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
    <!-- 历史服务器端地址 -->
<property>
    <name>mapreduce.jobhistory.address</name>
    <value>hadoop102:10020</value>
</property>

<!-- 历史服务器web端地址 -->
<property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>hadoop102:19888</value>
</property>
</configuration>

  9)进入/opt/module/hadoop-3.1.3/etc/hadoop修改yarn-site.xml

<?xml version="1.0"?>
<!--
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License. See accompanying LICENSE file.
-->
<configuration>

<!-- Site specific YARN configuration properties -->
    <!-- 指定MR走shuffle -->
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
    
    <!-- 指定ResourceManager的地址-->
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>hadoop103</value>
    </property>
    
    <!-- 环境变量的继承 -->
    <property>
        <name>yarn.nodemanager.env-whitelist</name>
        <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
    </property>
    
    <!-- yarn容器允许分配的最大最小内存 -->
    <property>
        <name>yarn.scheduler.minimum-allocation-mb</name>
        <value>512</value>
    </property>
    <property>
        <name>yarn.scheduler.maximum-allocation-mb</name>
        <value>4096</value>
    </property>
    
    <!-- yarn容器允许管理的物理内存大小 -->
    <property>
        <name>yarn.nodemanager.resource.memory-mb</name>
        <value>4096</value>
    </property>
    <property>
        <name>yarn.nodemanager.resource.cpu-vcores</name>
        <value>2</value>
    </property>    

    <!-- 关闭yarn对物理内存和虚拟内存的限制检查 -->
    <property>
        <name>yarn.nodemanager.pmem-check-enabled</name>
        <value>false</value>
    </property>
    <property>
        <name>yarn.nodemanager.vmem-check-enabled</name>
        <value>false</value>
    </property>
    <!-- 开启日志聚集功能 -->
<property>
    <name>yarn.log-aggregation-enable</name>
    <value>true</value>
</property>

<!-- 设置日志聚集服务器地址 -->
<property>  
    <name>yarn.log.server.url</name>  
    <value>http://hadoop102:19888/jobhistory/logs</value>
</property>

<!-- 设置日志保留时间为7天 -->
<property>
    <name>yarn.log-aggregation.retain-seconds</name>
    <value>604800</value>
</property>
</configuration>

  10)进入/opt/module/hadoop-3.1.3/etc/hadoop修改workers

hadoop102
hadoop103
hadoop104

  11)分发

xsync /opt/module/hadoop-3.1.3/
sudo /home/atguigu/bin/xsync /etc/profile.d/my_env.sh

  12)格式化 namenode

cd /opt/module/hadoop-3.1.3/
bin/hdfs namenode -format

  13)修改静态资源

vim /opt/module/hadoop-3.1.3/share/hadoop/hdfs/webapps/static/dfs-dust.js
//将第61行修改为以下内容
return moment(Number(v)).format('ddd MMM DD HH:mm:ss ZZ YYYY');

  14)在/home/atguigu/bin目录下编写hadoop集群启动脚本hdp.sh

vim /home/atguigu/hdp.sh
#!/bin/bash
if [ $# -ne 1 ]
then
  echo "参数个数错误!!!"
  exit
fi

case $1 in
"start")
  echo "----------------HDFS Start-------------"
  ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/start-dfs.sh"
  echo "----------------Yarn Start-------------"
  ssh hadoop103 "/opt/module/hadoop-3.1.3/sbin/start-yarn.sh"
  echo "----------------historyserver Start----------"
  ssh hadoop102 "/opt/module/hadoop-3.1.3/bin/mapred --daemon start historyserver"
;;
"stop")
  echo "----------------HDFS Stop-------------"
  ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/start-dfs.sh"
  echo "----------------Yarn Stop-------------"
  ssh hadoop103 "/opt/module/hadoop-3.1.3/sbin/start-yarn.sh"
  echo "----------------historyserver Stop----------"
  ssh hadoop102 "/opt/module/hadoop-3.1.3/bin/mapred --daemon stop historyserver"
;;
*)
  echo "参数格式输入错误!!!"
  exit
;;
esac

  15)赋予hdp.sh可执行权限

chmod +x /home/atguigu/bin/hdp.sh

  16)启动集群

hdp.sh start

  17)拷贝hadoop-lzo-0.4.20.jar到/opt/module/hadoop-3.1.3/share/hadoop/common

cp /opt/software/hadoop-lzo-0.4.20.jar /opt/module/hadoop-3.1.3/share/hadoop/common/

  18)分发

xsync /opt/module/hadoop-3.1.3/share/hadoop/common/hadoop-lzo-0.4.20.jar

  19)重启hadoop集群

  20)测试LZO压缩

    (1)在hdfs上的根目录创建/input文件夹并随便上传一些文件

     (2)执行以下案例

hadoop jar /opt/module/hadoop-3.1.3/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

    (3)查看/output

     (4)给 /output 创建索引

hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/common/hadoop-lzo-0.4.20.jar com.hadoop.compression.lzo.DistributedLzoIndexer /output

    (5)再次查看

4.2.1 项目经验HDFS存储目录

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

  2)在hdfs-site.xml文件中配置多目录,注意新挂载磁盘的访问权限问题。HDFSDataNode节点保存数据的路径由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

  2)磁盘间数据均衡

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

hdfs diskbalancer -plan hadoop102

  (2)执行均衡计划

hdfs diskbalancer -execute hadoop102.plan.json

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

hdfs diskbalancer -query hadoop102

  (4)取消均衡任务

hdfs diskbalancer -cancel hadoop102.plan.json

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

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

  (1)环境准备

maven(下载安装,配置环境变量,修改sitting.xml加阿里云镜像)
gcc-c++
zlib-devel
autoconf
automake
libtool
通过yum安装即可,yum -y install gcc-c++ lzo-devel zlib-devel autoconf automake libtool

  (2)下载、安装并编译LZO

wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz
tar -zxvf lzo-2.10.tar.gz
cd lzo-2.10
./configure -prefix=/usr/local/hadoop/lzo/
make
make install

  (3)编译hadoop-lzo源码

下载hadoop-lzo的源码,下载地址:https://github.com/twitter/hadoop-lzo/archive/master.zip

解压之后,修改pom.xml
    <hadoop.current.version>3.1.3</hadoop.current.version>

声明两个临时环境变量
     export C_INCLUDE_PATH=/usr/local/hadoop/lzo/include
     export LIBRARY_PATH=/usr/local/hadoop/lzo/lib

编译
    进入hadoop-lzo-master,执行maven编译命令
    mvn package -Dmaven.test.skip=true

进入target,hadoop-lzo-0.4.21-SNAPSHOT.jar 即编译成功的hadoop-lzo组件

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

  3)同步hadoop-lzo-0.4.20.jarhadoop103、hadoop104

xsync hadoop-lzo-0.4.20.jar

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

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

  5)同步core-site.xmlhadoop103、hadoop104

xsync core-site.xml

  6)启动及查看集群

hdp.sh start
xcall.sh jps

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.lzo200M)上传到集群的根目录

hadoop fs -mkdir /input
hadoop fs -put bigtable.lzo /input

  (2)执行wordcount程序

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

  (3)对上传的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

  (4)再次执行WordCount程序

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文件中增加如下配置,然后分发到hadoop103hadoop104服务器上,并重新启动集群。

<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是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集群写10128M的文件

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
2021-05-08 21:16:39,304 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
2021-05-08 21:16:39,436 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:             Date & time: Sat May 08 21:16:39 CST 2021
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:         Number of files: 10
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:  Total MBytes processed: 1280
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:       Throughput mb/sec: 0.58
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:  Average IO rate mb/sec: 0.59
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:   IO rate std deviation: 0.07
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:      Test exec time sec: 306.78
2021-05-08 21:16:39,436 INFO fs.TestDFSIO:

  2)测试HDFS性能

    测试内容:读取HDFS集群10128M的文件

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
2021-05-08 21:18:19,231 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
2021-05-08 21:18:19,243 INFO fs.TestDFSIO: ----- TestDFSIO ----- : read
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:             Date & time: Sat May 08 21:18:19 CST 2021
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:         Number of files: 10
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:  Total MBytes processed: 1280
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:       Throughput mb/sec: 48.09
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:  Average IO rate mb/sec: 277.82
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:   IO rate std deviation: 273.4
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:      Test exec time sec: 29.48
2021-05-08 21:18:19,243 INFO fs.TestDFSIO:

  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来产生随机数,每个节点运行10Map任务,每个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

4.2.6 项目经验Hadoop参数调优

  1HDFS参数调优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)解决办法:

    内存利用率不够。这个一般是Yarn2个配置造成的,单个任务可以申请的最大内存大小,和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

  1)集群规划

 

服务器hadoop102

服务器hadoop103

服务器hadoop104

Zookeeper

Zookeeper

Zookeeper

Zookeeper

  2)使用Xftp上传apache-zookeeper-3.5.7-bin.tar.gz至/opt/software/目录
  
3)解压至/opt/module

tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/

  4)重命名

mv apache-zookeeper-3.5.7-bin zookeeper

  5)在/opt/module/zookeeper目录下创建zkData文件夹

mkdir /opt/module/zookeeper/zkData

  6)进入zkData创建myid文件

vim /opt/module/zookeeper/zkData/myid
#添加如下内容
2

  7)重命名/opt/module/zookeeper-3.5.7/conf这个目录下的zoo_sample.cfgzoo.cfg

mv zoo_sample.cfg zoo.cfg

  8)修改该配置文件

vim zoo.cfg

#修改数据存储路径配置
dataDir=/opt/module/zookeeper/zkData
#增加如下配置
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

  9)分发

xsync /opt/module/zookeeper/

  10)修改myid文件(hadoop103和hadoop104)

vim /opt/module/zookeeper/zkData/myid

#hadoop103修改为3、hadoop104修改为4
3

  11)编写ZK集群脚本

vim /home/atguigu/bin/zookeeper.sh
#!/bin/bash
if [ $# -ne 1 ]
then
    echo "参数个数错误!!!"
    exit
fi

case $1 in
"start"){
    for i in hadoop102 hadoop103 hadoop104
    do
        echo ---------- zookeeper $i 启动 ------------
        ssh $i "/opt/module/zookeeper/bin/zkServer.sh start"
    done
};;
"stop"){
    for i in hadoop102 hadoop103 hadoop104
    do
        echo ---------- zookeeper $i 停止 ------------    
        ssh $i "/opt/module/zookeeper/bin/zkServer.sh stop"
    done
};;
"status"){
    for i in hadoop102 hadoop103 hadoop104
    do
        echo ---------- zookeeper $i 状态 ------------    
        ssh $i "/opt/module/zookeeper/bin/zkServer.sh status"
    done
};;
*)
    echo "参数输入错误!!!"
    exit
;;
esac

  12)添加可执行权限

chmod +x /home/atguigu/bin/zookeeper.sh

  13)启动集群

zookeeper.sh start

  14)查看集群状态

zookeeper.sh status

4.4 Kafka安装

4.4.1 Kafka集群安装

  1)集群规划

 

服务器hadoop102

服务器hadoop103

服务器hadoop104

Kafka

Kafka

Kafka

Kafka

  2)上传kafka_2.11-2.4.1.tgz至/opt/software/

  3)解压kafka_2.11-2.4.1.tgz至/opt/module/

tar -zxvf /opt/software/kafka_2.11-2.4.1.tgz -C /opt/module/

  4)重命名

cd /opt/module/
mv kafka_2.11-2.4.1 kafka

  5)配置环境变量

sudo vim /etc/profile.d/my_env.sh
#KAFKA_HOME
export KAFKA_HOME=/opt/module/kafka
export PATH=$PATH:$KAFKA_HOME/bin

  6)source

source /etc/profile.d/my_env.sh

  7)修改/opt/module/kafka/config/server.properties配置文件

vim /opt/module/kafka/config/server.properties
#broker的全局唯一编号,不能重复
broker.id=2
#删除topic功能使能
delete.topic.enable=true
#kafka运行日志存放的路径
log.dirs=/opt/module/kafka/logs
#配置连接Zookeeper集群地址
zookeeper.connect=hadoop102:2181,hadoop103:2181,hadoop104:2181/kafka

  8)分发

xsync /opt/module/kafka
sudo /home/atguigu/bin/xsync /etc/profile.d/my_env.sh

  9)修改hadoop103和hadoop104的broker.id为3和4

vim /opt/module/kafka/config/server.properties

  10)编写kafka集群脚本

vim /home/atguigu/bin/kafka.sh
#!/bin/bash
if [ $# -ne 1 ]
then
  echo "参数个数错误!!!"
  exit
fi

case $1 in
"start")
  for host in hadoop102 hadoop103 hadoop104
  do
    echo "-------------------$host kafka Start---------------------"
    ssh $host "/opt/module/kafka/bin/kafka-server-start.sh -daemon /opt/module/kafka/config/server.properties"
  done
;;
"stop")
  for host in hadoop102 hadoop103 hadoop104
  do
    echo "-------------------$host kafka Stop---------------------"
    ssh $host "/opt/module/kafka/bin/kafka-server-stop.sh"
  done
;;
"status")
  for host in hadoop102 hadoop103 hadoop104
  do
    echo "-------------------$host kafka Status---------------------"
    pp=$(ssh $host "ps -ef | grep server.properties | grep -v grep")
    [ "$pp" ] && echo "kafka服务正常" || echo "kafka服务异常或停止"
  done
;;
*)
  echo "参数格式输入错误!!!"
  exit
;;
esac

  11)赋予可执行权限,执行脚本即可

chmod +x /home/atguigu/bin/kafka.sh
/home/atguigu/bin/kafka.sh start

4.4.3 Kafka常用命令

  1)查看Kafka Topic列表

kafka-topics.sh --list --bootstrap-server hadoop102:9092

  2创建Kafka Topic

kafka-topics.sh --create --topic first2 --bootstrap-server hadoop102:9092 --partitions 1 replication-factor 3

  3删除Kafka Topic(最后再删除)

kafka-topics.sh --delete --topic first2 --bootstrap-server hadoop102:9092

  4Kafka生产消息

kafka-console-producer.sh --broker-list hadoop102:9092 --topic first2

  5Kafka消费消息

kafka-console-consumer.sh --topic first2 --bootstrap-server hadoop102:9092 --from-beginning --group aa

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

    --group:消费者组名称,同一个消费者组不会两次消费同一个消息

  6)查看Kafka Topic详情

kafka-topics.sh --describe --topic first2 --bootstrap-server hadoop102:9092

4.4.4 项目经验Kafka压力测试

  1Kafka压测

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

kafka-consumer-perf-test.sh
kafka-producer-perf-test.sh

  2Kafka Producer压力测试

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

kafka-producer-perf-test.sh  --topic producertest --record-size 100 --num-records 100000 --throughput -1 --producer-props bootstrap.servers=hadoop102:9092,hadoop103:9092,hadoop104:9092

    说明:

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

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

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

  (2Kafka会打印下面的信息

100000 records sent, 96618.357488 records/sec (9.21 MB/sec), 97.96 ms avg latency, 315.00 ms max latency, 55 ms 50th, 302 ms 95th, 311 ms 99th, 315 ms 99.9th.

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

  3Kafka Consumer压力测试

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

kafka-consumer-perf-test.sh --broker-list hadoop102:9092,hadoop103:9092,hadoop104:9092 --topic producertest --fetch-size 10000 --messages 10000000 --threads 1

    说明:

      --zookeeper 指定zookeeper的链接信息

      --topic 指定topic的名称

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

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

      --threads 处理数据的线程数,默认10个

    测试结果说明

start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec, rebalance.time.ms, fetch.time.ms, fetch.MB.sec, fetch.nMsg.sec2021-05-09 13:20:25:042, 2021-05-09 13:20:36:546, 19.0830, 1.6588, 200100, 17393.9499, 1620537625278, -1620537613774, -0.0000, -0.0001

    开始测试时间,测试结束数据,共消费数据19.0830MB,吞吐量1.6588MB/s,共消费200100条平均每秒消费17393.9499条。

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

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

4.5 采集日志Flume

4.5.1 日志采集Flume安装

  1)集群规划

 

服务器hadoop102

服务器hadoop103

服务器hadoop104

Flume(采集日志)

Flume

Flume

 

  2)上传apache-flume-1.9.0-bin.tar.gz至/opt/software/

  3)解压apache-flume-1.9.0-bin.tar.gz至/opt/module/

tar -zxvf /opt/software/apache-flume-1.9.0-bin.tar.gz -C /opt/module/

  4)重命名

mv /opt/module/apache-flume-1.9.0-bin /opt/module/flume

  5)删除 /opt/module/flume/lib/guava-11.0.2.jar 以兼容Hadoop 3.1.3

rm -rf /opt/module/flume/lib/guava-11.0.2.jar

  6)配置环境变量

sudo vim /etc/profile.d/my_env.sh
#FLUME_HOME
export FLUME_HOME=/opt/module/flume
export PATH+$PATH:$FLUME_HOME/bin

  7)修改/opt/module/flume/conf/flume-env.sh.template名称

mv /opt/module/flume/conf/flume-env.sh.template /opt/module/flume/conf/flume-env.sh

  8)修改/opt/module/flume/conf/flume-env.sh

vim /opt/module/flume/conf/flume-env.sh
#添加以下内容
export JAVA_HOME=/opt/module/java

  9)分发

xsync /opt/module/flume/
sudo /home/atguigu/bin/xsync /etc/profile.d/my_env.sh

4.5.2 项目经验Flume组件选型

  1Source

  (1Taildir Source相比Exec SourceSpooling Directory Source的优势

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

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

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

  (2batchSize大小如何设置?

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

  2Channel

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

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

4.5.3 日志采集Flume配置

  1)Flume配置分析

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

  2)Flume的具体配置如下:

    /opt/module/flume/job目录下创建file-to-kafka.conf文件

vim /opt/module/flume/job/file_to_kafka.conf
#1、定义agent、source、channel的名称
a1.sources = r1
a1.channels = c1

#2、描述source
a1.sources.r1.type = TAILDIR
#定义断点续传文件
a1.sources.r1.positionFile = /opt/module/flume/position.json
#定义监控的文件组
a1.sources.r1.filegroups = f1
#制定文件组监控的文件
a1.sources.r1.filegroups.f1 = /opt/module/applog/log/app.*
#定义source每个批次采集的数据
a1.sources.r1.batchSize = 100

#3、描述拦截器[过滤非json数据]
#定义拦截器名称
a1.sources.r1.interceptors = i1
#定义拦截器类型
a1.sources.r1.interceptors.i1.type = com.yuange.flume.interceptor.ETLInterceptor$Builder

#4、描述channel
a1.channels.c1.type = org.apache.flume.channel.kafka.KafkaChannel
#指定kafka集群地址
a1.channels.c1.kafka.bootstrap.servers = hadoop102:9092,hadoop103:9092,hadoop104:9092
#指定写入的topic的名称
a1.channels.c1.kafka.topic = applog
#指定数据是否以Event数据格式写入kafka
a1.channels.c1.parseAsFlumeEvent = false

#5、关联source->channel
a1.sources.r1.channels = c1

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

4.5.4 Flume拦截

  1创建Maven工程

  2创建包名:com.yuange.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>
pom.xml

  4)在com.yuange.flume.interceptor包下创建ETLInterceptor类

package com.yuange.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.util.Iterator;
import java.util.List;

public class ETLInterceptor implements Interceptor {
    @Override
    public void initialize() {

    }

    @Override
    public Event intercept(Event event) {
        String json = new String(event.getBody());
        try {
            JSON.parseObject(json);
            return event;
        }catch (Exception e){
            return null;
        }
    }

    @Override
    public List<Event> intercept(List<Event> events) {
        Iterator<Event> iterator = events.iterator();
        while (iterator.hasNext()){
            Event event = iterator.next();
            if (intercept(event) == null){
                iterator.remove();
            }
        }
        return events;
    }

    @Override
    public void close() {

    }

    public static class Builder implements Interceptor.Builder{
        //创建自定义拦截器对象,提供给flume使用
        @Override
        public Interceptor build() {
            return new ETLInterceptor();
        }

        @Override
        public void configure(Context context) {

        }
    }
}
ETLInterceptor.java

  5)打包

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

  7)分发Flumehadoop103、hadoop104

xsync /opt/module/flume/

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

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

vim /home/atguigu/bin/flume-first.sh
#! /bin/bash
#1、判断参数是否传入
if [ $# -lt 1 ]
then
        echo "必须传入参数..."
        exit
fi
#2、根据参数匹配逻辑
case $1 in
"start")
        for host in hadoop102 hadoop103
        do
                echo "--------------------$host flume启动采集---------------------------"
                ssh $host "nohup /opt/module/flume/bin/flume-ng agent -n a1 -c /opt/module/flume/conf/ -f /opt/module/flume/job/file_to_kafka.conf >/opt/module/flume/logs.txt 2>&1 &"
        done
;;
"stop")
        for host in hadoop102 hadoop103
        do
                echo "--------------------$host flume停止采集-----------------------"
                ssh $host "ps -ef |grep file_to_kafka |grep -v grep |awk '{print \$2}'| xargs -n1 kill"
        done
;;
*)
        echo "参数输入错误....."
;;
esac

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

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

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

  2)增加脚本执行权限

chmod +x /home/atguigu/bin/flume-first.sh

  3)采集数据集群启动脚本

flume-first.sh start

  4)在windows系统找到 kafkatool_64bit.exe 双击运行

     操作:点击“Refresh”按钮发现有6733条数据

4.6 消费Kafka数据Flume

    集群规划

 

服务器hadoop102

服务器hadoop103

服务器hadoop104

Flume(消费Kafka

 

 

Flume

4.6.1 项目经验Flume组件选型

  1FileChannelMemoryChannel区别

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

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

    选型:

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

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

  2FileChannel优化

    通过配置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恢复数据

  3SinkHDFS Sink

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

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

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

  (2HDFS小文件处理

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

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

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

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

4.6.2 Flume拦截器

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

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

package com.yuange.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文件夹下面。

  4)分发Flumehadoop103、hadoop104

xsync /opt/module/flume/lib/TestKafka-1.0-SNAPSHOT-jar-with-dependencies.jar

4.6.3 日志消费Flume配置

  1)Flume配置分析

  2)Flume的具体配置如下:

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

vim kafka-to-hdfs.conf
#1、定义agent、channel、source、sink名称
a1.sources = r1
a1.channels = c1
a1.sinks = k1

#2、描述source
a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource
#指定kafka集群地址
a1.sources.r1.kafka.bootstrap.servers = hadoop102:9092,hadoop103:9092
#指定从哪个topic读取数据
a1.sources.r1.kafka.topics = applog
#指定消费者组的id
a1.sources.r1.kafka.consumer.group.id = g1
#指定source从kafka一个批次拉取多少条消息: batchSize<=事务容量<=channel容量
a1.sources.r1.batchSize = 100
#指定消费者组第一个消费topic的数据的时候从哪里开始消费
a1.sources.r1.kafka.consumer.auto.offset.reset = earliest

#3、描述拦截器
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = com.yuange.flume.interceptor.MyTimestampInterceptor$Builder

#4、描述channel
a1.channels.c1.type = file
#指定数据保存在本地磁盘哪个目录
a1.channels.c1.dataDirs = /opt/module/flume/datas
#指定channel内存中event的指针数据
a1.channels.c1.checkpointDir = /opt/module/flume/checkpoint
#指定checkpoint的持久化的间隔时间
a1.channels.c1.checkpointInterval = 5000
#指定channel容量
a1.channels.c1.capacity = 1000000

#5、描述sink
a1.sinks.k1.type = hdfs
#指定数据存储目录
a1.sinks.k1.hdfs.path = hdfs://hadoop102:8020/applog/%Y%m%d
#指定文件的前缀
a1.sinks.k1.hdfs.filePrefix = log-
#指定滚动生成文件的时间间隔
a1.sinks.k1.hdfs.rollInterval = 30
#指定滚动生成文件的大小
a1.sinks.k1.hdfs.rollSize = 132120576
#指定写入多少个event之后滚动生成新文件<一般禁用>
a1.sinks.k1.hdfs.rollCount = 0
#指定sink每个批次从channel拉取多少数据
a1.sinks.k1.hdfs.batchSize = 100
#指定写入hdfs的时候压缩格式
#a1.sinks.k1.hdfs.codeC = lzop
#指定文件写入的是格式 SequenceFile-序列化文件, DataStream-文本文件, CompressedStream-压缩文件
#a1.sinks.k1.hdfs.fileType = CompressedStream
a1.sinks.k1.hdfs.fileType = DataStream

#6、关联source->channel->sink
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

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

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

vim /home/atguigu/bin/flume-second.sh
#! /bin/bash

if [ $# -lt 1 ]
then
        echo "参数个数错误!!!"
        exit
fi

case $1 in
"start")
        for i in hadoop104
        do
                echo " --------启动 $i 消费flume-------"
                ssh $i "nohup /opt/module/flume/bin/flume-ng agent --conf /opt/module/flume/conf/ --conf-file /opt/module/flume/job/kafka-to-hdfs.conf --name a1 >/opt/module/flume/logs.txt 2>&1 &"
        done
;;
"stop")
        for i in hadoop104
        do
                echo " --------停止 $i 消费flume-------"
                ssh $i "ps -ef | grep kafka-to-hdfs | grep -v grep |awk '{print \$2}' | xargs -n1 kill"
        done

;;
*)
        echo "参数格式错误!!!"
        exit
;;
esac

  2)增加脚本执行权限

chmod +x /home/atguigu/bin/flume-second.sh

  3)数据采集第二层集群启动脚本

flume-second.sh start

  4)数据采集第二层集群停止脚本

flume-second.sh stop

4.6.5 项目经验Flume内存优化

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

ERROR hdfs.HDFSEventSink: process failed
java.lang.OutOfMemoryError: GC overhead limit exceeded

  2)解决方案步骤:

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

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

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

xsync /opt/module/flume/conf/flume-env.sh

  3Flume内存参数设置优化

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

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

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

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

4.7.1 数据通道测试

  根据需求分别生成2021-05-11和2021-05-10日期的数据(数据采集脚本必须启动!!!)

  1)修改/opt/module/applog/application.yml中业务日期为2021-05-11

#业务日期
mock.date: "2021-05-11"

  2)执行脚本,生成2021-05-11日志数据

lg.sh

  3)再次修改/opt/module/applog/application.yml中业务日期2021-05-10

#业务日期
mock.date: "2021-05-10"

  4)执行脚本,生成2021-05-10日志数据

lg.sh

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

posted on 2021-05-11 08:57  LZ名約山炮  阅读(542)  评论(0编辑  收藏  举报