Hadoop
Hadoop
Day01
学习方法:
做笔记
MarkDown
有道云笔记
写博客 csdn
官网(Hadoop Hive...Spark,Flink)xxx.apache.org
背单词
大数据相关的博客和论坛
CSDN
about云
36大数据
http://www.36dsj.com/
一、大数据:
1.大数据起源于社交网络
QQ 博客 微信
发展于电商平台
淘宝,京东,一号店
交通大数据
金融行业 银行 保险公司
携程 途牛旅游网站
在线教育网站
游戏网站
DBA
2.***大数据的4V特征
Volume 数据量大 TB PB
1PB(Petabyte 拍字节) = 2^10 TB = 1024 TB
1EB(Exabyte 艾字节) = 2^10 PB = 1024 PB
1ZB(Zettabyte 泽字节) = 2^10 EB = 1024 EB
1YB(YottaByte 尧字节) = 2^10 ZB = 1024 ZB
1BB(Brontobyte ) = 2^10 YB = 1024 YB
1NB(NonaByte ) = 2^10 BB = 1024 BB
1DB(DoggaByte) = 2^10 NB = 1024 NB
Varity 的数据多种多样文本(.log .txt .sql .xml)
Veracity 价值密度低 商业价值高
Velocity 速度快
Hadoop -> 传统的数据统计分析 Mysql
Spark -> Hadoop 在内存快100倍 在磁盘快10倍
3.企业大数据分析的数据来源
(理解) 企业内部
:日志记录(应用服务器 Nginx)
:关系型数据库
外部渠道
:爬虫(Python)
:API(网站埋点技术 jsSDK JavaSDK)
4.大数据应用发展前景
拉勾网 智联招聘
**大数据应用分析
1)统计 -》 数据仓库
2)个性化推荐(预测)
3)机器学习 图形计算
4)人工智能
二、Hadoop 的概念
1.Hadoop的起源及发展史
大数据 Hdoop
Doug Coutting Hadoop之父
2.*** Goolge 三大论文 大数据的三驾马车
Goolge Hadoop
文件系统 GFS -> HDFS
计算MapReduce -> Mapreduce
大表格BigTable -> HBase
http://hadoop.apache.org/
The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models. It is designed to scale up from single servers to thousands of machines, each offering local computation and storage. Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer, so delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures.
3.Apache Hadoop是一个应用java语言实现的软件框架,由大量的廉价的计算机组成的集群中运行海量数据的可靠的,可扩展的分布式并行计算框架,它可以让应用程序支持上千个节点和PB级别的数据。Hadoop是项目的总称,主要是由分布式存储(HDFS)、和分布式并行计算(MapReduce)等组成。
Hadoop Common: The common utilities that support the other Hadoop modules.
Hadoop Distributed File System (HDFS™): A distributed file system that provides high-throughput access to application data.
Hadoop YARN: A framework for job scheduling and cluster resource management.
Hadoop MapReduce: A YARN-based system for parallel processing of large data sets.
4.*** Hadoop的四个模块,也叫四大组件
Hadoop Common 公共模块(支其他Hadoop模块的公用工具,包括FileSystem(面向通用文件系统的抽象类)、远程过程调用(RPC)和序列化库)
Hadoop HDFS 存储数据:一个为访问应用数据提供高吞吐量的分布式文件系统。
Hadoop YARN 管理资源(Hadoop2.x) 一个全局的任务调度与资源管理的框架--》YARN是mareduce的云操作系统
Hadoop MapReduce 并行计算框架:一个基于Yarn的大数据分布式并行计算框架
5.Hadoop的发行版本:
Apache
Cloudera 商业发行版(卖服务)cdh
7.Hadoop的体系架构
HDFS
NameNode(一个集群只有一个):用于保存元数据信息(Namenode将元数据保存在内存中),同时会在硬盘上保留一份。元数据(Filename、副本数,各个副本所在的节点的位置)
学生信息管理系统
书的目录
DataNode:用于具体保存数据的
在HDFS上保存的数据副本数,默认是3个,副本数可以设置
每个班级的学生(本人)
每个章节的具体的内容
SecondaryNameNode: 用于同步元数据信息
YARN
ResourceManager:负责全局的资源管理(Container:硬件资源(CPU,内存,硬盘))
教务处主任(教学资源:教室:实验室 阶梯教室 体育馆)
Nodemanager:负责所在节点上的资源
班主任 机房管理员
Mapreduce
分两个阶段:Map和Reduce 计算框架,编程模型 “分而治之”的思想
100副扑克,少了一张,那么可以找50个人。每个人分2副本扑克
分布式并行计算
三、Hadoop的安装运行模式:
单机模式:
1.单机(本地)运行模式
无需运行任何守护进程,所有程序都在单个JVM上执行,测试用
分布式:
2.伪分布式
将所有的守护进程运行在一个节点
3.集群模式
1)完全分布式
不同的守护进程运行在不同的节点
2)HA
Namenode HA
3)联盟
Hadoop2.x环境搭建
一、系统环境准备工作:
1、把网卡IP设置成静态(NAT模式)
** 首先查看网卡IP
$ ip a 或$ ifconfig (network interfaces configuring)网络接口配置
** 然后配置VPN(Virtual Private Network 虚拟专用网络)
a. 右下角选择"配置VPN"
b. 选择eth0,点击编辑
c. 在IPv4页面设置
方法:手动
添加:地址192.168.122.128 掩码255.255.255.0 网关192.168.122.2
DNS服务器:192.168.122.2, 202.96.209.5
勾选需要IPv4
#202.96.209.5(或133)是上海电信DNS服务器(baidu),8.8.8.8是Google服务器
***配置Notepad的NppFTP来修改文件,协议必需要选择SFTP***
** 插件--NppFTP--勾选"show NppFTP window"
** 注意:文件必需在Linux里建,可以在Windows里改
编辑文件(root)
# vi /etc/sysconfig/network-scripts/ifcfg-eth0
#注意:VPN修改后,文件名会变化,如:ifcfg-Auto_eth0
ONBOOT=yes # 把网卡设置成开机启动
BOOTPROTO=static # 把DHCP改为static,Linux严格区分大小写,一定要注意
IPADDR=192.168.122.128
NETMASK=255.255.255.0
GATEWAY=192.168.122.2 #前三位相同,末位设置为2,是NAT模式特有的做法
设置好后,重启网卡:
# ifup eth0 (若是有问题,将文件中以IPV6开头的行删除)
#Linux中eth0,eth1,eth2分别表示网卡一,网卡二,网卡三 ……
#/etc/sysconfig/network-scripts/ifcfg-eth0文件内容参照如下:
#若是有问题就将IPV6开头的删除
DEVICE="eth0"
BOOTPROTO=static
IPV6INIT="yes"
NM_CONTROLLED="yes"
ONBOOT="yes"
TYPE="Ethernet"
UUID="0faffc60-5eda-421f-9cb9-c90cea321005"
HWADDR=00:0C:29:3D:37:60
IPADDR=192.168.122.128
NETMASK=255.255.255.0
PREFIX=24
GATEWAY=192.168.122.2
DNS1=192.168.122.2
DNS2=202.96.209.5
DEFROUTE=yes
IPV4_FAILURE_FATAL=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
NAME="System eth0"
LAST_CONNECT=1477989881
2、设置DNS
# vi /etc/sysconfig/network-scripts/ifcfg-eth0 (同一个文件)
DNS1=192.168.200.2#第一个DNS设置成跟网关地址一样,NAT模式比较特殊
DNS2=202.96.209.5 上海的DNS
# service network restart #重启network服务,即网络服务
3、修改主机名
** 集群内部的主机名通常都会使用统一的命名格式
** 注意:hadoop里主机名不能使用下划线
gu.com
chao.com
feng.com
# vi /etc/sysconfig/network
HOSTNAME=gu.com
查看主机名:
# hostname
4、关闭Linux防火墙和selinux
** 默认情况下,防火墙只开启了22号端口,会影响集群通讯
# service iptables status
# service iptables stop # 关闭防火墙服务
# chkconfig iptables off # 设置为开机不启动
# chkconfig --list # 列出所有的系统服务
# chkconfig --list | grep iptables
PS:
等级代号指定该系统服务要在哪一个执行等级中开启或关闭。
等级0表示:表示关机,系统默认运行级别不能设置为0,否则不能正常启动、关闭。
等级1表示:单用户模式
等级2表示:无网络连接的多用户命令行模式
等级3表示:有网络连接的多用户命令行模式
等级4表示:等级4保留,一般不用,可以处理一些特殊情况。如笔记本电池用尽时,可以切换到这个模式来做一些设置。
等级5表示:带图形界面的多用户模式
等级6表示:重新启动
# 关闭selinux,是一个安全子系统,它能控制程序只能访问特定文件
# vi /etc/sysconfig/selinux(注意:此文件在notepad中不可见)
SELINUX=disabled # 把enforcing改成disabled
5、添加主机名映射
** 后面需要多次使用主机名
# vi /etc/hosts
在最后一行添加:192.168.122.128gu.com
6、创建普通用户
** 后期所有操作都尽量使用普通用户来进行
# useradd tom #创建用户tom
# passwd tom #设置密码
# echo blue | passwd --stdin tom #--stdin接收系统输入数据
PS:
** 安装rz
# yum install lrzsz -y
Xshell:工具--选项--键盘和鼠标
右键粘贴功能: 修改“右键按钮”为:paste the clipboard contents
选中复制功能:勾选“将选中的内容自动复制到剪贴板”
=============================安装jdk======================================
普通$ tar -zxf jdk-7u67-linux-x64.tar.gz -C ../modules/
配置环境变量
root# vim /etc/profile
#JAVA_HOME export JAVA_HOME=/opt/modules/jdk1.7.0_67
export PATH=$PATH:$JAVA_HOME/bin |
使配置生效
# source /etc/profile
卸载openJDK
# rpm -qa | grep jdk
# rpm -e --nodeps XXX.rpm //不验证依赖进行卸载
1.种:三、配置Hadoop ${HADOOP_HOME}---hadoop的安装目录
解压安装hadoop【注意上传和解压过程中的用户权限问题】
$ tar -zxf hadoop-2.5.0.tar.gz -C /opt/modules/
2.配置hadoop的java环境支持, ${HADOOP_HOME}/etc/hadoop目录下
hadoop-env.sh
mapred-env.sh
yarn-env.sh
在这3个文件中都配置
export JAVA_HOME=/home/gu/ruan/jdk
3.与hdfs相关的配置 ${HADOOP_HOME}/etc/hadoop
1)core-site.xml
========================core-site.xml==========================
<!--NameNode地址,8020是指定进程8020,访问入口 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://gu.com:8020</value>
</property>
<!--hadoop在运行时产生的文件,元数据在本地的存放目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data</value>
</property>
============================================================
2)hdfs-site.xml
=======================hdfs-site.xml==========================
<!--存放到hdfs上的文件的副本数,伪分布式配置为1 -->
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
===========================================================
3)格式化namenode 只格式化一遍,不要重复格式化
${HADOOP_HOME}目录下:
$ bin/hdfs namenode -format
17/03/21 00:34:52 INFO common.Storage: Storage directory /opt/modules/hadoop-2.5.0/data/dfs/name has been successfully formatted.
4)启动hdfs守护进程
$ sbin/hadoop-daemon.sh start namenode //启动namenode进程
$ sbin/hadoop-daemon.sh start datanode //启动datanode
$ jps
3097 Jps
2931 NameNode
3023 DataNode
web访问界面
http://gu.com:50070/
5)HDFS文件系统常用命令
$ bin/hdfs dfs //可以查看所有的dfs相关的操作指令
$ bin/hdfs dfs -ls /
$ bin/hdfs dfs -mkdir -p /input/test
$ bin/hdfs dfs -rmdir /input/test
$ bin/hdfs dfs -put /opt/software/jdk-7u67-linux-x64.tar.gz /input/test
3.配置YARN 任务调度 (Mapreduce) 资源管理(resourcemanager nodemanager)
${HADOOP_HOME}/etc/hadoop目录下配置yarn-site.xml
=======yarn-site.xml =====
<!-- 指定ResorceManager所在服务器的主机名-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>[hostname]</value>
</property>
<!-- 指明在执行MapReduce的时候使用shuffle-->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
====================================
复制并重名模板文件
$ cp etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml
Cp home/gu/ruan/hadoop-2.5.0/etc/hadoop/mapred-site.xml.template home/gu/ruan/hadoop-2.5.0/etc/hadoop/mapred-site.xml
=======mapred-site.xml=====
${HADOOP_HOME}/etc/hadoop目录下配置mapred-site.xml
<!-- 指定MapReduce基于Yarn来运行-->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
=====================================
4.启动hdfs yarn进程
$ sbin/hadoop-daemon.sh start namenode
$ sbin/hadoop-daemon.sh start datanode
$ sbin/yarn-daemon.sh start resourcemanager
$ sbin/yarn-daemon.sh start nodemanager
5.检查hdfs yarn启动状态,即查看守护进程 jps
6.向yarn提交mapreducer任务
1)计算圆周率
$ bin/yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar pi 5 3
2)wordcount词频统计
a.在用户主目录创建一个wordcount.txt
$ vi /home/user01/wordcount.txt
hadoop java
html java
linux hadoop
yarn hadoop
b.上传到hdfs的input目录下
$ bin/hdfs dfs -put ~/wordcoun.txt /input/
c.提交wordcount任务
执行方式
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /input /output
【报错】:再次执行wordcount会提示输出目录已存在
org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://gu.com:8020/output already exists
【报错】:unknowHostException
检查主机映射
【解决办法】
删除hdfs上的输出目录或者重新指定输出目录
【常见错误】:
1:主机名配置错误或者未配置主机名;
2:配置的参数【<name>标签对】错误,<value>标签对参数有空格
3:xml的注释格式错误,标签对未对齐
4:namenode重复格式化
5:修改配置参数未保存,进程未重启
PS:
编译Hadoop(选做,在Windows平台安装hadoop时,或者添加Hadoop一些额外功能时,才需要编译)
** hadoop-2.5.0.tar.gz 编译过后的包
** hadoop-2.5.0-src.tar.gz 没有经过编译的
** 系统必须联网(mvn仓库)
hadoop-2.5.0-src.tar.gz --> hadoop-2.5.0.tar.gz
** 时间比较长,而且对网络条件要求高,只要有一个包maven下载漏掉,就要重新编译,很麻烦(参考编译操作文档)
PS:
一、MapR是MapR Technologies, Inc的一个产品,号称下一代Hadoop,使Hadoop变为一个速度更快、可靠性更高、更易于管理、使用更加方便的分布式计算服务和存储平台,同时性能也不断提高。它将极大的扩大了Hadoop的使用范围和方式。它包含了开源社区的许多流行的工具和功能,例如Hbase、Hive。它还100%和 Apache Hadoop的API兼容。它能够为客户节约一半的硬件资源消耗,使更多的组织能够利用海量数据分析的力量提高竞争优势。目前有两个版本,M3和M5,其中M3是免费版,
M5为收费版。
二、NAT(Network Address Translation)网络地址转换,它是一个IETF标准,允许一个整体以一个公用IP地址出现在Internet上。
顾名思义,它是一种把内部私有网络地址翻译成合法网络IP地址的技术。简单的说,NAT就是在局域网内部网络中使用内部地址,
而当内部节点要与外部网络进行通讯时,就在网关处,将内部地址替换成公用地址,从而在外部公网(internet)上正常使用,
这一功能很好地解决了公共IP地址紧缺的问题。通过这种方法,只申请一个合法IP地址,就把整个局域网中的计算机接入Internet。
内部网计算机用户通常不会意识到NAT的存在。NAT功能通常被集成到路由器、防火墙、ISDN路由器或者单独的NAT设备中。
NAT有三种类型:静态NAT(Static NAT)、动态地址NAT(Pooled NAT)、网络地址端口转换NAPT(Port-Level NAT)。其中,
静态NAT设置起来最为简单和最容易实现的一种,内部网络中的每个主机都被永久映射成外部网络中的某个合法的地址。
在使用的之前 可以将 rm -rf /tmp/*.pid 这样可以避免namenode和datanode的一些异常错误。
8020是为web(50070)界面提供数据流的端口
Hadoop分布环境搭建的步骤: 1).环境准备 静态Ip地址的配置(包括DNS) 主机名称的更改 配置所需的映射 防火墙的关闭 2).JDK的安装 环境的配置 # vi /etc/profile(root用户) 3).hadoop的安装(实际上就是在对应的目录下解压) 环境的配置 hadoop-env.sh mapred-env.sh yarn-env.sh 文件的配置 hdfs-site.xml core-site.xml mapred-site.xml yarn-site.xml 格式化(在没有报错的时候) $ bin/hdfs namenode -format 在命令行开启相对应的进程 Jps检查是否开启 测试环境是否存在问题 Web: http://gu.com:50070/ http://gu.com:8088/ |
2种:
在使用本地模式MapReduce程序运行在本地,启动JVM
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar grep input output 'dfs[a-z.]+'
统计
[hadoop-2.5.0]$ mkdir wcinput
[hadoop-2.5.0]$ cd wcinput
[wcinput]$ touch wc.input
[wcinput]$ vi wc.input
$bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount (统计)wcinput(所需要统计的文件目录) wcoutput(自己命名的在查询时用的到)
[hadoop-2.5.0]$ cat wcoutput/part-r-00000(查看统计结果)
akjfdskhfdsj 1
asdasfd 1
asdfasdfasdkhaudsfsdfajsdvjk 1
asdflahfdsiuhasdkuf 1
asdfnaksdfalkvljkvas 1
fsdfasdfasd 1
hadoop 1
sadfkashdkjfafdskj 1
yarn 1
伪分布式:
配置core-site.xml(配置文件系统hdfs)
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://gu.com:8020</value> </property>
<property> <name>hadoop.tmp.dir</name> <value>/home/gu/linux/hadoop-2.5.0/date/tmp(自己新建的一个临时文件)</value> </property> </configuration> |
hdfs-site.xml 伪分布式配置为1,其他的时候则不需要
<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration> |
对他进行格式化:
bin/hdfs namenode –format
启动namenode:(主节点)
sbin/hadoop-daemon.sh start namenode
启动datanode:(从节点)
sbin/hadoop-daemon.sh start datanode
hdfs的监控界面可以通过50070来查看文件信息
http://gu.com(映射名):50070/dfshealth.html#tab-overview
通过dfs来对hdfs文件系统进行操作
bin/hdfs dfs -mkdir -p /user/gu/
循环查看hdfd 文件目录bin/ hdfs dfs –ls –R /
因为跑的是mapreduce所以再建立一个便于管理
bin/hdfs dfs -mkdir -p /user/ gu/mapreduce/wordcount/input
上传到文件
bin/hdfs dfs -put wcinput/wc.input /user/gu/mapreduce/wordcount/input/
跑一下
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /user/gu/mapreduce/wordcount/input/ /user/gu/mapreduce/wordcount/output
配置yarn
- 配置yarn-site.xml
<property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property>
<!--bendi--> <property> <name>yarn.resourcemanager.hostname</name> <value>gu.com</value> </property> |
配置环境文件yarn-env.sh
Jdk环境的位置 export JAVA_HOME=/home/gu/linux/jdk1.7.0_67
- slaves文件决定了node的主节点从节点的分布
gu.com
- 启动yarn的主节点sbin/yarn-daemon.sh start resourcemanager
从节点sbin/yarn-daemon.sh start nodemanager
Yarn的监控界面
将mapreduce在yarn上运行
- 配置mapred-env.sh
export JAVA_HOME=/home/gu/linux/jdk1.7.0_67
- 配置mapred-site.xml.template重命名为mapred-site.xml
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration> |
3. 输出目录不能存在不然会报错所以要删除它
bin/hdfs dfs -rm -R /user/gu/mapreduce/wordcount/output/
然后跑一下
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar wordcount /user/gu/mapreduce/wordcount/input/ /user/gu/mapreduce/wordcount/output
Jps 查看开启的程序(线程)
======================================================================================
Hadoop 2.x
Common
Hdfs
存储数据
NameNode
存储文件系统的元数据,命名空间namespace
DataNode
存储数据(每一台机器上面)
SecondaryNameNode
辅助NameNode工作,合并两个文件(定时周期性)
客户端先于NameNode进行交互,获取需要读取的文件所在位置。然后再到具体的DataNode去读文件数据 数据流不经过NameNode的
YARN
Hadoop操作系统
Data 操作系统
Container(容器)对资源的隔离
ResouceManager 对整个集群的管理和调度
NodeManager 对每个节点管理的资源与调度
MapReduce
分而治之的思想
map
“分”,大的分成小的,每一份都进行单独的处理
Reduce
“合并”
Input -> map shuffle(排序) ->reduce ->output
分布式并行的计算框架
运行模式:
本地模式上(小数据上)
Yarn模式上
bin/hdfs(脚本) dfs(运行文件系统的命令)
查看自带的一些案例
bin/yarn jar share/hadoo[p/mapreduce/hadoop-mapreduce-examples-2.5.0.jar
mapreduce默认功能排序升序
测试程序:
Hadoop为MapReduce提供的三个程序ckiruo程序
teragen :生成数据
terasort:对数据进行排序
teravalidate:验证排序的结果
==================================问题====================================================
在格式化时出错:$ bin/hdfs namenode –format
- 配置文件错误(在文件格式化时会先读取core-site.xml配置文件)
- 主机名与IP地址的映射问题
- NameNode启动出错
需要查看日志信息[hadoop]$ll /logs
More 翻页查看 以log结尾的文件
Tail:文件的末尾
Yarn的历史服务器
需要启动一下
$ sbin/mr-jobhistory-daemon.sh start historyserver
Log Aggregation
日志聚集
应用运行完成以后,将日志信息上传到HDFS系统上,
需要配置yarn-site.xml文件
<!--aggregation log--> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <!--log save time--> <property> <name>yarn.log-aggregation.retain-seconds</name> <value>640200(秒默认-1永久保存)</value> </property> |
配置完成后需要重启一下
关闭
sbin/yarn-daemon.sh stop resourcemanager
sbin/yarn-daemon.sh stop nodemanager
sbin/mr-jobhistory-daemon.sh stop historyserver
开启
sbin/yarn-daemon.sh start resourcemanager
sbin/yarn-daemon.sh start nodemanager
sbin/mr-jobhistory-daemon.sh start historyserver
============================启动方式================================
各个服务组件逐一启动
hdfs
hadoop-daemon.sh start|stop namenode|datanode|secondarynamenode
yaen
yarn-daemon.sh staret|stop resourcemanager|nodemanager
mapreduce
mr-historyserver-deamon.sh start|stop historyserver
脚本
各个模块分开启动所以要配置ssh(通过ssh来实现)
(sbin/start.sh)
Hdfs start-dfs.sh stop-dfs.sh yarn start-yarn.sh stop-yarn.sh |
需要配置一下
脚本是在主节点上运行的
配置SSH无秘钥登录
在根目录下的.shh目录中
生成公钥 ssh-keygen –t rea
指定用户使用公钥
ssh-copy-id (hostname)
全部启动或停止(不推荐)
Start-all.sh
Stop-all.sh
==============================总结============================================
守护进程
HDFS
NameNode core-site.xml <property> <name>fs.defaultFS</name> <value>hdfs://guyu.com:8020</value> </property> |
DataNode slaves guyu.com hdfs-site.xml <property> <name>dfs.namenode.secondary.http-address </name> <value>hdfs://guyu.com:50090</value> </property> |
7.配置日志聚合
=======mapred-site.xml=========
**追加到原来配置和后面
<property>
<name>mapreduce.jobhistory.address</name>
<!--配置实际的主机名和端口-->
<value>[hostname]:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>[hostname]:19888</value>
</property>
==============yarn-site.xml=======
<!--启用日志聚合功能-->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<!--日志保存时间-->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
8.停止所有进程重新启动,以便配置文件生效
1)停止进程
$ sbin/hadoop-daemon.sh stop namenode
$ sbin/hadoop-daemon.sh stop datanode
$ sbin/yarn-daemon.sh stop resourcemanager
$ sbin/yarn-daemon.sh stop nodemanager
2)启动进程
$ sbin/hadoop-daemon.sh start namenode
$ sbin/hadoop-daemon.sh start datanode
$ sbin/yarn-daemon.sh start resourcemanager
$ sbin/yarn-daemon.sh start nodemanager
3)启动历史
启动历史服务
sbin/mr-jobhistory-daemon.sh start historyserver
4)查看守护进程
28904 ResourceManager
28724 NameNode
28808 DataNode
29152 NodeManager
29304 JobHistoryServer
30561 Jps
查看hdfs的web界面
http://gu.com:50070
28724 NameNode
28808 DataNode
查看yarn的web访问界面
http://gu.com:8088
28904 ResourceManager
28724 NameNode
28808 DataNode
29152 NodeManager
查看历史日志的web访问界面
http://gu.com:19888
28904 ResourceManager
28724 NameNode
28808 DataNode
29152 NodeManager
29304 JobHistoryServer
Day02
===========================HDFS================================================
HDFS(Hadoop Distributed File System)
** block:(见图)
** HDFS把文件划分成block存储在不同节点上
--默认128M(以前是64M,今后可能会变为256M)
--dfs.blocksize属性(hdfs-site.xml)
--该属性应该由文件大小的数值分布来决定,比如80%的文件大小为200M左右,那么该值设定为256M或者128就比较合适
另如,大都是G级单位大小的文件,该值就应该尽量设置的大些
** 如果一个文件大小只有1M,它实际占用的空间也是1M,并非128M,并不会浪费空间
client(1M) --> namenode(128M逻辑空间) --> datanode(1M实际占用空间)
** 遵循:一次写入多次读取
** namenode(一台)
--存储和管理整个文件系统的元数据,目录和文件的元数据会被持久化保存
--管理文件块和datanode节点的对应关系,该数据保存在内存中,
记录一个block的信息大约需要0.15K,因此内存的大小,会限制能够存储的文件的总数
--整个文件系统集群的访问入口,无论读写数据,都要首先访问namenode
在namenode上找到了对应的datanode,数据读写就不再需要经过namenode
--监听datanode节点的存活状态
** datanode(多台)
--以块(block)的形式存储数据
--默认每个块有三个副本(包括自身),都是存储在不同的节点
-- 向namenode发送心跳信息(默认3s),超时则认为该节点不可用(默认超过10m)
一旦发生,namenode会复制该节点上的所有block到其他节点
--向namenode发送存储的所有块的信息
--真正响应客户端数据读写请求
Hadoop默认block副本存放策略(分布式系统默认为3,伪分布式只能是1)
官方说法:
** 第一个副本放在本机架某一个datanode节点
** 第二个副本放在同一机架另外一个datanode节点
** 第三个副本放在另外一个机架的节点(离架)
参见:http://hadoop.apache.org/docs/r2.5.2/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
(For the common case, when the replication factor is three, HDFS’s placement policy is to put
one replica on one node in the local rack/机架, another on a different node in the local rack, and the last on a different node in a different rack. )
另外一种说法(Hadoop权威指南):
** 第一个副本放在运行客户端程序的节点,如果该节点位于集群外,就随机选择一个节点
** 第二个副本放在和第一个副本不同机架的随机节点(离架)
** 第三个副本放在与第二副本同一机架的随机节点
** 如果需要存放其他副本,则在集群中随机选择其他节点,系统会尽量避免过多副本集中在同一个机架的现象
-- 其实这两种说法类似,都是一个机架放一个,另外一个机架放两个,其他随机存放
-- 客户端读取副本: 就近原则
----------------------------------------
NameNode元数据(见图)
** fsimage文件系统镜像
** edits 编辑日志
client操作行为: put、rm... ==> 记录到edits文件(变化的元数据)
-- 存放位置由dfs.namenode.name.dir属性(hdfs-site.xml)决定,
默认为/opt/modules/hadoop-2.5.0/data(即${hadoop.tmp.dir})/dfs/name,可以查看
-- 类似的,数据存放位置由dfs.datanode.data.dir属性决定,默认为file://${hadoop.tmp.dir}/dfs/data
-- 回顾:hadoop.tmp.dir在core-site.xml(见上一章)
NameNode启动过程
** 加载fsimage,并重新执行edits文件,然后加载到内存
** 如果edits文件比较大,合并会非常消耗时间
** 解决方法:通过Secondarynamenode合并
** 等待dataNode发送block report(块报告)到namenode
** 等待过程中,整个HDFS进入安全模式(safemode)
SecondaryNamenode
** 辅助Namenode,进行fsiamge和edits文件合并
** 避免Namenode下一次重启fsiamge和edits合并时间过长问题
** SecondaryNamenode不是namnode的热备
安全模式safemode
** 整个文件系统只能读,不能写
** 为什么要设计一个安全模式? 保证数据的完整和安全性
** 什么条件下我们会进入安全模式
** namenode启动过程中
** 使用命令手动进入(如:维护阶段)
** NameNode重启时,进入安全模式,DataNode需要向NameNode发送块的信息,NameNode只有当整个文件系统中99.9%
(可以通过dfs.namenode.safemode.threshold-pct属性配置)的块满足最小副本要求,才会自动退出安全模式。
** 假设我们设置的副本数(dfs.replication属性)是5,那么在dataNode上,每个块就应该有5个副本存在,假设现在
只存在3个副本,那么比率就是3/5=0.6,明显小于0.999,因此系统会自动的复制副本到其他dataNode,直到至少
99.9%的块都有5个副本,才会自动退出安全模式。
** 同样,如果系统中有8个副本,超过我们设定的5个副本,那么系统也会删除多余的3个副本。
查看安全模式
$ bin/hdfs dfsadmin -safemode get
进入安全模式
$ bin/hdfs dfsadmin -safemode enter
离开安全模式
$ bin/hdfs dfsadmin -safemode leave
-----------------------------------
HDFS里面常见的SHELL操作命令
$ bin/hdfs dfs
Usage: hadoop fs [generic options]
[-cat [-ignoreCrc] <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-cp [-f] [-p | -p[topax]] <src> ... <dst>]
[-du [-s] [-h] <path> ...]
[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-ls [-d] [-h] [-R] [<path> ...]]
[-mkdir [-p] <path> ...]
[-mv <src> ... <dst>]
[-put [-f] [-p] <localsrc> ... <dst>]
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
[-text [-ignoreCrc] <src> ...]
例子:
上传文件:(测试HDFS)
#随便创建一个文件a.txt,测试用
$ vi a.txt
# 打开网页,Utilities--Browse file system
$ hdfs dfs -mkdir /input2 #在HDFS上创建文件夹,没有类似-cd进入目录的参数
$ hdfs dfs -mkdir -p /aaa/bbb/ccc #级联创建目录
$ hdfs dfs -ls / #查看
$ hdfs dfs -put a.txt /input #把本地文件拷到HDFS
$ hdfs dfs -cat /input2/a.txt #查看文件
$ hdfs dfs -text /input2/a* #同上,查看文件内容(可以查看非纯文本格式文件)
$ hdfs dfs -rm /input2/a.txt #删除文件
$ hdfs dfs -rmr /input? #递归删除文件夹和里面的文件,推荐使用'-rm -r'格式;单字符通配符'?'
$ hdfs dfs -help
PS:
# hadoop fs :可以跨文件系统操作,到了2.x版本,分成hdfs和yarn两个命令
# hadoop dfs :功能有限,不赞成使用(Deprecated)
$ hadoop fs -mkdir /input2 #用法和'hdfs dfs'类似
$ hadoop fs -ls /
$ hadoop fs -put b.txt /input2
$ hadoop fs -cat /input2/b.txt
$ hadoop fs -rm /input2/b.txt
$ hadoop fs -rmr /input2
$ hadoop fs -help
----日志-------------------------------------
1.HDFS深入学习
2.Namenode的启动流程和元数据的合并
3.HDFS的读写流程和存储机制(重点)
4.HDFS的Java API
一、HDFS深入
1、namenode 和 datanode功能
【namenode】
接收用户操作请求 维护文件系统的目录结构 管理文件与block之间关系,block与datanode之间关系 namenode管理:namenode支持对HDFS中的目录、文件和块做类似文件系统的创建、修改、删除、列表文件和目录等基本操作。 块存储管理 在整个HDFS集群中有且只有唯一一个处于active状态namenode节点,该节点负责对这个命名空间(HDFS)进行管理
【datanode】
存储文件 文件被分成block存储在磁盘上 为保证数据安全,文件会有多个副本 namenode和client的指令进行存储或者检索block,并且周期性的向namenode节点报告它存了哪些文件的block
2.NameNode的启动流程和元数据合并流程
NameNode的元数据信息先往edits文件中写,当edits文件达到一定的阈值(3600秒或大小到64M)的时候,会开启合并的流程。
合并流程:
1.当开始合并的时候,SecondaryNameNode会把edits和fsimage拷贝到自己服务器所在内存中,开始合并,合并生成一个名为fsimage.ckpt的文件。
2.将fsimage.ckpt文件拷贝到NameNode上,成功后,再删除原有的fsimage,并将fsimage.ckpt文件重命名为fsimage。
3.当SecondaryNameNode将edits和fsimage拷贝走之后,NameNode会立刻生成一个edits.new文件,用于记录新来的元数据,当合并完成之后,原有的edits文件才会被删除,并将edits.new文件重命名为edits文件,开启下一轮流程。
====core-site.xml=====
<property>
<name>fs.checkpoint.period</name>
<value>3600</value>
<description>The number of seconds between two periodic checkpoints.</description>
</property>
<property>
<name>fs.checkpoint.size</name>
<value>67108864</value>
<description>The size of the current edit log (in bytes) that triggers
a periodic checkpoint even if the fs.checkpoint.period hasn’t expired.</description>
</property>
【安全模式 safemode】
Namenode的一种状态,启动时会自动进入安全模式,在安全模式,文件系统不允许有任何修改,“只读不写”。目的,是在系统启动时检查各个DataNode上数据的有效性。
//手动进入安全模式
bin/hdfs dfsadmin -safemode enter
//手动离开安全模式
$ bin/hdfs dfsadmin -safemode leave
3、HDFS的特点
优点:
1)处理超大文件
这里的超大文件通常是指百MB、数百TB大小的文件。目前在实际应用中,HDFS已经能用来存储管理PB级的数据了。
2)流式的访问数据
*** HDFS的设计建立在更多地响应"一次写入、多次读取"任务的基础上。这意味着一个数据集一旦由数据源生成,就会被复制分发到不同的存储节点中,然后响应各种各样的数据分析任务请求。在多数情况下,分析任务都会涉及数据集中的大部分数据,也就是说,对HDFS来说,请求读取整个数据集要比读取一条记录更加高效。
3)运行于廉价的商用机器集群上
Hadoop设计对硬件需求比较低,只须运行在低廉的商用硬件集群上,而无需昂贵的高可用性机器上。廉价的商用机也就意味着大型集群中出现节点故障情况的概率非常高。这就要求设计HDFS时要充分考虑数据的可靠性,安全性及高可用性。
缺点:
1)不适合低延迟数据访问
如果要处理一些用户要求时间比较短的低延迟应用请求,则HDFS不适合。HDFS是为了处理大型数据集分析任务的,主要是为达到高的数据吞吐量而设计的,这就可能要求以高延迟作为代价。
2)无法高效存储大量小文件
因为Namenode把文件系统的元数据放置在内存中,所以文件系统所能容纳的文件数目是由Namenode的内存大小来决定。一般来说,每一个文件、文件夹和Block需要占据150字节左右的空间,所以,如果你有100万个文件,每一个占据一个Block,你就至少需要300MB内存。当前来说,数百万的文件还是可行的,当扩展到数十亿时,对于当前的硬件水平来说就没法实现了。还有一个问题就是,因为Map task的数量是由splits来决定的,所以用MR处理大量的小文件时,就会产生过多的Maptask,线程管理开销将会增加作业时间。举个例子,处理10000M的文件,若每个split为1M,那就会有10000个Maptasks,会有很大的线程开销;若每个split为100M,则只有100个Maptasks,每个Maptask将会有更多的事情做,而线程的管理开销也将减小很多。
3)不支持多用户写入及任意修改文件
在HDFS的一个文件中只有一个写入者,而且写操作只能在文件末尾完成,即只能执行追加操作。目前HDFS还不支持多个用户对同一文件的写操作,以及在文件任意位置进行修改。
二、HDFS的读写流程
在hdfs中,将数据存入hdfs的时候,会把数据分成一个一个的block,在hadoop2.x中,一个block默认是128M
rack1rack2rack3
NNDN3DN6
DN1DN4DN7
DN2DN5DN8
File:200M
2个block
block1:128M
block2:72M
流式写入:
1.将block1分成一个一个的package,将package1发送给DN1
2.DN1接受完package1,自己存一份,再将package1发送给DN2
同时,接收client发送来的package2
3.DN2接收完package1,自己存一份,再将package1发送给DN4
...
4.当block1接收完毕,DN1,DN2,DN4向NN汇报消息(接收完毕),DN1再向client汇报block1接收完毕,于是,client开始发送block2.
5....
hdfs读取
1.client会想NameNode发送读取请求,NameNode会将元数据查出来,每一个数据存在的位置发给client
2.client会优先从本地去读取数据,如果本地不存在数据,会
从元数据记录的第一个存储位置开始读取
三、搭建Linux环境的Java开发(Eclipse + maven)
1.Java 安装 配置环境变量
2.Maven 管理工程,管理依赖包(jar包)
1)上传并解压apache-maven安装包
$ tar -zxf apache-maven-3.0.5-bin.tar.gz -C ../modules/
2)配置环境变量
vi /etc/profile
# MAVEN_HOME
export MAVEN_HOME=/opt/modules/apache-maven-3.0.5
export PATH=$PATH:$MAVEN_HOME/bin
3)使配置文件生效
$ source /etc/profile
4)检查配置是否正确
$ mvn --v
Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 21:51:28+0800)
3.安装Eclipse
1)上传并解压Eclipse安装包
2)启动Eclipse
//进入eclipse安装目录
$ cd /opt/software/eclipse
//启动
./eclipse
3)
4)进入maven安装目录
cd /opt/modules/apache-maven-3.0.5/conf
vi settings.xml
<localRepository>/home/user01/.m2/repository</localRepository>
5)拷贝settings.xml到/home/user01/.m2
cp /opt/modules/apache-maven-3.0.5/conf/settings.xml ~/.m2
6)上传repository.tar.gz到~/.m2
tar -zxf repository.tar.gz -C ./
***顺序: 一定要先替换repository中的jar文件,然后创建maven工程,接下来修改porm.xml增加<dependency>依赖信息
四、Windows下Eclispe远程开发Mapreduce程序
1.安装插件
1).将hadoop-eclipse-plugin-2.6.0.jar 拷贝到${MyEclispe_HOME} /plugins
2).打开MyEclispe,菜单栏->windows->Preferneces->Hadoop MapReduce
2.Windows安装hadoop
1)解压hadoop-2.5.0.tar.gz到D:/根目录
右键WinRar--》属性--》兼容性-》勾选 以管理员运行此程序
打开==》浏览到到hadoop-2.5.0.tar.gz ==>解压到 D:/根目录
2)配置hadoop的环境变量
HADOOP_HOME=【hadoop的解压目录】 //新建项
Path=%HADOOP_HOME%\bin;//在原有配置的最前面
;%HADOOP_HOME%\bin //在原有配置的最后面
;%HADOOP_HOME%\bin; //在原有位置的中间插入
cmd命令提示符
hadoop -h
Error: JAVA_HOME is incorrectly set.
Please update D:\green\hadoop-2.5.0\conf\hadoop-env.cmd
Definde Hadoop Location
3.配置插件参数
Mavreduce(V2)
host:[hostname]
port:8032 //resourcemanager 的默认端口号
DFS Master
host:[hostname]
port:8020
4.拷贝winutils.exe 和hadoop.dll到${hadoop_HOME}/bin
5.单独拷贝hadoop.dll到C:\Windows\System32
6.创建工程的两种方式
1)使用插件,自动导入jar包,使用模板创建mapper reducer
driver类
2)创建maven工程
2-1)解压apache-maven-3.0.5.tar.gz
2-2) 配置maven环境变量
MAVEN_HOME=[maven的解压目录]
path=%MAVEN_HOME%/bin
2-3)命令提示符 mvn --v
Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 21:51:28+0800)
3)修改apache-maven-3.0.5\conf\settings.xml
<localRepository>C:\Users\Administrator\.m2\repository</localRepository>
4)解压repository.tar.gz到settings.xml配置文件中指定的repository
5)配置使用自己解压的maven
6)将${hadoop_Home}/ect/hadoop/log4j.properties拷贝到项目的src目录
在linux中的hadoop安装目录下的etc/hadoop/hdfs-site.xml添加如下配置
,重启HDFS的进程
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
五、Windows下Eclispe远程开发Mapreduce程序
1.安装插件
1).将hadoop-eclipse-plugin-2.6.0.jar 拷贝到${MyEclispe_HOME} /plugins
2).打开MyEclispe,菜单栏->windows->Preferneces->Hadoop MapReduce
2.Windows安装hadoop
1)解压hadoop-2.5.0.tar.gz到D:/根目录
右键WinRar--》属性--》兼容性-》勾选 以管理员运行此程序
打开==》浏览到到hadoop-2.5.0.tar.gz ==>解压到 D:/根目录
2)配置hadoop的环境变量
HADOOP_HOME=【hadoop的解压目录】 //新建项
Path=%HADOOP_HOME%\bin;//在原有配置的最前面
;%HADOOP_HOME%\bin //在原有配置的最后面
;%HADOOP_HOME%\bin; //在原有位置的中间插入
cmd命令提示符 hadoop -h
Error: JAVA_HOME is incorrectly set. Please update D:\green\hadoop-2.5.0\conf\hadoop-env.cmd
Definde Hadoop Location
|
3.配置插件参数
Mavreduce(V2)
host:[hostname]
port:8032 //resourcemanager 的默认端口号
DFS Master
host:[hostname]
port:8020
4.拷贝winutils.exe 和hadoop.dll到${hadoop_HOME}/bin
5.单独拷贝hadoop.dll到C:\Windows\System32
6.创建工程的两种方式
1)使用插件,自动导入jar包,使用模板创建mapper reducer
driver类
2)创建maven工程
2-1)解压apache-maven-3.0.5.tar.gz
2-2) 配置maven环境变量
MAVEN_HOME=[maven的解压目录]
path=%MAVEN_HOME%/bin
2-3)命令提示符 mvn --v
Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 21:51:28+0800)
3)修改apache-maven-3.0.5\conf\settings.xml
<localRepository>C:\Users\Administrator\.m2\repository</localRepository>
4)解压repository.tar.gz到settings.xml配置文件中指定的repository
5)配置使用自己解压的maven
6)将${hadoop_Home}/ect/hadoop/log4j.properties拷贝到项目的src目录
在linux中的hadoop安装目录下的etc/hadoop/hdfs-site.xml添加如下配置
,重启HDFS的进程
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
Day03
MapReduce(重点)
一、Yarn的基本流程(执行流程)
1.client向yarn提交job,首先找ResourceManager分配资源(CPU 内存),
2.ResourceManager开启一个Container,在Container中运行一个Application manager
3.Application manager找一台nodemanager启动Application master,计算任务所需的计算
4.Application master向Application manager(Yarn)申请运行任务所需的资源
5.Resource scheduler将资源封装发给Application master
6.Application master将获取到的资源分配给各个nodemanager
7.各个nodemanager得到任务和资源开始执行map task
8.map task执行结束后,开始执行reduce task
9.map task和 reduce task将执行结果反馈给Application master
10.Application master将任务执行的结果反馈Application manager
mapreduce
** 分布式离线计算模型
** 周期性(每天、每周、每月)分析历史数据
** Mapreduce分为两个阶段
** map阶段: 找出关键数据,会产生多个mapper
默认情况,一个split对应一个mapper,一个block对应一个mapper
** reduce阶段: 把map阶段运行的结果进行合并
例如:一个100G文件:
被分隔成多个block,分散存放在不同的datanode(通常一个节点即是datanode又是nodemanager)
这些nodemanager会为每个split启动一个mapper
** Input --> map --> reduce --> output
** 整个过程数据流都是键值对
====wordcount=========================================================
以此例分析Mapreduce:
需求:单词统计,分隔符是\t
hadoopmapreduce
sparkstorm
maphadoopmapreduce
reducestormhadoop
hbasemapstorm
** map 输入
** 按行读取数据,然后转换成key-value
<0,hadoopmapreduce>
<15,sparkstorm>
<26,maphadoopmapreduce>
<40,reducestormhadoop>
<50,hbasemapstorm>
** map 输出
<hadoop,1> <mapreduce,1> <spark,1> <storm,1> <map,1> <hadoop,1> ...
** 中间结果临时存储在本地目录,而非HDFS
** reduce
** 从相关nodemanager拉取map输出的结果
** 运行reduce函数
** 输入
<hadoop,(1,1,1)> <storm,(1,1,1)> <hbase,1> ...
** 输出
hadoop3
storm3
hbase1 ...
** 结果写入HDFS
hadoop3
storm3
hbase1 ...
二、MapRedcue
分布式并行计算框架 分而治之的思想
编程模型
bin/hadoop jar *****.jar /input/wc.txt /out/
1.一个简单的MapRedcue包含两个过程,一个Map阶段(map 映射),一个Reduce(化简)阶段
2.第一个阶段Map Task,并发的各司其职的读取,完全并行
3.第二个阶段Redcue Task,处理的数据要依赖于map阶段 reduce个数少于map个数
4.整个过程是以key value形式进行数据传递
input(/input/wc.txt) -》 Map Task -》 Reduce task -》 out(/out)
=====input=======================
输入源文件/input/wc.txt
hadoop java
namenode java
xml html
spark
=====map Task(一行一行的读取)
hadoop java -> <0, hadoop java>
namenode java -> <10, namenode java>
用户逻辑
str[]=line.split(" ")
<str[0],1> -> <hadoop,1>
<str[1],1> -> <java,1 >
......
Context 上下文
=====shuffle(洗牌)==========================
分区:决定map阶段的<key value>交给哪个reduce处理
分组: <key,list[1,1,1,1...]>
=======Redcue Task =====================
<hadoop,n>
Context 上下文
=====out(/out)
hadoop 1
java 2
....
package mapReduce;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/**
* hadoop专门封装的数据类型,是HDFS的序列化接口 long -> LongWritable String -> Text
*
* @author Administrator
*
*/
public class WordCountMR extends Configured implements Tool {
/**
* LongWritable,Text -> 文件每一行内容偏移量 每一行的内容
* Text,IntWritable -> 每一行每个单词 1
* @author Administrator
*/
public static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
/**
* Context 上下文 将map输出的key value 发给reduce的输入
* /input/wordcount.txt
* 一行一行读进来 Mapper按一行一行的处理
* key LongWritable的每一行的偏移量
* vaue Text类型每一行的内容 hadoop java
*/
private Text mapOuoputKey = new Text();
private IntWritable mapOutputValue = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {
//将Text类型的内容转化成String类型
String line = value.toString();
//将String类型的每一行内容按照空格切分为String
String[] strs = line.split(",");
/**
* 遍历数组将每个Text类型的元素作为map输出的key
* 将IntWritable类型的1作为map输出的value
*/
for(String str : strs){
mapOuoputKey.set(str);
context.write(mapOuoputKey, mapOutputValue);
}
}
}
public static class wordCountReducer extends
Reducer<Text,IntWritable, Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context)
throws IOException, InterruptedException {
//定义临时变量 用来接收相同单词出现个数的总和
int sum = 0;
for(IntWritable value : values){
System.out.print(value.toString()+"\t");
sum += value.get();
}
/**
* context 将统计结果输出到结果文件中
*/
context.write(key, new IntWritable(sum));
}
}
public int run(String[] args) throws Exception {
//1.获取hadoop配置信息
Configuration conf = new Configuration();
//2.生成job
Job job = Job.getInstance(
conf,
this.getClass().getName()
);
//打成jar包并指定jar包所在路径
job.setJarByClass(getClass());
//3.设置job的内容
// inputDir -> map -> reduce -> outPutdir
//3.1 指定输入路径
Path inPath = new Path(args[0]);
FileInputFormat.setInputPaths(job, inPath);
//3.2 map阶段
job.setMapperClass(WordCountMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//3.3 reduce阶段
job.setReducerClass(wordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//3.4 指定输出路径
Path outPath = new Path(args[1]);
FileSystem fs = outPath.getFileSystem(conf);
if(fs.exists(outPath)){
fs.delete(outPath, true);
}
FileOutputFormat.setOutputPath(job, outPath);
//4.提交job运行并得到结果
boolean isSuccess = job.waitForCompletion(true);
return isSuccess ? 0 : 1;
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
args = new String[]{
"hdfs://apache.bigdata.com:8020/input/wc.txt",
"hdfs://apache.bigdata.com:8020/output"
};
int status = ToolRunner.run(conf , new WordCountMR() , args);
System.exit(status);
}
}
1、(可选)
创建"Source Folder":src/main/resources目录,用来存放core-site.xml等
拷贝log4j.properties
$ cp /opt/modules/hadoop-2.5.0/etc/hadoop/log4j.properties /home/tom/workspace/myhdfs/src/main/resources
2、编写代码
Hadoop常用类型:
IntWritableLongWritable Text NullWritable
package com.myblue.myhdfs;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCountMapReduce{
//mapper
public static class WordCountMapper extends
Mapper<LongWritable, Text, Text, LongWritable> {
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//输入行
System.out.println(key.get());
String lineValue = value.toString();
String[] splits = lineValue.split("\t");
Text mapOutputKey = new Text(); //输出键
LongWritable mapOutputValue = new LongWritable(1); //输出值,本例恒为1
for (String s : splits) {
mapOutputKey.set(s);
context.write(mapOutputKey, mapOutputValue);
}
}
}
//reducer
public static class WordCountReducer extends
Reducer<Text, LongWritable, Text, LongWritable> {
protected void reduce(Text key, Iterable<LongWritable> values,
Context context) throws IOException, InterruptedException {
long sum = 0;
for (LongWritable value : values) {
sum += value.get();
}
LongWritable outputValue = new LongWritable();
outputValue.set(sum);
context.write(key, outputValue);
}
}
public static void main(String[] args) throws Exception {
args = new String[]{"hdfs://chao.com:8020/input/wc.txt",
"hdfs://chao.com:8020/output"
};
Configuration conf = new Configuration();
//创建作业
Job job = Job.getInstance(conf);
job.setJarByClass(WordCountMapReduce.class);
//输入路径
FileInputFormat.addInputPath(job, new Path(args[0]));
//输出路径
Path outPath = new Path(args[1]);
FileSystem dfs = FileSystem.get(conf);
if (dfs.exists(outPath)) {
dfs.delete(outPath, true);
}
FileOutputFormat.setOutputPath(job, outPath);
//mapper
job.setMapperClass(WordCountMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
//reducer
job.setReducerClass(WordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//提交作业
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
3、运行
在eclipse里直接运行(需要core-site.xml)
PS:打包运行
a) 启动Hadoop (若是报进程已启动的错误,可以到tmp目录下删除对应的pid文件 --ls /tmp/*.pid)
b) 将WordCountMapReduce.java文件导出为jar(需要填写文件名,如:XXX.jar)
c) /opt/modules/hadoop-2.5.0/bin/yarn jar WordCountMapReduce.jar com.myblue.myhdfs.WordCountMapReduce /input /output
====计算每个省份的PV=======================================================
数据来源:
** web服务器的日志文件(20150828)
案例:
** web服务器的日志文件(20150828)
** web服务器生产日志文件
** 数据字典
** 36个字段
需求:
** 计算每个省份的PV
** provinceId
常见的统计指标:
** PV page view
用户每访问一个页面就记录一条日志,如果是多次访问同一个页面会累计
** UV unique visitor
独立访客(cookie)
** 独立IP
思路:依据provinceId字段去统计
** 把provinceId作为key, value是1
package com.myblue.myhdfs;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class WebPvMapReduce extends Configured implements Tool {
public static class ModuleMapper extends
Mapper<LongWritable, Text, IntWritable, IntWritable> {
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String lineValue = value.toString();
String[] splits = lineValue.split("\t");
//过滤非法数据,若该行数据少于30字段,则视为非法数据,不再处理
if (splits.length < 30) {
//参数:计数器组,计数器名
context.getCounter("Web Pv Counter", "Length limit 30").increment(1L);
return;
}
String url = splits[1];// 第2个字段为url
if (StringUtils.isBlank(url)) {
context.getCounter("Web Pv Counter", "Url is Blank").increment(1L);
return;
}
String provinceIdValue = splits[23];// 第24个字段为provinceId
if (StringUtils.isBlank(provinceIdValue)) {
context.getCounter("Web Pv Counter", "Province is Blank").increment(1L);
return;
}
int provinceId = 0;
try {
provinceId = Integer.parseInt(provinceIdValue);
} catch (Exception e) {
System.out.println(e);
return;
}
IntWritable mapOutputKey = new IntWritable();
mapOutputKey.set(provinceId);
IntWritable mapOutputValue = new IntWritable(1);//本例输出恒为1
context.write(mapOutputKey, mapOutputValue);
}
}
public static class ModuleReducer extends
Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
protected void reduce(IntWritable key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
IntWritable outputValue = new IntWritable();
outputValue.set(sum);
context.write(key, outputValue);
}
}
public int run(String[] args) throws Exception {
// 创建作业
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(getClass());
// 输入、输出路径
FileInputFormat.addInputPath(job, new Path(args[0]));
Path outPath = new Path(args[1]);
FileSystem dfs = FileSystem.get(conf);
if (dfs.exists(outPath)) {
dfs.delete(outPath, true);
}
FileOutputFormat.setOutputPath(job, outPath);
// mapper
job.setMapperClass(ModuleMapper.class);
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(IntWritable.class);
// reducer
job.setReducerClass(ModuleReducer.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(IntWritable.class);
// 提交作业
return job.waitForCompletion(true) ? 0 : 1;
}
public static void main(String[] args) throws Exception {
args=new String[]{"/input2","/output2"};
// 使用ToolRunner运行作业
Configuration conf = new Configuration();
int status = ToolRunner.run(conf, new WebPvMapReduce(), args);
System.exit(status);
}
}
测试:
$ hdfs dfs -mkdir /input2
$ hdfs dfs -put 2015082818 /input2
$ /opt/modules/hadoop-2.5.0/bin/yarn jar WebPvMapReduce.jar com.myblue.myhdfs.WebPvMapReduce /input2 /output2
====YARN================================================
YARN架构
** 集群资源管理、作业和任务管理
** hadoop2.0以前
** jobtracker
** tasktracker
** hadoop2.0以后
** resourcemanager
** nodemanager
** resourcemanager
--接收客户端请求 bin/yarn jar xxx.jar wordcount /input /output
--启动/监控ApplicationMaster
--监控NodeManager
--资源分配与调度
** nodemanager
--单个节点上的资源管理
--处理来自ResourceManager的命令
--处理来自ApplicationMaster的命令
** applicationmaster
--当前这个任务的管理者,任务运行结束,applicationmaster会消失
--数据切分
--为应用程序申请资源,并分配给任务使用
--任务监控与容错
** Container
--对任务运行环境的抽象,封装了CPU、内存等多维资源以及环境变量、启动命令等任务运行相关的信息
再次认识Hadoop
** HDFS
--分布式文件系统的架构、存储数据
--namenode
--datanode
** yarn
--集群资源管理、作业和任务管理
--resourcemanager
--nodemanager
通常集群资源配置:
** 内存
yarn.nodemanager.resource.memory-mb8G 64G 128G
** CPU
yarn.nodemanager.resource.cpu-vcores8核 16核
** 内存不够,会直接影响job任务运行成败
** CPU不够,只会影响job任务运行的快慢
Day04
一、前一天的问题:
1.编写mapreduce程序
Driver
1.// 设置运行job的jar类 打jar包,提交到yarn时必须加这一行
//否则会报:ClassNoFound
job.setJarByClass(this.getClass());
2.获取文件系统对象
//推荐写法
Path outPath = new Path(args[1]);
FileSystem fs = outPath.getFileSystem(conf);
FileSystem fs = New FileSystem() //这样获取的对象是本地文件系统
Wrong FS:hdfs:// expected file:///
3.nativeio method jdk安装了最新版本 更换jre libariy
4.mapred.LocalJobRunner: 1 / 1 copied. 本地运行,不需要启动任何的守护进程
二、mapreduce(map和reduce个数) map任务split切片 reduce个数 partition
map个数:由任务切片spilt决定的,默认情况下一个split的大小就是block
由参与任务的文件个数决定的
number of splits:1
对于大文件,一般选择split=block,如果split<block 则会增加map执行的并发度,但是会造成在节点之间拉取数据
对于小文件,默认一个文件启动一个map,这样会启动多个map,增大节点资源消耗,此时可以使用使用InputFormat将多个小文件加入到一个split,并适当增大split的大小,这样会减少map启动的个数,减少并发度,减少资源消耗
reduce个数:由分区个数决定 可以由用户在程序中Driver自定义job.setNumReduceTasks(3);一个ruduce对应一个结果文件part_0000
partiton(分区):用来指定map输出的key交给哪个reuducer处理 默认是通过对map输出的key取hashcode 对指定的reduce个数求模(取余)
key.hashcode() % N=job.setNumReduceTasks(n)
Group 分组:map输出的相同key放到一个分组
Sort 排序: 根据key进行排序
三、完全分布式的安装
1、集群规划
角色分配
组件PC1 PC2 PC3
HDFS Namenode SecondaryNamenode
Datanode DatanodeDatanode
Yarn RecourceManager
Nodemanager Nodemanager Nodemanager
Histrory HistroryServer
2、基本环境准备
2.1系统和软件【3台】
CentOS 6.5 hadoop 2.5.0 jdk1.70—67
2.2 配置IP和DNS(root)
配置静态IP
DNS
//检查主机映射
$ cat /etc/hosts
//检查主机名
$cat /etc/sysconfig/network
//检查IP和DNS
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
2.3关闭防火墙 (3台) (root)
# service iptables stop
# chkconfig iptables off
检查:
$ sudo service iptables status
iptables: Firewall is not running.
$ sudo chkconfig --list | grep iptables
0:off1:off2:off3:off4:off5:off6:off
关闭Linux安全子系统
# vi /etc/sysconfig/selinux
2.4创建相同普通用户名和密码 【3台】
# useradd hadoop
# echo 123456 | passwd --stdin hadoop
2.5配置主机映射 【三台都需要需要添加】
# vi /etc/hosts
192.168.7.9 yu.com
192.168.7.10 gcf.com
192.168.7.11 feng.com
2.6卸载自带的jdk
# rpm -qa | grep jdk
# rpm -e --nodeps tzdata-java-2012j-1.el6.noarch
# rpm -e --nodeps java-1.6.0-openjdk-1.6.0.0-1.50.1.11.5.el6_3.x86_64
# rpm -e --nodeps java-1.7.0-openjdk-1.7.0.9-2.3.4.1.el6_3.x86_64
配置Java环境变量
# vi /etc/profile
#JAVA_HOME
export JAVA_HOME=/opt/modules/jdk1.7.0_67
export PATH=$PATH:$JAVA_HOME/bin
生效配置
source /etc/profile
检查Java环境变量
java -version
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
二、配置NTP服务
*.把PC1作为整个集群的时间同步服务器
*.集群中所有其他服务器都来这台服务器PC1同步时间
1.检查每台服务器所在的时区
$ date -R
Thu, 23 Mar 2017 11:13:57 +0800
如果不是+0800,如要通过如下命令调整
# rm -rf /etc/localtime ---如果时区不是+0800
# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
2.安装ntp服务
# rpm -qa | grep ntp --查看ntp软件包是否已安装
ntp-4.2.6p5-1.el6.centos.x86_64
ntpdate-4.2.6p5-1.el6.centos.x86_64
# yum -y install ntp --如果没有那就需要安装ntp
3.修改ntp的配置文件(PC1)
# vi /etc/ntp.conf
去掉第18行的# 修改成自己的网段
restrict 192.168.7.0 mask 255.255.255.0 nomodify notrap
注释掉以下几行(22行)
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
CentsOS6.4 去掉注释第35 36行
CentsOS6.5 去手动添加以下内容
server 127.127.1.0 #local clock
fudge 127.127.1.0 stratum 10
4、同步服务器的时间(PC1)
# ntpdate cn.pool.ntp.org -->操作这一步时关闭ntp服务
23 Mar 11:36:56 ntpdate[26856]: step time server 173.255.246.13 offset -12.240613 sec
5、启动ntp服务(默认式开始)PC1 root用户操作
# service ntpd start
# chkconfig ntopd on
$ sudo chkconfig --list | grep ntpd
$ sudo ntpdate 202.120.2.101
9 Jun 15:27:49 ntpdate[2689]: the NTP socket is in use, exiting //ntpd一旦开启就不能手动同步时间
6、如果另外两台的ntp的进程开启,那么需要关闭
# service ntpd stop
# chkconfig ntpd off
7.第2、3台向第一台同步时间
# ntpdate yu.com
16 Feb 17:43:27 ntpdate[2554]: adjust time server 192.168.7.9 offset -0.001412 sec
8.制定周期性时间同步计划任务(PC2、PC3定时向PC1手动同步时间)
在PC2 PC3每10分钟同步一次时间
# crontab -e
*/10 * * * * /usr/sbin/ntpdate yu.com
[注意]:如果确实无法向第一台同步时间,请在交互窗口(可以同时设置3台时间)执行手动设置时间
# date -s "11:48:00 2017/3/23"
三、配置SSH免密钥登录
使用ssh登录的时候不需要用户名密码
$ sbin/start-dfs.sh
$ ssh-keygen
* 回车,生产当前主机的公钥和私钥
//分发密钥(要向3台都发送)
$ ssh-copy-id yu.com
$ ssh-copy-id gcf.com
$ ssh-copy-id feng.com
(PC1~PC3)
$ ssh-keygen
$ ssh-copy-id yu.com
$ ssh-copy-id gcf.com
$ ssh-copy-id feng.com
分发完成之后会在用户主目录下.ssh目录生成以下文件
$ ls .ssh/
authorized_keys id_rsa id_rsa.pub known_hosts
测试失败,需要先删除.ssh目录,重做一遍
四、安装Hadoop
1.下载上传到Linux并解压hadoop的.tar.gz
$ tar -zxf hadoop-2.5.0.tar.gz -C /opt/modules/
2.删除${HADOOP_HOME}/share/doc
$ rm -rf doc/
3.配置java环境支持在${HADOOP_HOME}/etc/hadoop
在hadoop-env.sh mapred-env.sh yarn-env.sh中配置
export JAVA_HOME=/opt/modules/jdk1.7.0_67
4.配置slaves(集群中所有的主机)
yu.com
gcf.com
feng.com
5.=======core-site.xml===
<!--指定第一台作为NameNode-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://yu.com:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data</value>
</property>
=============hdfs-site.xml==========
<!-- 分布式副本数设置为3 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- secondarynamenode主机名:端口号 -->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>gcf.com:50090</value>
</property>
<!-- namenode的web访问主机名:端口号 -->
<property>
<name>dfs.namenode.http-address</name>
<value>yu.com:50070</value>
</property>
<!-- 关闭权限检查用户或用户组 -->
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
=================mapred-site.xml=======
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>yu.com:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>yu.com:19888</value>
</property>
================yarn-site.xml======
<property>
<name>yarn.resourcemanager.hostname</name>
<value>feng.com</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
===============================
5.配置slaves
yu.com
gcf.com
feng.com
【注意事项】:
1.slaves中配置集群中所有的主机名
2.所有节点上的配置文件内容都是一样的(联盟模式例外)
3.要按照集群规划配置所属进程
五、(PC1)分发hadoop(已经配置好的)目录到其他两台(PC2和PC3)服务器上
scp -r PC1的hadoop目录(带路径) PC2:/要复制到的目录
$ scp -r /opt/modules/hadoop-2.5.0/ gcf.com:/opt/modules/
$ scp -r /home/gu/ruan/hadoop-2.5.0/etc feng.com:/home/gu/ruan/hadoop-2.5.0/etc
六、格式化Namenode
在PC1上的${HADOOP_HOME}/bin
$ bin/hdfs namendoe -format
【注意】
1.先将PC1的hadoop配置目录分发到PC2和PC3
2.保证3台上的配置内容一模一样
3.先确保将3台之前残留的data 和 logs删除掉
4.最后格式化
七、启动进程
在PC1上使用如下命令启动HDFS
$ sbin/start-dfs.sh
在PC3上使用如下命令启动YARN
$ sbin/start-yarn.sh
停止进程
在PC1上使用如下命令停止HDFS
$ sbin/stop-dfs.sh
在PC3上使用如下命令停止YARN
$ sbin/stop-yarn.sh
【注意】
修改任何配置文件,请先停止所有进程,然后重新启动
八、检查启动是否正常
3台上jps查看进程,参考之前的集群规划
PC1:
28626 DataNode
28883 NodeManager
28989 Jps
28531 NameNode
PC2:
7528 DataNode
7826 Jps
7717 NodeManager
7583 SecondaryNameNode
PC3
7622 NodeManager
7922 Jps
7527 ResourceManager
7405 DataNode
Day05
搭建完全分布式注意的地方
1.3台服务器的时间应该一致,至少不应该相差太大
2.SSH免密钥必须要在3台上进行生成密钥和分发密钥,(必须要给自己也要发一份,也就是每台要分发3次)
3.必须使用相同的用户名和密码
4.选其中一台进行配置(*-env.sh ,*-site.xml,slaves),然后使用scp命令 分发到另外两台
**5.集群(这里是3台)中的配置文件必须一模一样
6.配置完成最好重启3台服务器,在规划为namenode所在节点进行bin/hdfs namenode -format格式化
7.启动进程自动关闭(root和普通用户交叉启动进程造成的)
1).ll logs 是否存在root用户所属的日志文件(.log 和.out)
2).检查 ll /tmp/*.pid 有没有root用户所属的.pid
3).切换root用户删除rm -f /tmp/*.pid 删除${HADOOP_HOME}/data 和 ${HADOOP_HOME}/logs/*
4).切换成普通用户,重新格式化namenode
一、Yarn的运行原理(执行流程)
1.client向yarn提交job,首先找ResourceManager分配资源,
2.ResourceManager开启一个Container,在Container中运行一个Application manager
3.Application manager找一台nodemanager启动Application master,计算任务所需的计算
4.Application master向Application manager(Yarn)申请运行任务所需的资源
5.Resource scheduler将资源封装发给Application master
6.Application master将获取到的资源分配给各个nodemanager
7.各个nodemanager得到任务和资源开始执行map task
8.map task执行结束后,开始执行reduce task
9.map task和 reduce task将执行结果反馈给Application master
10.Application master将任务执行的结果反馈pplication manager。
二、shuffle过程
从map()的输出到reduce()的输入,中间的过程被称为shuffle过程。
map side
1.在写入磁盘之前,会先写入环形缓冲区(circular memory buffer),默认100M(mapreduce.task.io.sort.mb可修改),当缓冲区内容达到80M(mapre
duce.map.sort.spill.percent可修改),缓冲区内容会被溢写到磁盘,形成一个spill file文件
2.分区:在写入磁盘之前,会先进分区(partition),而partition的数量是由reducer的数量决定的
job.setNumReduceTasks(2);
默认是用map输出的<key,value>中key的hashcode对NumReduceTasks的个数取余,相同的分到一个区
3.排序:在每一个partition中,都会有一个sort by key
4.combiner:如果有combiner function,在sort之后会执行combiner,相当于map阶段的rudece 【满足数学运算的交换律和结合律】
5.merge:数个spill files会合并(merge成一个分过区的排过序的文件
6.compress压缩the map output
mapreduce.task.io.sort.factor一次性合并小文件的数量 默认10个
mapreduce.map.output.compress 启用压缩,默认是false
org.apache.hadoop.io.compress.DefaultCodec默认使用的压缩算法
reduce side
1.解压缩:如果在map side 已经压缩过,在合并排序之前要先进行解压缩
2.sort phase(merge)
3.group phase:将相同key的value分到一组,形成一个集合
三、【案例分析一:网站PV UV分析】
学习内容:
1.离线hadoop大数据分析的一个ETL数据过滤清洗阶段
2.了解应用hadoop分析网站统计指标
3.网站统计分析的基本指标
电商(淘宝、京东、一号店等)生产环境下,周期性性,多维度分析:
1.1天24小时(0~24)网站的PV UV 独立IP等等
2.多维度,基于时间、地域,平台等等
1.网站基本统计指标
PV(Page View)
即页面浏览量或点击量,是衡量一个网站或网页用户访问量。具体的说,PV值就是所有访问者在24小时(0点到24点)内看了某个网站多少个页面或某个网页多少次。PV是指页面刷新的次数,每一次页面刷新,就算做一次PV流量。
度量方法就是从浏览器发出一个对网络服务器的请求(Request),网络服务器接到这个请求后,会将该请求对应的一个网页(Page)发送给浏览器,从而产生了一个PV。那么在这里只要是这个请求发送给了浏览器,无论这个页面是否完全打开(下载完成),那么都是应当计为1个PV。
UV(Unique Visitor)
即独立访客数,指访问某个站点或点击某个网页的不同cookie的人数,在同一天内再次访问该网站则不计数。UV提供了一定时间内不同观众数量的统计指标,而没有反应出网站的全面活动。通过cookie是判断UV值的一种方式(另外也可以通过IP地址来判断UV值):
用Cookie分析UV值:
当客户端第一次访问某个网站服务器的时候,网站服务器会给这个客户端的电脑发出一个Cookie,通常放在这个客户端电脑的C盘当中。在这个Cookie中会分配一个独一无二的编号,这其中会记录一些访问服务器的信息,如访问时间,访问了哪些页面等等。当你下次再访问这个服务器的时候,服务器就可以直接从你的电脑中找到上一次放进去的Cookie文件,并且对其进行一些更新,但那个独一无二的编号是不会变的。
VV(Visit View)
即产生的会话数量
独立IP数
IP可以理解为独立IP的访问用户,指1天内使用不同IP地址的用户访问网站的数量,同一IP无论访问了几个页面,独立IP数均为1。但是假如说两台机器访问而使用的是同一个IP,那么只能算是一个IP的访问。
IP -》 国家 省 市
2.需求:根据省份统计日志中网站PV
1.字段长度大于30才为有效记录
2.url不为空为有效记录
3.provinceId不为空为有效记录
4.统计
map---split(1个split就是1个map方法)
split---block(默认1:1的对应关系)
reduce的数量默认是1
案例1:手机上网流量统计
数据源: HTTP_20130313143750 每个电话号码每上一次网络,就会生成一条日志数据
需求目标: 手机号码上行数据包总数 下行数据包总数 上行总流量 下行总流量 1312341243112381782334242342 136223112381722334214234211231 1312341243112380182834 23 ......
MapReduce设计: ** key是什么? --电话号码 ** value是什么? --后面四个字段
keyvalue list 13123412431(123,2423,3453,234),(789,1231,4353,234),(1231,231,342,23) ... 13622311238(1233,23,342353,23234),(78239,123231,42353,2234) ... ............
最终结果: 13123412431(1232313,241231323,23133453,1231234) 13622311238(6666,62,889,99999999) ............
----DataTotalWritable------
package com.myblue.myhdfs;
import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.Writable;
public class DataTotalWritable implements Writable {
// 上行数据包总数 private long upPackNum ; // 下行数据包总数 private long downPackNum ; // 上行总流量 private long upPayLoad ; // 下行总流量 private long downPayLoad ;
public DataTotalWritable() { }
public DataTotalWritable(long upPackNum, long downPackNum, long upPayLoad,long downPayLoad) { this.set(upPackNum, downPackNum, upPayLoad, downPayLoad); }
public void set (long upPackNum, long downPackNum, long upPayLoad,long downPayLoad) { this.upPackNum = upPackNum; this.downPackNum = downPackNum; this.upPayLoad = upPayLoad; this.downPayLoad = downPayLoad; }
public long getUpPackNum() { return upPackNum; }
public void setUpPackNum(long upPackNum) { this.upPackNum = upPackNum; }
public long getDownPackNum() { return downPackNum; }
public void setDownPackNum(long downPackNum) { this.downPackNum = downPackNum; }
public long getUpPayLoad() { return upPayLoad; }
public void setUpPayLoad(long upPayLoad) { this.upPayLoad = upPayLoad; }
public long getDownPayLoad() { return downPayLoad; }
public void setDownPayLoad(long downPayLoad) { this.downPayLoad = downPayLoad; }
//^为异或运算, << 带符号左移, >>带符号右移, >>> 无符号右移 @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (downPackNum ^ (downPackNum >>> 32)); result = prime * result + (int) (downPayLoad ^ (downPayLoad >>> 32)); result = prime * result + (int) (upPackNum ^ (upPackNum >>> 32)); result = prime * result + (int) (upPayLoad ^ (upPayLoad >>> 32)); return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DataTotalWritable other = (DataTotalWritable) obj; if (downPackNum != other.downPackNum) return false; if (downPayLoad != other.downPayLoad) return false; if (upPackNum != other.upPackNum) return false; if (upPayLoad != other.upPayLoad) return false; return true; }
@Override public String toString() { return upPackNum + "\t"+ downPackNum + "\t" + upPayLoad + "\t"+ downPayLoad ; }
public void write(DataOutput out) throws IOException { out.writeLong(upPackNum); out.writeLong(downPackNum); out.writeLong(upPayLoad); out.writeLong(downPayLoad); }
public void readFields(DataInput in) throws IOException { this.upPackNum = in.readLong() ; this.downPackNum = in.readLong() ; this.upPayLoad = in.readLong() ; this.downPayLoad = in.readLong() ; }
}
----DataTotalMapReduce-----------
package com.myblue.myhdfs;
import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import com.myblue.myhdfs.DataTotalWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner;
public class DataTotalMapReduce extends Configured implements Tool {
public static class DataTotalMapper extends Mapper<LongWritable, Text, Text, DataTotalWritable> {
@Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//split by '\t' String[] splits = value.toString().split("\t") ;
//以手机号码作为output key String phoneNum = splits[1]; Text mapOutputKey = new Text(); mapOutputKey.set(phoneNum);
// set map output value long upPackNum = Long.parseLong(splits[6]) ; long downPackNum = Long.parseLong(splits[7]) ; long upPayLoad = Long.parseLong(splits[8]) ; long downPayLoad = Long.parseLong(splits[9]) ; DataTotalWritable mapOutputValue = new DataTotalWritable() ; mapOutputValue.set(upPackNum, downPackNum, upPayLoad, downPayLoad);
//map output context.write(mapOutputKey, mapOutputValue); } }
public static class DataTotalReducer extends Reducer<Text, DataTotalWritable, Text, DataTotalWritable> {
@Override protected void reduce(Text key, Iterable<DataTotalWritable> values, Context context) throws IOException, InterruptedException {
long upPackNumSum = 0; long downPackNumSum = 0; long upPayLoadSum = 0; long downPayLoadSum = 0;
//iterator for(DataTotalWritable value : values){ upPackNumSum += value.getUpPackNum() ; downPackNumSum += value.getDownPackNum() ; upPayLoadSum += value.getUpPayLoad() ; downPayLoadSum += value.getDownPayLoad() ; }
// set output value DataTotalWritable outputValue = new DataTotalWritable() ; outputValue.set(upPackNumSum, downPackNumSum, upPayLoadSum, downPayLoadSum);
// output context.write(key, outputValue); } }
public int run(String[] args) throws Exception {
//Job Configuration conf = super.getConf(); Job job = Job.getInstance(conf); job.setJarByClass(getClass());
//Mapper job.setMapperClass(DataTotalMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(DataTotalWritable.class);
//Reducer job.setReducerClass(DataTotalReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(DataTotalWritable.class);
//输入路径 Path inPath = new Path(args[0]); FileInputFormat.addInputPath(job, inPath); //输出路径 Path outPath = new Path(args[1]); FileSystem dfs = FileSystem.get(conf); if (dfs.exists(outPath)) { dfs.delete(outPath, true); } FileOutputFormat.setOutputPath(job, outPath);
//Submit Job boolean isSuccess = job.waitForCompletion(true); return isSuccess ? 0 : 1; }
public static void main(String[] args) throws Exception {
args = new String[] {"hdfs://blue01.mydomain:8020/input2", "hdfs://blue01.mydomain:8020/output2"};
// run job Configuration conf = new Configuration(); int status = ToolRunner.run(conf,new DataTotalMapReduce(),args);
System.exit(status); } }
===================案例2:Join=================================================
数据文件: customer文件 1,Stephanie Leung,555-555-5555 2,Edward Kim,123-456-7890 3,Jose Madriz,281-330-8004 4,David Stork,408-555-0000
order文件 3,A,12.95,02-Jun-2008 1,B,88.25,20-May-2008 2,C,32.00,30-Nov-2007 3,D,25.02,22-Jan-2009
目标: 1,B,88.25,20-May-2008,Stephanie Leung,555-555-5555 2,C,32.00,30-Nov-2007,Edward Kim,123-456-7890 3,D,25.02,22-Jan-2009,Jose Madriz,281-330-8004 3,A,12.95,02-Jun-2008,Jose Madriz,281-330-8004
思路: 选用: Join
map阶段: ** map task依次读取两个文件,切割,并设置key和value,取cid为key,同时给来自不同的文件的value打一个标签 value == flag + value
reduce阶段: ** Join
Map读入 <偏移量,这一行值> Map()输出 --customer文件输出 <1,customer_[Stephanie Leung,555-555-5555]> <2,customer_[Edward Kim,123-456-7890]> ...
--order文件输出 <3,order_[A,12.95,02-Jun-2008]> <1,order_[B,88.25,20-May-2008]> <3,order_[D,25.02,22-Jan-2009]> ...
Reduce()输入 <key,( , , , ) > <1,(customer_[Stephanie Leung,555-555-5555],order_[B,88.25,20-May-2008]) <2,(customer_[Edward Kim,123-456-7890],order_[C,32.00,30-Nov-2007]) <3,(customer_[Jose Madriz,281-330-8004],order_[A,12.95,02-Jun-2008],order_[D,25.02,22-Jan-2009]) <4,(customer_[David Stork,408-555-0000])
----DataJoinWritable-------------
package com.myblue.myhdfs;
import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.Writable;
public class DataJoinWritable implements Writable {
private String flag; private String data;
public DataJoinWritable() { }
public DataJoinWritable(String flag, String data) { this.set(flag, data); } public void set(String flag, String data) { this.flag = flag; this.data = data; }
public String getFlag() { return flag; }
public void setFlag(String flag) { this.flag = flag; }
public String getData() { return data; }
public void setData(String data) { this.data = data; }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((data == null) ? 0 : data.hashCode()); result = prime * result + ((flag == null) ? 0 : flag.hashCode()); return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DataJoinWritable other = (DataJoinWritable) obj; if (data == null) { if (other.data != null) return false; } else if (!data.equals(other.data)) return false; if (flag == null) { if (other.flag != null) return false; } else if (!flag.equals(other.flag)) return false; return true; }
@Override public String toString() { return flag + "," + data ; }
public void write(DataOutput out) throws IOException { //用与平台无关的方式使用UTF-8编码将一个字符串写入输出流 out.writeUTF(getFlag()); out.writeUTF(getData()); }
public void readFields(DataInput in) throws IOException { this.flag = in.readUTF() ; this.data = in.readUTF() ; } }
----DataJoinMapReduce--------------
package com.myblue.myhdfs;
import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import com.myblue.myhdfs.DataJoinWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.Job;
public class DataJoinMapReduce extends Configured implements Tool {
public static class DataJoinMapper extends Mapper<LongWritable, Text, Text, DataJoinWritable> {
@Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] splits = value.toString().split(",");
//output key,以连接值为key String cid = splits[0]; Text mapOutputKey = new Text(); mapOutputKey.set(cid);
//output value DataJoinWritable mapOutputValue = new DataJoinWritable();
// length == 3 ==> customer if (splits.length == 3) { String name = splits[1]; String phoneNum = splits[2]; mapOutputValue.set("customer", name + "," + phoneNum); }
// length == 4 ==> order if (splits.length == 4) { String name = splits[1]; String price = splits[2]; String date = splits[3]; mapOutputValue.set("order", name + "," + price + "," + date); `}
context.write(mapOutputKey, mapOutputValue); } }
public static class DataJoinReducer extends Reducer<Text, DataJoinWritable, NullWritable, Text> {
@Override protected void reduce(Text key, Iterable<DataJoinWritable> values, Context context) throws IOException, InterruptedException {
String customerInfo = null; List<String> orderList = new ArrayList<String>();
for (DataJoinWritable value : values) { if ("customer".equals(value.getFlag())) { customerInfo = value.getData(); } else if ("order".equals(value.getFlag())) { orderList.add(value.getData()); } }
Text outputValue = new Text(); for (String order : orderList) { outputValue.set(key.toString() + "," + order + "," + customerInfo); context.write(NullWritable.get(), outputValue); } } }
public int run(String[] args) throws Exception {
Configuration conf = super.getConf(); Job job = Job.getInstance(conf); job.setJarByClass(getClass());
//Mapper job.setMapperClass(DataJoinMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(DataJoinWritable.class);
//Reducer job.setReducerClass(DataJoinReducer.class); job.setOutputKeyClass(NullWritable.class); job.setOutputValueClass(Text.class);
//输入路径 Path inPath = new Path(args[0]); FileInputFormat.addInputPath(job, inPath); //输出路径 Path outPath = new Path(args[1]); FileSystem dfs = FileSystem.get(conf); if (dfs.exists(outPath)) { dfs.delete(outPath, true); } FileOutputFormat.setOutputPath(job, outPath);
//Submit Job boolean isSuccess = job.waitForCompletion(true); return isSuccess ? 0 : 1; }
public static void main(String[] args) throws Exception {
args = new String[] {"hdfs://blue01.mydomain:8020/input2", "hdfs://blue01.mydomain:8020/output2"};
Configuration conf = new Configuration(); int status = ToolRunner.run(conf,new DataJoinMapReduce(), args);
System.exit(status); } }
-----------------------------------
|
mapreduce中的Join
** Map端Join
** 一个表比较小,另外一个表非常大
会把小表数据完整的放入到大表关联的每台nodemanager节点的内存中去,
[map task]依次匹配内存中小表数据
** reduce端Join
** 两张表通常都是大文件
** Join的操作是在Reduce端执行
** semi Join
** map端Join和reduce端Join结合
** mapper在读取block数据处理的时候,如果有相关字段则保留,否则过滤掉。然后把需要的数据传递给reduce端进行join。
====Shuffle==============================================================
MapReduce程序
** 离线数据分析、数据清洗(过滤脏数据)
** 执行命令:bin/yarn jar 包名.类名 参数
MapReduce Shuffle
数据从map task输出到reduce task输入的这段过程
** map的输入: split
** 默认情况下,一个block就是一个split,一个split对应一个map
** 尽量保证每个map的输入数据是来自同一个block
** 如果设计多个block为一个split,可能会造成大量额外流量
** 合理控制map个数
>>Input
<0,hadoop mapreduce>
<14,hbase hadoop>
>>map()
** map() --> value.toString().split("\t")
** output
<hadoop,1> <mapreduce,1> <hbase,1> <hadoop,1>
----Shuffle---------------
>>>>>>>> map shuffle
>>> 环形缓存区
默认大小100M mapreduce.task.io.sort.mb
>>> partition分区
** HashPartitioner
** 决定数据交给哪个reduce处理
1hadoop hbase-->reduce1
2mapreduce--> reduce2
3...--> reduce3
>>> sort
** 按照key进行字典顺序排序
>>> combine (可选,并非所有的情况都可以使用combine)
** 默认情况下,相当于map阶段局部reduce
>>> spill
** 当环形缓存区容量达到80M(0.8) mapreduce.map.sort.spill.percent
** 会将缓存区的数据写入本地磁盘临时目录(不是HDFS)
>>> merge
** 把很多小文件合并成一个大文件
>>> compress (可选)
** 减轻网络IO的压力
>>>>>>>> reduce shuffle (application master)
每个reduce会去map的输出结果中拉取自己对应的分区数据
merge合并
** 按照key进行文件合并
group分组
** 将相同key的value值放到一起,形成list
** <hadoop,(1,1)> <mapreduce,1> ...
----reduce-------------
>>reduce
<hadoop,(1,1)><mapreduce,1><hbase,1>
>>output
** 数据汇总
** hadoop 2,mapreduce 1,hbase 1 ...
设置reduce个数:
** 当前job任务
job.setNumReduceTasks(n);
** 永久生效
配置文件 mapred-site.xml
Day06
回顾:
[Map和 Reduce的个数]
map的个数由什么决定 切片
1.每一个文件会有1个map(不足128M)
2.大于128M文件存储一个一个的block,map个数就是block的个数
***.avi文件 有10个block ,10个map
129M文件切成2个block,一个128M,另一个1M,最后一个块小于block1.1倍
split 大小就和block大小一致
max(0,min(block.size, split.max))
reducede 个数
默认情况下1,输出目录只有一个part**文件
reduce的个数可以设定
设置3个reduce,输出目录里面的part*文件有3个
key.hashcode(整形数据 int) 取模 partition 个数
设置了 partition 个数如果3个
a 1
b 2
c 3
d 4
e 5
f 6
对3 取模
a d -> reduce 0
b e -> reduce 1
c f -> reduce 2
分区就是增加并行度,分到不同的节点进行计算
job.setNumReduceTasks(2);
MapReduce <key -> value>
1.分区
2.分组
3.排序
都是针对于key完成
自定义key -> 实现WritableComparebale序列化接口
自定义value -> 实现Writable序列化接口
自定义分区
自定义分区
====二次排序=================================================
思路: ** MapReduce特性:自动对key进行排序 ** 把需要排序的第一字段和第二字段组合成一个新的key (可选) ** 修改分区规则--针对原始key进行分区 ** 修改分组规则--针对原始key进行分组
具体实现: ** 自定义Key数据类型,实现WritableComparable接口 (可选) ** 自定义分区函数类,实现Partitioner接口 ** 自定义分组类 ** 继承WritableComparator类 ** 继承RawComparator接口
----PairWritable-------------------
package com.myblue.mymapreduce;
import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.WritableComparable;
//自定义类型 public class PairWritable implements WritableComparable<PairWritable> {
private String first; private int second;
public PairWritable() { }
public PairWritable(String first, int second) { this.set(first, second); } public void set(String first, int second) { this.first = first; this.second = second; }
public String getFirst() { return first; }
public void setFirst(String first) { this.first = first; }
public int getSecond() { return second; }
public void setSecond(int second) { this.second = second; }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + second; return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PairWritable other = (PairWritable) obj; if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; if (second != other.second) return false; return true; }
@Override public String toString() { return first + "," + second ; }
public void write(DataOutput out) throws IOException { out.writeUTF(first); out.writeInt(second); }
public void readFields(DataInput in) throws IOException { this.first = in.readUTF(); this.second = in.readInt(); }
//比较两个对象的大小 public int compareTo(PairWritable o) {
//先比较第一个值 int result = this.getFirst().compareTo(o.getFirst());
if( result != 0 ){//比较出大小 return result; }else return Integer.valueOf(getSecond()).compareTo(Integer.valueOf(o.getSecond())); } }
----SecondarySortMapReduce-------------------
package com.myblue.mymapreduce;
import java.io.IOException; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner;
public class SecondarySortMapReduce extends Configured implements Tool {
public static class SecondarySortMapper extends Mapper<LongWritable, Text, PairWritable, LongWritable> {
@Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] splits = value.toString().split(",") ;
//output key PairWritable mapOutputKey = new PairWritable(); mapOutputKey.set(splits[0], Integer.valueOf(splits[1]));
//output Value LongWritable mapOutputValue = new LongWritable() ; mapOutputValue.set(Long.valueOf(splits[1]));
context.write(mapOutputKey, mapOutputValue); } }
public static class SecondarySortReducer extends Reducer<PairWritable, LongWritable, Text, LongWritable> {
@Override protected void reduce(PairWritable key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
Text outputKey = new Text(); for(LongWritable value : values){ outputKey.set(key.getFirst()); context.write(outputKey, value); } } }
public int run(String[] args) throws Exception {
Configuration conf = super.getConf(); Job job = Job.getInstance(conf); job.setJarByClass(getClass());
//Mapper job.setMapperClass(SecondarySortMapper.class); job.setMapOutputKeyClass(PairWritable.class); job.setMapOutputValueClass(LongWritable.class);
// 1.Partition,可以注释 job.setPartitionerClass(FirstPartitioner.class); // 2.sort // job.setSortComparatorClass(cls); // 3.combine // job.setCombinerClass(WordCountReducer.class); // 4.compress // conf.set("mapreduce.map.output.compress", "false"); // 5.group,可以注释 job.setGroupingComparatorClass(FirstGroupingComparator.class);
//Reducer job.setReducerClass(SecondarySortReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(LongWritable.class);
Path inPath = new Path(args[0]); FileInputFormat.addInputPath(job, inPath); Path outPath = new Path(args[1]); FileSystem dfs = FileSystem.get(conf); if (dfs.exists(outPath)) { dfs.delete(outPath, true); } FileOutputFormat.setOutputPath(job, outPath);
boolean isSuccess = job.waitForCompletion(true); return isSuccess ? 0 : 1; }
public static void main(String[] args) throws Exception {
args = new String[]{"hdfs://blue01.mydomain:8020/input", "hdfs://blue01.mydomain:8020/output"};
Configuration conf = new Configuration(); int status = ToolRunner.run(conf,new SecondarySortMapReduce(),args);
System.exit(status); } }
----FirstPartitioner-------------------
package com.myblue.mymapreduce;
import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.Partitioner;
public class FirstPartitioner extends Partitioner<PairWritable, LongWritable>{
public int getPartition(PairWritable key, LongWritable value, int numPartitions) {
// [0-9] [a-n] [o-z] //if(key.matches("[0-9].*")){ //return 0; //}else if(key.matches("[a-n].*")){ //return 1; //}else //return 2;
return (key.getFirst().hashCode() & Integer.MAX_VALUE) % numPartitions; } }
----FirstGroupingComparator-------------------
package com.myblue.mymapreduce;
import org.apache.hadoop.io.RawComparator; import org.apache.hadoop.io.WritableComparator;
public class FirstGroupingComparator implements RawComparator<PairWritable> {
public int compare(PairWritable o1, PairWritable o2) { return o1.getFirst().compareTo(o2.getFirst()); }
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { return WritableComparator.compareBytes(b1, 0, l1-4, b2, 0, l2-4); } } |
一、学习内容
1.Zookeeper (文件系统 角色 选举机制 watch)
2.HA (Namenode HA) ZKFC(fail over) 隔离机制(fence "篱笆") 元数据同步(QJM)
3.HA (ResourceManager HA)
二、Zookeeper
(一)、文件系统(数据结构)
Znode(1.代表zookeeper文件系统中的一个目录,2.代表 实体的客户端(Namenode))
动物 -> hadoop 中的节点 Namende
(二)、Watch事件
1.NameNode启动,然后向Zookeeper,触发注册事件,同时会创建一个唯一的目录
2.通过心跳信息,来确认节点的状态(存活或者宕机)
3.如果宕机,失去心跳信息,触发节点丢失事件,删除这个目录
Zookeeper是一个多server的服务(一台服务器就是一个server)
leader
fllower
(三)、投票(理解企业中节点为什么是奇数个 2n+1)
leader的候选人必须获取到超过半数的选票 n+1
zookeeper集群中存活的节点数据必须过半数容错率
3台 挂掉1台 33%
4台 挂掉1台 25%
(1)在zookeeper的选举过程中,为了保证选举过程最后能选出leader,就一定不能出现两台机器得票相同的僵局,所以一般的,要求zk集群的server数量一定要是奇数,也就是2n+1台,
(2)如果集群出现问题,其中存活的机器必须大于n+1台,否则leader无法获得多数server的支持,系统就自动挂掉。所以一般是3个或者3个以上节点。要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1。
(3)2n+1 ,2n+2的失效节点的容忍度是一致性的,那么这样的话,就没有必要多安装一个节点。
Zookeeper的功能以及工作原理 - FelixZh - 博客园 http://www.cnblogs.com/felixzh/p/5869212.html
选举流程(2种)
1.basic paxos
2.fast paxos(毛遂自荐)
三zookeeper(动物管理员) 安装
(一)伪分布式
##安装ZooKeeper
$ tar -zxf /opt/software/zookeeper-3.4.5.tar.gz -C /opt/modules/waremodules/
##新建一个Zookeeper的data目录
$ mkdir zkData --//可以不用手动创建,启动自动生成
##修改配置文件${ZOOKEEPER_HOME}/conf
1)$ cp zoo_sample.cfg zoo.cfg
2)vi zoo.cfg
dataDir=/opt/modules/zookeeper-3.4.5/zkData
##启动zookeeper
bin/zkServer.sh start
8967 QuorumPeerMain
##查看zookeeper的状态
bin/zkServer.sh status
JMX enabled by default
Using config: /opt/modules/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: standalone 单机模式
(二)完全分布式
1.安装JDK(3台PC都要安装JDK)
配置环境变量
2.安装完全分布式集群
1)安装zk
2)配置zoo.cfg文件
dataDir=/opt/modules/zookeeper-3.4.5/zkData
server.1=hadoop.ibeifeng.com.cn01:2888:3888
server.2=hadoop.ibeifeng.com.cn02:2888:3888
server.3=hadoop.ibeifeng.com.cn03:2888:3888
3)创建zkData目录,在zkData目录目录下创建myid文件,编辑myid,内同就是此台server的id,就是zoo.cfg中指定的server.1
4)从第一台(PC1)分发zookeeper目录
在/opt/modules目录下
$ scp -r zookeeper/ feng.com:/home/gu/ruan
5)修改第2(PC2)、3(PC3)台的myid文件
vi myid
修改对应的id(根据conf/zoo.zfg中绑定到server.n的主机名对应)
6)启动(3台上)
$ bin/zkServer.sh start
7)检查进程
jps
3050 QuorumPeerMain
3111 Jps
8)检查并核对状态(3台上)
$ bin/zkServer.sh status
JMX enabled by default
Using config: /opt/modules/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: follower
JMX enabled by default
Using config: /opt/modules/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: follower
bin/zkServer.sh status
JMX enabled by default
Using config: /opt/modules/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: leader
9)访问zookeeper文件系统
在进程启动正常的情况下
$ bin/zkCli.sh connect feng.com:2181
[zk: localhost:2181(CONNECTED) 0] ls / --查看根目录
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /zookeeper --查看zookeeper目录
[quota]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper/quota
[]
[zk: localhost:2181(CONNECTED) 3] help --查看支持的所命令
ZooKeeper -server host:port cmd args
connect host:port
get path [watch]
ls path [watch]
set path data [version]
rmr path
四 Hadoop Ha (High avilable)
Namenode HA
集群规划(3台)
PC01PC02PC03
NameNodeNameNode
ZKFCZKFC
ResourceManager
DataNodeDataNodeDataNode
JournalNodeJournalNodeJournalNode
NodeManagerNodeManagerNodeManager
ZooKeeperZooKeeperZooKeeper
一)安装hadoop
二)配置环境文件
hadoop-env.sh
mapred-env.sh
yarn-env.sh
export JAVA_HOME=/opt/modules/jdk1.7.0_67
三)配置4个site.xml文件
1.========core-site.xml========
<!--NameNode HA的逻辑访问名称-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data</value>
</property>
2.=================hdfs-site.xml=============
<!-- 分布式副本数设置为3 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!--指定hdfs的nameservice为ns1,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!-- ns1下面有两个NameNode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>yu.com:8020</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>yu.com:50070</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>gcf.com:8020</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>gcf.com:50070</value>
</property>
<!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://yu.com:8485;gcf.com:8485;feng.com:8485/ns1</value>
</property>
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/opt/modules/hadoop-2.5.0/journal</value>
</property>
<!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行
sshfence:当Active出问题后,standby切换成Active,此时,原Active又没有停止服务,这种情况下会被强制杀死进程。
shell(/bin/true):NN Active和它的ZKFC一起挂了,没有人通知ZK,ZK长期没有接到通知,standby要切换,此时,standby调一个shell(脚本内容),这个脚本返回true则切换成功。
-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔离机制超时时间 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
<!-- 关闭权限检查用户或用户组 -->
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
3.=============mapred-site.xml
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>yu.com:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>yu.com:19888</value>
</property>
4.============yarn-site.xml
<property>
<name>yarn.resourcemanager.hostname</name>
<value>feng.com</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
5.=================slaves
yu.com
gcf.com
feng.com
四)分发配置
$ scp etc/hadoop/core-site.xml etc/hadoop/hdfs-site.xml etc/hadoop/slaves etc/hadoop/yarn-site.xml /etc/hadoop/ feng.com:/home/gu/ruan/hadoop-2.5.0/etc/hadoop/
$ scp etc/hadoop/core-site.xml etc/hadoop/hdfs-site.xml feng.com:/opt/modules/hadoop-2.5.0/etc/hadoop/
五)启动HDFS HA
## 注意:每一个步骤都严格按照以下步骤执行
1.删除data和logs目录(3台上,有必须删掉)
$ rm -rf data logs
2.启动zk(3台上都要)
$ bin/zkServer.sh start
3.启动journalnode(3台上都要)
$ sbin/hadoop-daemon.sh start journalnode
4.[nn1]格式化namenode(PC1 也就是nn1)
$ bin/hdfs namenode -format
$ sbin/hadoop-daemon.sh start namenode
5.[nn2]同步nn1的元数据(PC2 也就是nn2)
$ bin/hdfs namenode -bootstrapStandby
$ sbin/hadoop-daemon.sh start namenode
6.查看web界面
http://yu.com:50070 ##standby
http://gcf.com:50070 ##standby
7.手动切换namenode的状态
$ bin/hdfs haadmin -transitionToActive nn1 ##切换active
$ bin/hdfs haadmin -transitionToStandby nn1 ##切换成standby
六)开启故障自动转移
1.配置故障转移
1)=====core-site.xml
<property>
<name>ha.zookeeper.quorum</name>
<value>yu.com:2181,gcf.com:2181,feng.com:2181</value>
</property>
2)====hdfs-site.xml
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
2.分发配置文件
$ scp etc/hadoop/core-site.xml etc/hadoop/hdfs-site.xml feng.com:/home/gu/ruan/hadoop-2.5.0/etc/hadoop/
3.启动故障转移服务
1)首先停止hdfs和zk
$ sbin/stop-dfs.sh
$ bin/zkServer.sh stop##关闭zk(3台服务器)
重启
$ bin/zkServer.sh start##启动zk(3台服务器)
2)初始化zkfc[PC1也就是nn1]
$ bin/hdfs zkfc -formatZK ##初始化ZKFC
17/03/27 16:49:18 INFO ha.ActiveStandbyElector: Successfully created /hadoop-ha/ns1 in ZK.
$ sbin/start-dfs.sh##启动hdfs
bin/hdfs haadmin -getServiceState nn1 #查看nn1状态
bin/hdfs haadmin -getServiceState nn2 #查看nn2状态
[PC1]
[hadoop@hadoop hadoop-2.5.0]$ jps
4196 JournalNode
4356 DFSZKFailoverController
4012 DataNode
3920 NameNode
3586 QuorumPeerMain
4458 Jps
[PC2]
[hadoop@hadoop hadoop-2.5.0]$ jps
4117 Jps
3849 DataNode
3786 NameNode
3926 JournalNode
3633 QuorumPeerMain
4045 DFSZKFailoverController
[PC3]
[hadoop@hadoop hadoop-2.5.0]$ jps
3387 DataNode
3461 JournalNode
3551 Jps
3231 QuorumPeerMain
五、ResourceManager HA
一、集群规划(3台)
PC01PC02PC03
NameNodeNameNode
ZKFCZKFC
ResourceManagerResourceManager
DataNodeDataNodeDataNode
JournalNodeJournalNodeJournalNode
NodeManagerNodeManagerNodeManager
ZooKeeperZooKeeperZooKeeper
二、修改配置文件
=====yarn-site.xml
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
<!--启用resourcemanager ha-->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>rmcluster</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>gcf.com</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>feng.com</value>
</property>
<!--指定zookeeper集群的地址-->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>yu.com:2181,gcf.com:2181,feng.com:2181</value>
</property>
<!--启用自动恢复-->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!--指定resourcemanager的状态信息存储在zookeeper集群-->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
三、分发配置文件
将yarn-site.xml分发到其他两台
scp etc/hadoop/yarn-site.xml gcf.com:/opt/modules/hadoop-2.5.0/etc/hadoop/
scp etc/hadoop/yarn-site.xml feng.com:/opt/modules/hadoop-2.5.0/etc/hadoop/
四、启动ResourceManagere
在PC2上:
sbin/start-yarn.sh
在pc3上单独启动:
sbin/yarn-daemon.sh start resourcemanager
【PC1】
jps
5468 DataNode
5934 NodeManager
5653 JournalNode
5820 DFSZKFailoverController
5371 NameNode
3586 QuorumPeerMain
6058 Jps
【PC2】
jps
5023 NodeManager
4825 DFSZKFailoverController
4554 NameNode
4621 DataNode
4714 JournalNode
5359 Jps
4927 ResourceManager
3633 QuorumPeerMain
[PC3]
$ jps
3792 DataNode
3986 NodeManager
3881 JournalNode
4178 Jps
4120 ResourceManager
3231 QuorumPeerMain
Day07
一、HDFS使用讲解
1.测试NameNode HA
-在处于active的Namenode上使用kill -9 pid(NameNode)
-在web界面查看切换结果
2.Namenode元数据在本地存放的目录
[扩展] 安装tree
切换root用户
# yum install tree -y
/opt/modules/hadoop-2.5.0/data/dfs/name/current/
元数据
├── fsimage_0000000000000000256
├── fsimage_0000000000000000256.md5
├── fsimage_0000000000000000316
├── fsimage_0000000000000000316.md5
edit文件
├── edits_0000000000000000001-0000000000000000002
├── edits_0000000000000000003-0000000000000000004
├── edits_0000000000000000005-0000000000000000006
├── edits_0000000000000000007-0000000000000000008
├── edits_0000000000000000009-0000000000000000010
正在写入的日志文件
├── edits_inprogress_0000000000000000360
3.HDFS block的元数据本地存储
/opt/modules/hadoop-2.5.0/data/dfs/data/current/
├── dfsUsed
│ │ │ │ │ ├── finalized
│ │ │ │ │ │ ├── blk_1073741835
│ │ │ │ │ │ ├── blk_1073741835_1011.meta
│ │ │ │ │ │ ├── blk_1073741836
│ │ │ │ │ │ ├── blk_1073741836_1012.meta
│ │ │ │ │ │ ├── blk_1073741837
│ │ │ │ │ │ ├── blk_1073741837_1013.meta
│ │ │ │ │ │ ├── blk_1073741838
│ │ │ │ │ │ ├── blk_1073741838_1014.meta
│ │ │ │ │ │ ├── blk_1073741839
│ │ │ │ │ │ └── blk_1073741839_1015.meta
4.程序开发中如何访问hdfs
hdfs://ns1/input
5.使用IDE开发MapRedcue或者HDFS API
-在工程下面创建source folder
src/resource
-将当前namenode HA的配置文件core-site.xml hdfs-site.xml拷贝到工程中的src/resource
二、ResouceManager的使用讲解
1.查看ResourceManager的状态
$ bin/yarn rmadmin -getServiceState rm1
active##查看rm1的状态
$ bin/yarn rmadmin -getServiceState rm2 ##查看rm2的状态
standby
2.在web界面,如果访问的是处于standby状态的resoucemanager会提示以下信息,并且会自动跳转到处于active的那台上
This is standby RM. Redirecting to the current active RM: http://feng.com:8088/
三、Namenode 联盟 联邦
Namenode 的水平扩展
每个Namenode 相当于一个州(51个,每一个都比较自治),组合起来就是一个美联邦政府
相当于硬盘分区 每一个分区(C D E F 盘),独立访问
业务隔离
方便管理
Federation即为“联邦”,该特性允许一个HDFS集群中存在多个NameNode同时对外提供服务,这些NameNode分管一部分目录(水平切分),彼此之间相互隔离,但共享底层的DataNode存储资源。
Namenode1(业务1) namenode2(业务2) namenode3(业务3)
*存储空间充分利用
*业务隔离,分类管理
四、配置NameNode联盟
一)、集群规划
==集群规划
PC01 PC02 PC03
hadoop-senior01hadoop-senior02hadoop-senior03
namenode namenode
datanode datanode datanode
二)、修改配置文件
======core-site.xml=======
[PC1]
<property>
<name>fs.defaultFS</name>
<value>hdfs://yu.com:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data</value>
</property>
***********需要单独修改
[PC2]
<property>
<name>fs.defaultFS</name>
<value>hdfs://gcf.com:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/modules/hadoop-2.5.0/data</value>
</property>
**************
=========hdfs-site.xml===========
<!-- 分布式副本数设置为3 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.nameservices</name>
<value>ns1,ns2</value>
</property>
<!-- ns1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1</name>
<value>yu.com:8020</value>
</property>
<!-- ns1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1</name>
<value>yu.com:50070</value>
</property>
<!-- ns2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns2</name>
<value>gcf.com:8020</value>
</property>
<!-- ns2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns2</name>
<value>gcf.com:50070</value>
</property>
==========mapred-site.xml=========
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>yu.com:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>yu.com:19888</value>
</property>
===========yarn-site.xml=========
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>feng.com</value>
</property>
三)、分发配置文件
scp etc/hadoop/core-site.xml etc/hadoop/hdfs-site.xml etc/hadoop/mapred-site.xml etc/hadoop/yarn-site.xml gcf.com:/opt/modules/hadoop-2.5.0/etc/hadoop/
scp etc/hadoop/core-site.xml etc/hadoop/hdfs-site.xml etc/hadoop/mapred-site.xml etc/hadoop/yarn-site.xml feng.com:/opt/modules/hadoop-2.5.0/etc/hadoop/
四)、在ns1(PC1)和ns2(PC2)上执行
bin/hdfs namenode -format -clusterId hdfs-cluster
$ sbin/hadoop-daemon.sh start namenode
五)、启动所有节点的datanode
sbin/hadoop-daemon.sh start datanode
[PC1]
[hadoop@hadoop hadoop-2.5.0]$ jps
2761 DataNode
4478 Jps
2686 NameNode
[PC2]
[hadoop@hadoop hadoop-2.5.0]$ jps
4851 Jps
2769 DataNode
2694 NameNode
[PC3]
[hadoop@hadoop hadoop-2.5.0]$ jps
4682 Jps
2654 DataNode
五、【案例:二次排序】
name money
zhangsan 125
lisi 135
wangwu 60
zhangsan 56
wangwu 80
lisi 650
zhangsan 50
wangwu 6
lisi 900
二次排序:第一次排要求按照姓名的首字母进行排
第二次排序要求按照同一个人的消费金额进行排
分析实现的思路
key#value value
统计结果
lisi 135
lisi 650
lisi 900
wangwu 6
wangwu 60
wangwu 80
zhangsan 50
zhangsan 56
zhangsan 125
使用默认分组 PairWritable
lisi,900 [ 900 ]
lisi,650 [ 650 ]
lisi,135 [ 135 ]
wangwu,80 [ 80 ]
wangwu,60 [ 60 ]
wangwu,6 [ 6 ]
zhangsan,125 [ 125 ]
zhangsan,56 [ 56 ]
zhangsan,50 [ 50 ]
使用自定义分组 PairWritable.getFisrt()
lisi,900 [ 900 650 135 ]
wangwu,80 [ 80 60 6 ]
zhangsan,125 [ 125 56 50 ]
七.Join
1.map Join
适用场景:一个大表、一个小表的情况 25MB
在map端,小表会被加载到处理大表的block的map方法所在的NodeManager的内存中,具体方式是重写Mapper类的setup()方法,将小表的数据从HDFS读出来,保存到某一个变量中,在map()方法中,就可以读取到小表的数据和大表的数据,然后先进行join,join的结果大大减小,这样,就可以减小网络和磁盘的IO,降低reduce()方法处理数据的压力。
2.reduce Join
适用场景:两个大表的情况
两张表通常都是大文件,Join的操作是在Reduce端执行,由于文件过大,载入内存是不现实的,可以在发送到reduce之后再进行join.
每次在map端得到数据之后,就打一个标签将标签和数据一起发送到reduce,在reduce端根据标签和具体的业务需求完成join
3.semi Join(半连接)
适用场景:一张小表、一张大表
将小表加载到map端执行大表所在的NodeManager的内存中,在map()方法执行的时候,会过滤掉无用的数据,将参与join的数据传输到reduce端,在reduce端完成真正的join过程,这种方式就是semi join,是reduce join的一种特例
==========================================================================
reduce join实现
customer.txt
1,Stephanie Leung,555-555-5555
2,Edward Kim,123-456-7890
3,Jose Madriz,281-330-8004
4,David Stork,408-555-0000
order.txt
3,A,12.95,02-Jun-2008
1,B,88.25,20-May-2008
2,C,32.00,30-Nov-2007
3,D,25.02,22-Jan-2009
代码实现:
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;
public class CustomerOrderBean implements Writable{
private String flag;
private String data;
@Override
public String toString() {
return flag + "," + data;
}
public void set(String flag, String data) {
this.flag = flag;
this.data = data;
}
public CustomerOrderBean() {
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public void write(DataOutput out) throws IOException {
out.writeUTF(flag);
out.writeUTF(data);
}
public void readFields(DataInput in) throws IOException {
this.flag = in.readUTF();
this.data = in.readUTF();
}
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class CustomerOrderMapReduce {
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//1.get Job
Job job = Job.getInstance(configuration);
//2.set Jar
job.setJarByClass(CustomerOrderMapReduce.class);
//3.set Mapper
job.setMapperClass(CustomerOrderMapper.class);
job.setMapOutputKeyClass(LongWritable.class);
job.setMapOutputValueClass(CustomerOrderBean.class);
//3.5 set Partition
//job.setPartitionerClass(MyPartitioner.class);
//set number of Reducer
//job.setNumReduceTasks(new Integer(args[2]));
//job.setNumReduceTasks(3);
//3.6 set Combiner
//job.setCombinerClass(PVReducer.class);
//4.set Reducer
job.setReducerClass(CustomerOrderReducer.class);
job.setOutputKeyClass(LongWritable.class);
job.setOutputValueClass(Text.class);
//5.PathIn PathOut
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//6.submit
job.waitForCompletion(true);
}
public static class CustomerOrderMapper extends Mapper<LongWritable, Text, LongWritable, CustomerOrderBean>{
CustomerOrderBean bean = new CustomerOrderBean();
LongWritable k = new LongWritable();
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String[] split = value.toString().split(",");
/**
* 数组的长度等于3的时候,说明是customer表的数据
* 1,Stephanie Leung,555-555-5555
*/
if (split.length == 3) {
bean.set("customer", split[1]+","+split[2]);
k.set(Long.valueOf(split[0]));
context.write(k, bean);
}
/**
* 说明是order表 的数据
* 3,A,12.95,02-Jun-2008
*/
if (split.length == 4) {
bean.set("order", split[1]+","+split[2]+","+split[3]);
k.set(Long.valueOf(split[0]));
context.write(k, bean);
}
}
}
/**
* key:value
* 1:{(customer,Stephanie Leung,555-555-5555)(order,B,88.25,20-May-2008)}
* ...
* ...
*/
public static class CustomerOrderReducer extends Reducer<LongWritable, CustomerOrderBean, LongWritable, Text>{
Text v = new Text();
@Override
protected void reduce(LongWritable key,
Iterable<CustomerOrderBean> iterable,
Context context)
throws IOException, InterruptedException {
String customerStr = null;
List<String> orderList = new ArrayList<String>();
for (CustomerOrderBean bean : iterable) {
String flag = bean.getFlag();
//如果flag等于customer说明是customer表的数据
if (flag.equals("customer")) {
//customerStr = "Stephanie Leung,555-555-5555";
customerStr = bean.getData();
}else {
//"B,88.25,20-May-2008"
orderList.add(bean.getData());
}
}
/**
* Join过程
*/
for (String orderData : orderList) {
v.set(customerStr+","+orderData);
context.write(key, v);
}
}
}
}
结果
1 Stephanie Leung,555-555-5555,B,88.25,20-May-2008
2 Edward Kim,123-456-7890,C,32.00,30-Nov-2007
3 Jose Madriz,281-330-8004,D,25.02,22-Jan-2009
3 Jose Madriz,281-330-8004,A,12.95,02-Jun-2008
=================================================
当map读取源文件时,如何区分出是File1还是File2
joinMapper()<>{
FileSplit fileSplit = (FileSplit)context.getInputSplit();
String path = fileSplit.getPath().getname().toString();
path文件来源路径+文件名
if(path.contains("tab1")){
数据来源于File1
按指定字符区切分
String strs = valuse.split("\t");
mapoutkey.set(strs[0])
mapoutvalue.set("tag1"+strs[1,]+"\t"+...)
context.write(mapoutkey,mapoutvalue)
}
if(path.contains("tab2")){
数据来源于File2
按指定字符区切分
String strs = valuse.split("\t");
mapoutkey.set(strs[0])
mapoutvalue.set("tag2"+strs[1,]+"\t"+...)
context.write(mapoutkey,mapoutvalue)
}
补充:
3、hadoop2.x与Hadoop1.x区别:
(1)2.x比1.x从性能上有很大增强
(2)Hadoop1中的JobTracker是一个功能集中的部分,负责资源的分配和任务的分配,所以JobTracker单点出问题就会造成整个集群无法使用了,而且MapReduce模式是集成在Hadoop1中,不易分解;Hadoop2中,ResourceManager(RM)就是负责资源的分配,NodeManager(NM)是从节点上管理资源的,而ApplicationMaster(AM)就是一个负责任务分配的组件,根据不同的模式有不同的AM,因此MapReduce模式有自己独有的AM;
(3)1.x版本没有Namenode Federation功能,只能有一个NameNode;而2.x添加了,还可以有多个NameNode同时运行,每个负责集群中的一部分 (4)1.x版本没有Namenode Ha功能,只能有一个NameNode;而2.x添加了,解决了namenode单点故障问题 (5)解决对MapReduce之外的框架支持问题。
4、HDFS数据安全性如何保证
1)、存储在HDFS系统上的文件,会分割成128M大小的block存储在不同的节点上,block的副本数默认3份,也可配置成更多份;
2)、第一个副本一般放置在与client(客户端)所在的同一节点上(若客户端无datanode,则随机放),第二个副本放置到与第一个副本同一机架的不同节点,第三个副本放到不同机架的datanode节点,当取用时遵循就近原则;
3)、datanode已block为单位,每3s报告心跳状态,做10min内不报告心跳状态则namenode认为block已死掉,namonode会把其上面的数据备份到其他一个datanode节点上,保证数据的副本数量;
4)、datanode会默认每小时把自己节点上的所有块状态信息报告给namenode;
5)、采用safemode模式:datanode会周期性的报告block信息。Namenode会计算block的损坏率,当阀值<0.999f时系统会进入安全模式,HDFS只读不写。 HDFS元数据采用secondaryname备份或者HA备份
6、MapReduce运行流程?
1).首先对输入数据源进行切片
2).master调度worker执行map任务
3).worker读取输入源片段
4).worker执行map任务,将任务输出保存在本地
5).master调度worker执行reduce任务,reduce worker读取map任务的输出文件
6).执行reduce任务,将任务输出保存到HDFS
==================================总结===============================
1.Hadoop是什么、生态系统组件功能?
答:1).Hadoop是一个能够对大量数据进行分布式处理的软件框架。具有可靠、高效、可伸缩的特点。
2).HDFS,MapReduce,Hive,ZooKeeper,Yarn等
2.简要叙述一下YARN的功能、如何分配资源调度应用的,以运行MapReduce WordCount程序为例。
答:1).client向yarn提交job,首先找ResourceManager分配资源(CPU 内存),
2).ResourceManager开启一个Container,在Container中运行一个Application manager
3).Application manager找一台nodemanager启动Application master,计算任务所需的计算
4).Application master向Application manager(Yarn)申请运行任务所需的资源
5).Resource scheduler将资源封装发给Application master
6).Application master将获取到的资源分配给各个nodemanager
7).各个nodemanager得到任务和资源开始执行map task
8).map task执行结束后,开始执行reduce task
9).map task和 reduce task将执行结果反馈给Application master
10.Application master将任务执行的结果反馈Application manager
如:单词统计,分隔符是\t
hadoopmapreduce
sparkstorm
maphadoopmapreduce
reducestormhadoop
hbasemapstorm
$map 输入
$按行读取数据,然后转换成key-value key 为偏移量 value为这一行数据
<0,hadoopmapreduce>
<13,sparkstorm>
<24,maphadoopmapreduce>
<41,reducestormhadoop>
<52,hbasemapstorm>
** map 输出
<hadoop,1> <mapreduce,1> <spark,1> <storm,1> <map,1> <hadoop,1> ...
$ 中间结果临时存储在本地目录,而非HDFS
$ reduce
$ 从相关nodemanager拉取map输出的结果
$ 运行reduce函数
$ 输入 reduce 的输入就是Map的输出
<hadoop,(1,1,1)> <storm,(1,1,1)> <hbase,1> ...
$ 输出
hadoop3
storm3
hbase1 ...
$ 结果写入HDFS
hadoop3
storm3
hbase1 ...
3.描述MapReduce中的map和reduce执行过程?
答:MapReduce分布式并行计算框架,分而治之的思想 编程模型
1).一个简单的MapRedcue包含两个过程,一个Map阶段(map 映射),一个Reduce(化简)阶段
2).第一个阶段Map Task,并发的各司其职的读取,完全并行
3).第二个阶段Redcue Task,处理的数据要依赖于map阶段 reduce个数少于map个数
4).整个过程是以key value形式进行数据传递
input(/input) -》 Map Task -》 Reduce task -》 output(/out)
4.HDFS HA集群中,ZooKeeper作用是什么?JournalNode作用是什么?由谁负责fsimage和edits文件的合并工作,并且是如何合并的?
答:1).Zookeeper (文件系统 角色 选举机制 watch)
$NameNode启动,然后向Zookeeper,触发注册事件,同时会创建一个唯一的目录
$通过心跳信息,来确认节点的状态(存活或者宕机)
$如果宕机,失去心跳信息,触发节点丢失事件,删除这个目录
2).两个NameNode为了数据同步,会通过JournalNodes的进程进行相互通信。当active状态的NameNode的命名空间有任何修改时,会告知大部分的JournalNodes进程。standby状态的NameNode有能力读取JNs中的变更信息,并且一直监控edit log的变化,把变化应用于自己的命名空间。standby可以确保在集群出错时,命名空间状态已经完全同步。
3).SecondaryNameNode.合并流程:当开始合并的时候,SecondaryNameNode会把fsimage和edits复制到自己服务器的内存中,开始合并,合并后生成一个叫fsimage.ckpt*的文件。将fsimage.ckpt*文件复制到NameNode上,成功后将原有的fsiamge删除,并将fsimage.ckpt*文件重新命名fsimage。当Secondarynamenode将edits和fsimage拷贝走之后,NameNode会立刻生成一个edits.new文件,用于记录新来的元数据,当合并完成之后,原有的edits文件才会被删除,并将edits.new文件重命名为edits文件。
5.HDFS的存储机制是什么及如何保证数据安全性?
答:遵循:一次写入多次读取,就近原则
$ 第一个副本放在运行客户端程序的节点,如果该节点位于集群外,就随机选择一个节点
$ 第二个副本放在和第一个副本不同机架的随机节点
$ 第三个副本放在与第二副本同一机架的随机节点
$ 如果需要存放其他副本,则在集群中随机选择其他节点,系统会尽量避免过多副本集中在同一个机架的现象
6.简要描述如何安装配置一个Apache开源版的Hadoop(2.5.0版本),完全分布式,列出步骤及注意点
答:Hadoop分布环境搭建的步骤:
1).环境准备(同时要规划节点)
静态Ip地址的配置(包括DNS)
主机名称的更改
配置所需的映射
防火墙的关闭
各节点规划是否合理
创建一个普通用户。
2).JDK的安装
环境的配置
# vi /etc/profile(root用户)
3).hadoop的安装(实际上就是在对应的目录下解压安装)
环境的配置
hadoop-env.sh mapred-env.sh yarn-env.sh
文件的配置
hdfs-site.xml core-site.xml mapred-site.xml yarn-site.xml
格式化(在没有报错的时候)
$ bin/hdfs namenode -format
在命令行开启相对应的进程
Jps检查是否开启
测试环境是否存在问题
Web:
http://对应的IP地址或主机名:50070/ HDFS中的文件或目录显示是否正常(默认会有tmp目录,
如果没有可以通过新建一个目录来查看)
http://对应的IP地址或主机名:8088/
7.现有如下文件:trans.txt,账号,时间(yyyy-MM-dd),金额
请简要说明一下如何使用MapReduce,得到按账号升序,账号年消费额降序排列的结果文件?
1,2015-02-13,234.45
1,2015-04-12,56778
2,2016-12-03,45.32
...
答:选用Join
map阶段:
map task依次读取两个文件,切割,并设置key和value,取cid为key,同时给文件的value打一个标签,及判定为日期在前面打上d(后续按升序排序),判定为消费额在前面打上m(后续按降序排序)。
reduce阶段:
将相同key的Value合并放在一起。
8.描述MapReduce中的二次排序的思路
答: $ MapReduce特性:自动对key进行排序
$ 把需要排序的第一字段和第二字段组合成一个新的key
(可选)
$ 修改分区规则--针对原始key进行分区
$ 修改分组规则--针对原始key进行分组
具体实现:
$ 自定义Key数据类型,实现WritableComparable接口
(可选)
$ 自定义分区函数类,实现Partitioner接口
$ 自定义分组类
$ 继承WritableComparator类
$ 继承RawComparator接口
9.分别描述namenode、datanode、secondnamenode的作用
答:1).namenode 是资源(内存、CPU等)的管理者负责资源的调度。同时管理文件系统的元数据,及块和节点之间的关系,用户对文件的操作信息。
2).每个集群节点均有一个从属DataNode,它为读/写请求提供服务以及按照NameNode的指令执行数据块创建、删除和复制。
3).secondnamenode的整个目的是在HDFS中提供一个检查点。它只是namenode的一个助手节点。及负责fsimage和edits文件的合并操作。
10)描述HDFS中block的存放策略,以及按自己的理解说出该策略的优点。
答:1).采用block之后文件可以非常大,因为block可以存储在集群上的任一台机器上。(这样就具有了分布式文件系统的基础,比如可以做负载平衡,可以做冗余以避免文件的损坏或机器故障等。)
2).存储子系统的职责单一化。(只负责block的读写,文件的权限控制等可由其它系统负责。)
3).采用replication策略实现高可用性更适宜。(当某个block不可访问时,HDFS将自动复制相应的块从而维持备份的次数。)
4).方便于管理(备份、恢复、删除)。
5).提高文件的读写速度。
6).减轻cpu和内存的压力。
7).适合处理比较大的文件。(小文件不占优势)