1、数据加工整体的流向
1.1、业务交互数据 -后端埋点数据
业务流程中产生的登录、订单、用户、商品、支付等数据,通常存储在DB中,MySQL、oracle中
web/app业务交互 - 业务服务器 - mysql业务数据(业务日志数据) - sqoop上传到hdfs
①业务数据上传到mysql数据库中,有些表需要每天进行更新,便于较少数据的增删改查;
②mysql将数据通过sqoop上传到hdfs上,sqoop上传时,运行时间比较长;
1.2、前端埋点用户行为数据
与产品发生交互的数据,用户的曝光,点击,停留,评论等
①埋点数据存储在特定的linux目录中;
②启动flume将数据上传到kafka中的数据,再启动flume消费kafka中的数据;
③通过sink到hdfs的指定目录。
2、hdfs相关
2.1、hdfs的读写
1.hdfs写流程
①block:文件上传需要分块,一般为128M,可以改
块太小,寻址时间占比过高,块太大,Map任务数太少,作业执行速度变慢
②packet:由client到datanode,是datanode和pipline之间传数据的最小单位,默认64k
③chunk:由client到datanode,是datanode和pipline之间 进行数据校验的基本单位,默认512byte
1)客户端向namenode发出写文件请求;
2)检查是否已存在文件、检查权限。若已通过检查,直接先将操作写入EditLog,并返回输出流对象;
3)client按照128M划分文件;
4)client将namenode返回的分配的可写的DataNode列表和Data数据一同发送给最近的第一个namenode节点,此后client端 和namenode分配的多个Datanode构成pipline管道,client端向输出流对象写数据,client每向第一个DataNode写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode。;
5)每个datanode写完一个块,会返回确认信息;
***正确的做法是写完一个block块后, 对packet中的每个chunk校验信息进行汇总
6)写完数据,关闭输出流;
7)发送完成信号给namenode。
***发送完成信号的时机取决于集群是强一致性还是最终一致性,强一致性则需要所有DataNode写完后才向NameNode汇报。最终一致性则其中任意一个DataNode写完后就能单独向NameNode汇报,HDFS一般情况下都是强调强一致性。
2.hdfs读流程
1)client访问NameNode,查询元数据信息,获得这个文件的数据块位置列表,返回输入流对象。
2)就近挑选一台datanode服务器,请求建立输入流 。
3)DataNode向输入流中中写数据,以packet为单位来校验。
4)关闭输入流
3.hdfs的体系结构
主要由四部分组成,分别为HDFS Client,NameNode,DataName和Secondary NameNode
1)client客户端:访问HDFS的程序和HDFS shell命令,通过与 NameNode和DataNode 交互访问HDFS中的文件,
HDFS客户端就是用来访问这个hadoop文件系统的机器,它可以是装有hadoop的机器,也可以是没有装hadoop的机器。
2)Namenode就是HDFS的master架构,管理节点,存储并管理元数据,主要负责HDFS文件系统的管理工作,包括名称空间管理,文件Block管理。
①名称空间管理:文件系统树(filesystem tree)以及文件树中所有的文件和文件夹的元数据(metadata);
②文件Block管理:每个文件中各个块所在的数据节点的位置信息。
3)DataNode
负责存储数据的组件,一个数 据块Block会在多个DataNode中进行冗余备份;而一个DataNode对于一个块最多只包含一个备份
4)Secondary NameNode
从NameNode获得fsimage和edits后把两者重新合并发给NameNode,这样,既能减轻NameNode的负担又能安全地备份,一旦HDFS的Master架构失效,就可以借助Secondary NameNode进行数据恢复。
2.2、mapjoin的原理
通常用于一个很小的表和一个大表的连接
①map阶段进行表之间的连接,map阶段直接拿另外一个表的数据和内存中表的数据匹配
②不需要到reduce阶段才进行连接,节省了shuffle阶段时要进行的大量数据传输。
2.3、hadoop的shuffle的原理
2.4、工作中的hadoop的小文件处理,结合项目进行说明
小文件:文件大小要比一个hdfs块大小小很多的文件,一般块=128M
2.4.1、负面影响
①小文件的存在占用大量NameNode内存,从而影响HDFS的横向扩展能力
②MapReduce任务处理小文件,每个Map会处理一个HDFS块,导致程序启动大量mqp来处理这些任务
③HDFS上每个文件都要在NameNode上建立一个索引,这个索引的大小约为150byte,这样当小文件比较多的时候,就会产生很多的索引文件,一方面会大量占用NameNode的内存空间,另一方面就是索引文件过大使得索引速度变慢。
2.4.2、HDFS自带的小文件处理
①文件归档存储
将文件再次进行整理和保存,通过二层索引文件查找,进行最终目录的读取
归档文件不可修改
②使用序列文件存储
由一系列的二进制对组成,key为文件名,value为文件内容
写一个程序将小文件放入单一的序列文件中。
③合并小文件输入
将一个目录作为一个map的输入,而不是一个文件进行输入
从指定目录下的多个文件进行分片,不同文件可以放入不同的poll,一个分片只能包含一个pool中的文件。
--每个map最大输入大小
set mapred.max.split.size = 256000000
--一个节点上split的至少大小
set mapred.min.split.size.per.node = 10000000
--一个交换机split至少的大小
set mapred.min.split.size.per.rack
--执行map前进行小文件的合并
hive.input.format = org.apache。Hadoop.hive.ql.io.CombineHiveInputFormat
2.8、优化
2.8.1、数据输入
① 合并小文件:在执行MR任务前将小文件进行合并,大量的小文件会产生大量的Map任务,增大Map任务装载次数,而任务的装载比较耗时,从而导致MR运行较慢。
② 采用CombineTextImputFormat来作为输入,解决输入端大量小文件场景。
2.8.2、Map阶段
① 减少溢写(Spill)次数:通过调整io.sort.mb及sort.spill.percent参数值,增大触发Spill的内存上限,减少Spill次数,从而减少磁盘IO。
② 减少合并(Merge)次数:通过调整io.sort.factor参数,增大Merge的文件数目,减少Merge的次数,从而缩短MR处理时间。
③ 在Map之后,不影响业务逻辑前提下,先进行Combine处理,减少I/O。
2.8.3、Reduce阶段
① q合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致Map、Reduce任务间竞争资源,造成处理超时等错误。
(2)设置Map、Reduce共存:调整slowstart.completedmaps参数,使Map运行到一定程度后,Reduce也开始运行,减少Reduce的等待时间。
(3)规避使用Reduce:因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
(4)合理设置Reduce端的Buffer:默认情况下,数据达到一个阈值的时候,Buffer中的数据就会写入磁盘,然后Reduce会从磁盘中获得所有的数据。也就是说,Buffer和Reduce是没有直接关联的,中间多次写磁盘>读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得Buffer中的一部分数据可以直接输送到Reduce,从而减少IO开销:mapreduce.reduce.input.buffer.percent,默认为0.0。当值大于0的时候,会保留指定比例的内存读Buffer中的数据直接拿给Reduce使用。这样一来,设置Buffer需要内存,读取数据需要内存,Reduce计算也要内存,所以要根据作业的运行情况进行调整。
2.8.4、I/O传输
(1)采用数据压缩的方式,减少网络IO的的时间。安装smappy和LZO压缩编码器。
(2)使用SequenceFile二进制文件。
2.8.5、常用的调优参数
(1)以下参数是在用户自己的MR应用程序中配置就可以生效(mapred-default.xml)
mapreduce.map.memory.mb一个MapTask可使用的资源上限(单位:MB),默认为1024。如果MapTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.reduce.memory.mb 一个ReduceTask可使用的资源上限(单位:MB),默认为1024。如果ReduceTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.map.cpu.vcores 每个MapTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.cpu.vcores 每个ReduceTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.shuffle.parallelcopies 每个Reduce去Map中取数据的并行数。默认值是5
mapreduce.reduce.shuffle.merge.percent Buffer中的数据达到多少比例开始写入磁盘。默认值0.66
mapreduce.reduce.shuffle.input.buffer.percent Buffer大小占Reduce可用内存的比例。默认值0.7
mapreduce.reduce.input.buffer.percent 指定多少比例的内存用来存放Buffer中的数据,默认值是0.0
(2)应该在YARN启动之前就配置在服务器的配置文件中才能生效(yarn-default.xml)
yarn.scheduler.minimum-allocation-mb 给应用程序Container分配的最小内存,默认值:1024
yarn.scheduler.maximum-allocation-mb 给应用程序Container分配的最大内存,默认值:8192
yarn.scheduler.minimum-allocation-vcores 每个Container申请的最小CPU核数,默认值:1
yarn.scheduler.maximum-allocation-vcores 每个Container申请的最大CPU核数,默认值:32
yarn.nodemanager.resource.memory-mb 给Containers分配的最大物理内存,默认值:8192
(3)Shuffle性能优化的关键参数,应在YARN启动之前就配置好(mapred-default.xml)
mapreduce.task.io.sort.mb Shuffle的环形缓冲区大小,默认100m
mapreduce.map.sort.spill.percent 环形缓冲区溢出的阈值,默认80%
3、hive相关
3.1、hive的架构
Hive:由Facebook开源用于解决海量结构化日志的数据统计。
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
1)Hive的数据存储在hdfs上,简单的说hive就是hdfs的简单一种映射,比如:hive的一张表映射hdfs上的一个文件,hive的一个数据库就映射为hdfs上的文件夹
2)Hive是一个计算框架,他是MapReduce的一种封装,实际上他的底层还是MR,Hive就是用人们熟悉的sql对数据进行分析的
3)Hive执行程序是运行在Yarn上的
3.2、hive怎么解析成mr的
① Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree
② 遍历AST Tree,抽象出查询的基本组成单元QueryBlock
③ 遍历QueryBlock,翻译为执行操作树OperatorTree
④ 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
⑤ 遍历OperatorTree,翻译为MapReduce任务
⑥ 物理层优化器进行MapReduce任务的变换,生成最终的执行计划
3.3、hive和数据库比较,有哪些区别
3.3.1 查询语言
由于SQL被广泛的应用在数据仓库中,因此,专门针对Hive的特性设计了类SQL的查询语言HQL。熟悉SQL开发的开发者可以很方便的使用Hive进行开发。
3.3.2 数据存储位置
Hive 是建立在 Hadoop 之上的,所有 Hive 的数据都是存储在 HDFS 中的。而数据库则可以将数据保存在块设备或者本地文件系统中。
3.3.3 数据更新
由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的。而数据库中的数据通常是需要经常进行修改的,因此可以使用 INSERT INTO … VALUES 添加数据,使用 UPDATE … SET修改数据。
3.3.4 索引
Hive没有索引,在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中的某些Key建立索引。Hive要访问数据中满足条件的特定值时,需要暴力扫描整个数据,因此访问延迟较高。由于 MapReduce 的引入, Hive 可以并行访问数据,因此即使没有索引,对于大数据量的访问,Hive 仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了 Hive 不适合在线数据查询。
3.3.5 执行
Hive中大多数查询的执行是通过 Hadoop 提供的 MapReduce 来实现的。而数据库通常有自己的执行引擎。
3.3.6 执行延迟
Hive 在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致 Hive 执行延迟高的因素是 MapReduce框架。由于MapReduce 本身具有较高的延迟,因此在利用MapReduce 执行Hive查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive的并行计算显然能体现出优势。
3.3.7 可扩展性
由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是和Hadoop的可扩展性是一致的(世界上最大的Hadoop 集群在 Yahoo!,2009年的规模在4000 台节点左右)。而数据库由于 ACID 语义的严格限制,扩展行非常有限。目前最先进的并行数据库 Oracle 在理论上的扩展能力也只有100台左右。
3.3.8 数据规模
由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。
3.4、hive的优化,分区,分桶
3.4.1、分区
我们可以按照日期对数据表进行分区,不同日期的数据存放在不同的分区,在查询时只要指定分区字段的值就可以直接从该分区查找。
3.4.2、分桶
分桶将整个数据内容安装某列属性值得hash值进行区分
3.5、hive工作中常用的函数
1)窗口函数
① 排序
-- 自然序号排序,不跳数,不重复
ROW_NUMBER() over(partition by name order by c) c1,
-- 排序相同,中间会跳数,总数不变
RANK() over(partition by name order by c) c2,
-- 排序相同,中间不会跳数,总数会减少
DENSE_RANK() over(partition by name order by c) c3
② 切片
-- 将组内数据分成1片
ntile(1) over(partition by name order by orderdate) c1,
-- 将组内数据分成2片
ntile(2) over(partition by name order by orderdate) c2,
-- 将组内数据分成3片
ntile(3) over(partition by name order by orderdate) c3,
-- 将组内数据分成4片
ntile(4) over(partition by name order by orderdate) c4
③ lag和lead
-- 分组内当前行,往后第一行的值(不包括当前行)
lead(cost) over(partition by name order by cost) c1,
-- 分组内当前行,往后第二行的值(不包括当前行)
lead(cost,2) over(partition by name order by cost) c2,
-- 分组内当前行,往后第二行的值(不包括当前行),如果为null,则用9999代替
lead(cost,2,9999) over(partition by name order by cost) c3,
-- 分组内当前行,往前第一行的值(不包括当前行)
lag(cost) over(partition by name order by cost) c4,
-- 分组内当前行,往前第二行的值(不包括当前行)
lag(cost,2) over(partition by name order by cost) c5,
-- 分组内当前行,往前第二行的值(不包括当前行),如果为null,则用-1代替
lag(cost,2,-1) over(partition by name order by cost) c6
④ 聚合函数
count():统计行数
sum(col1):统计指定列和
avg(col1):统计指定列平均值
min(col1):返回指定列最小值
max(col1):返回指定列最大值
⑤条件函数
if(boolean,t1,t2):若布尔值成立,则返回t1,反正返回t2。如if(1>2,100,200)返回200
case when boolean then t1 else t2 end:若布尔值成立,则t1,否则t2,可加多重判断
coalesce(v0,v1,v2):返回参数中的第一个非空值,若所有值均为null,则返回null。如coalesce(null,1,2)返回1
isnull(a):若a为null则返回true,否则返回false
⑥字符串函数
length(string1):返回字符串长度
concat(string1,string2):返回拼接string1及string2后的字符串
concat_ws(sep,string1,string2):返回按指定分隔符拼接的字符串
lower(string1):返回小写字符串,同lcase(string1)。upper()/ucase():返回大写字符串
trim(string1):去字符串左右空格,ltrim(string1):去字符串左空格。rtrim(string1):去字符串右空格
repeat(string1,int1):返回重复string1字符串int1次后的字符串
reverse(string1):返回string1反转后的字符串。如reverse('abc')返回'cba'
rpad(string1,len1,pad1):以pad1字符右填充string1字符串,至len1长度。如rpad('abc',5,'1')返回'abc11'。lpad():左填充
split(string1,pat1):以pat1正则分隔字符串string1,返回数组。如split('a,b,c',',')返回["a","b","c"]
substr(string1,index1,int1):以index位置起截取int1个字符。如substr('abcde',1,2)返回'ab'
⑦时间函数
to_date(string timestamp):返回时间字符串中的日期部分,如to_date('1970-01-01 00:00:00')='1970-01-01'
current_date:返回当前日期
year(date):返回日期date的年,类型为int如year('2019-01-01')=2019
month(date):返回日期date的月,类型为int,如month('2019-01-01')=1
day(date): 返回日期date的天,类型为int,如day('2019-01-01')=1
weekofyear(date1):返回日期date1位于该年第几周。如weekofyear('2019-03-06')=10
datediff(date1,date2):返回日期date1与date2相差的天数,如datediff('2019-03-06','2019-03-05')=1
date_add(date1,int1):返回日期date1加上int1的日期,如date_add('2019-03-06',1)='2019-03-07'
date_sub(date1,int1):返回日期date1减去int1的日期,如date_sub('2019-03-06',1)='2019-03-05'
months_between(date1,date2):返回date1与date2相差月份,如months_between('2019-03-06','2019-01-01')=2
add_months(date1,int1):返回date1加上int1个月的日期,int1可为负数。如add_months('2019-02-11',-1)='2019-01-11'
last_day(date1):返回date1所在月份最后一天。如last_day('2019-02-01')='2019-02-28'
next_day(date1,day1):返回日期date1的下个星期day1的日期。day1为星期X的英文前两字母如next_day('2019-03-06','MO') 返回'2019-03-11'
trunc(date1,string1):返回日期最开始年份或月份。string1可为年(YYYY/YY/YEAR)或月(MONTH/MON/MM)。如trunc('2019-03-06','MM')='2019-03-01',trunc('2019-03-06','YYYY')='2019-01-01'
unix_timestamp():返回当前时间的unix时间戳,可指定日期格式。如unix_timestamp('2019-03-06','yyyy-mm-dd')=1546704180
from_unixtime():返回unix时间戳的日期,可指定格式。如select from_unixtime(unix_timestamp('2019-03-06','yyyy-mm-dd'),'yyyymmdd')='20190306'
⑧解析url函数
parse_url
⑨自定义函数
Hive使用python编写的自定义函数UDF进行ETL
Ⅰ、使用python脚本实现UDF函数
# -*- coding: utf-8 -*-
import sys
for line in sys.stdin:
detail = line.strip().split("\n")
detail_str = line.strip()
detail_list = detail_str.split("&")
detail_list = detail_list[4].split("=")
#print(detail_list)
data_key = 'spuid'
for item in detail_list:
#print(type(item))
if data_key in item:
item = item.replace('}','')
item = item[7:]
print("\n".join(item))
Ⅱ、将python脚本上传到集群
Ⅲ、使用UDF函数
ADD file /data/wcdstat_luna/udf/supid2/supid2.py;
insert overwrite table mtt_search.t_ed_mtt_search_test partition(ds=%YYYYMMDD%)
select
transform(targeturl) USING 'python supid2.py' as supid
from mtt_search.t_od_search_page_work_behavior
where ds=20210124
and targeturl like 'qb://wxapp/%'
and action in ('click','expose')
and guid rlike '^[a-z0-9]{32}$' and guid not rlike '^0{32}$'
and pagename='search_result' --是自建结果页
and platform_lc in ('android','iphone','android-ff','iphone-ff')
and moduletype='module'
and restypeid in ('841','842','843','844','846','847','8410','8420','8430','8440','8460','8470');
and targeturl = 'qb://wxapp/?appid=wx4cbd6b7f04b166ac&source=100004&sceneid=resultPage&c_sceneid=841&ext={entryScene:001,jump_from:2,spuid:102}&path=pages/searchExpress/index&need_backup=1'
3.6、hive导入/导出数据的方式
3.6.1、hive导出数据
EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])]
TO 'export_target_path' [ FOR replication('eventid') ]
eg:
bin/hive -e "EXPORT TABLE emp TO '/user/hive/exp/emp';
3.6.2、hive导入数据
IMPORT [[EXTERNAL] TABLE new_or_original_tablename [PARTITION (part_column="value"[, ...])]]
FROM 'source_path' [LOCATION 'import_target_path']
eg:
IMPORT TABLE db_hive.emp from '/user/hive/exp/emp/';
3.8、4个排序的区别
3.8.1、order by
对输出的结果进行全局排序,这就意味着只有一个reduce task时才能实现(多个reducer无法保证全局有序)但是当数据量过大的时候,效率就很低,速度会很慢。可以指定升序asc 降序desc
3.8.2、sort by
局部排序,只保证了每个reduce task中数据按照指定字段和排序方式有序排列。排序列必须出现在select column列表中,reduce task 的数量可以通过 set mapred.reduce.tasks=[num] 来设置,当reducer task数量设置为1时,相当于order by排序
3.8.3、distribute by
照指定的字段进行划分,将数据分到不同的输出reduce task中,通常与sort by一起使用,使用时distribute by必须放在前面。数据通过hash算法分到不同的task中。
-----先分组再排序
分组个数由reduce个数决定,分组内有序,但是不能保证分组外有序,可以指定升序还是降序
3.8.4、cluster by
cluster by 可以看做是一个特殊的distribute by+sort by,它具备二者的功能,但是只能实现正序排序的方式,不能指定排序方式
4、flume相关
Flume 是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。
4.1、flume的组件
4.1.1、source
数据源,负责将数据捕获后进行特殊的格式化,然后再封装在Event中,再将数据推入到Channel中
event是最小的数据单元,由header和body组成
4.1.2、channel
连接source和sink的组件,可以理解为数据缓冲区(数据队列),可以将event暂存在内存上,也可以持久化到本地磁盘上,直到sink消费完。
channel 中的数据直到进入到下一个channel中或者进入终端才会被删除。当 sink 写入失败后,可以自动重启,不会造成数据丢失,因此很可靠。
4.1.3、sink
数据下沉。从channel中取出数据后,分发到别的地方,比如HDFS或者HBase等,也可以是其他Agent的source。当日志数据量小的时候,可以将数据存在文件系统中,并设定一定的时间间隔来存储数据。
4.2、flume怎么采集数据的
4.2.1、埋点
①全埋点
前端的一种埋点方式,在产品中嵌入SDK
②代码埋点
1)前端代码埋点
前端埋点类似于全埋点,也需要嵌入SDK,不同的是对于每个事件行为都需要调用SDK代码,传入必要的事件名,属性参数等等,然后发到后台数据服务器。
2)后端代码埋点
后端埋点则将事件、属性通过后端模块调用SDK接口方式发送到后台服务器。
4.2.2、实时的埋点数据采集
①直接触发的日志发送到指定的HTTP端口,写入kafka,然后Flume消费kafka到HDFS
②用户访问日志落磁盘,在对应的主机上部署flume agent,采集日志目录下的文件,发送到kafka,然后在云端部署flume消费kafka数据到HDFS中
4.3、flume自定义拦截器
对较为敏感的数据进行MD5加密处理。
4.4、flume的数据积压,怎么解决?
4.4.1、数据挤压原因
启动flume之前,积压的数据过多,所以,source读得很快,而sink写hdfs速度有限,会导致反压
反压从下游传递到上游,上游的flume的运行日志中会不断报:channel已满,source重试。
4.4.2、解决方案
a. 如果资源允许,可以增加写入hdfs的agent机器数,通过负载均衡来提高整体吞吐量
b. 如果资源不允许,可以适当增大batchSize,来提高写入hdfs的效率
c. 如果资源不允许,可以配置数据压缩,来降低写入hdfs的数据流量
d. 如果source的数据流量不是恒定大于sink的写出速度,可以提高channel的缓存容量,来削峰
4.5、flume采集数据是否会丢失?
不会,Channel存储可以存储在File中,数据传输自身有事务。
4.6、HDFS sink小文件处理
4.6.1、HDFS存入大量小文件,有什么影响?
元数据层面:每个小文件都有一份元数据,其中包括文件路径,文件名,所有者,所属组,权限,创建时间等,这些信息都保存在Namenode内存中。所以小文件过多,会占用Namenode服务器大量内存,影响Namenode性能和使用寿命
计算层面:默认情况下MR会对每个小文件启用一个Map任务计算,非常影响计算性能。同时也影响磁盘寻址时间。
4.6.2、HDFS小文件处理
官方默认的这三个参数配置写入HDFS后会产生小文件,hdfs.rollInterval、hdfs.rollSize、hdfs.rollCount
基于以上hdfs.rollInterval=3600,hdfs.rollSize=134217728,hdfs.rollCount =0,hdfs.roundValue=10,hdfs.roundUnit= second几个参数综合作用,效果如下:
(1)tmp文件在达到128M时会滚动生成正式文件
(2)tmp文件创建超10秒时会滚动生成正式文件
5、MapReduce相关
5.1、MapReduce原理
5.2、
6、yarn相关
6.1、yarn概述
6.1.1、yarn是集群中的资源管理模块,为各类计算框架提供资源的管理和调度
①用于管理集群资源(服务器硬件,包括CPU,内存,磁盘,网络IO等);
②调度运行在yarn上的各种任务
***总而言之:调度资源,管理任务
6.1.2、核心出发点:分离资源管理和作业监控**
①全局资源管理 - RM
②每个应用程序对应一个应用资源管理 - AM
6.1.3、调度层级
①一级调度管理
计算资源管理(CPU,内存,磁盘,IO)
②二级调度管理
任务内部的计算模型管理(Appmaster的任务精细化管理)
6.1.4、整体调度流程
①client向RM提交计算任务
②RM的appilcations manager向nodemanager传递任务
③nodemanager启动第一个container,启动APPmaster
④APPmaster向appmanage注册appmaster编号,同时向scheduler申请资源
⑤scheduler以container形式回复资源列表,比如node2的centainer列表
⑥appmaster让node2分配资源,包括maptask的contenier和reducetask的contenier
⑦同时node执行计算任务,并向appmaster汇报任务情况,appmaster向appmanager汇报任务情况
6.2、相关概念
6.2.1、ResourceManager
①调度器:根据容量、队列等条件,将系统中的资源分配给各个正在运行的应用程序。
②应用程序管理器:监控管理整个系统中所有应用程序,跟踪分给的container的进度、状态。
6.2.2、NodeManager
每个节点上的资源和任务管理器
①定时向ResourceManager汇报节点上的资源使用情况和各个container的运行状态
②接受处理Appmaster的container的启动/停止请求er
6.2.3、Appmaster
用户请教的程序均包含一个Appmaster,负责应用的监控,跟踪应用状态,重启是失败任务。
6.2.4、Container
资源抽象,包含内存,CPU,磁盘,网络等
***当Appmaster向Resource申请资源时,Resourcemanager为Appmaster返回的资源便用container表示。
6.3、调度器的种类
6.3.1、队列调度
任务提交的顺序排成队列,资源分配时,先进先出
***大任务导致占用集群资源,导致其他任务被阻塞
job进入队列,先进先出,仅能支持第一个job
6.3.2、容量调度器
--apache默认版本
多个组织共享集群,每个组织获得集群一部分计算能力,为每个组织分配专门的队列,然后为每个队列分配一部分集群资源。
在一个队列内部,先进先出
6.3.3、公平调度器
--CDH默认版本
为所有应用分配公平资源,公平调度可在多个队列工作。
①假设有两个A和B,他们分别拥有一个队列;
②当A启动一个job,而B没有job,A会获得全部集群资源;
③当B启动一个job后,A的job会继续运行,不过一会之后两个任务各自会获得一半的集群资源;
④若B再启动第二个job且其他job还在运行,则它将会和B的第一个job共享B这个队列的资源,
B两个job会各自使用集群的四分之一的资源,而A的job仍然会用集群一半的资源,结果就是资源最终在两个用户之间的平等共享。
6.4、相关参数
在yarn-site.xml文件中进行参数设置
①设置container分配最小内存
②设置container分配最大内存
③设置每个container的最小虚拟内核个数
④设置每个container的最大虚拟内存个数
⑤设置NodeManager可以分配的内存大小
⑥定义每台机器的内存使用大小
⑦定义交换区间可使用的大小
6.5、yarn查看日志
6.5.1、Kill Command 卡住数分钟没有日志输出
提交Hive查询任务,作业状态running,日志提示:Kill Command 卡住数分钟没有日志输出,该如何处理?
YarnApplicationState字段为当前作业状态,Queue为当前运行集群队列
查看该任务运行状态为waitting,即等待资源运行状态,由于用户使用的队列为root.default,该队列为公用队列,资源吃紧时会出现等待的情况。
解决方案:有申请集群单独队列的应用组,需排查队列是否有批量任务启动,导致资源队列吃紧。核查正常使用导致的资源不足,建议用户申请资源队列扩容,解决问题。
7、sqoop相关
7.1、sqoop是什么?
“Hadoop和关系数据库服务器之间传送数据”的工具。
导入数据:MySQL,Oracle导入数据到Hadoop的HDFS、HIVE、HBASE等数据存储系统;
导出数据:从Hadoop的文件系统中导出数据到关系数据库mysql等。
7.2、导入数据
①导入表到HDFS指定目录
bin/sqoop import \
--connect jdbc:mysql://hdp-node-01:3306/test \
--username root \
--password root \
--target-dir /queryresult \指定目录
--fields-terminated-by ‘\001’ \指定分隔符
--table emp
--split-by id
--m 1
如果设置了 --m 1,则意味着只会启动一个maptask执行数据导入;
如果不设置 --m 1,则默认为启动4个map task执行数据导入,则需要指定一个列来作为划分map task任务的依据。
②导入关系表到HIVE
bin/sqoop import
--connect jdbc:mysql://hdp-node-01:3306/test
--username root
--password root
--table emp
--hive-import \增加导入hive声明
--split-by id
--m 1
③增量导入
1)基于递增列的增量数据导入
bin/sqoop import \
--connect jdbc:mysql://hdp-node-01:3306/test \
--username root \
--password root \
--table emp \
--m 1 \
--incremental append \ --基于递增列的增量导入
--check-column id \ --递增列
--last-value 1208 --阈值(将递增列值大于阈值的所有数据增量导入Hadoop)
2)基于时间列的增量数据导入
# 将时间列大于等于阈值的数据增量导入HDFS
sqoop import \
--connect jdbc:mysql://192.168.xxx.xxx:3316/testdb \
--username root \
--password transwarp \
--query “select order_id, name from order_table where \$CONDITIONS” \
--target-dir /user/root/order_all \
--split-by id \
-m 4 \
--incremental lastmodified \ --基于时间列的增量导
--merge-key order_id \ --合并列(主键,合并主键相同的记录)
--check-column time \ --时间列
# remember this date !!!
--last-value “2014-11-09 21:00:00” --阈值(将时间列大于等于阈值的所有数据增量导入Hadoop)
③并发导入参数
-m 参数能够设置导入数据的 map 任务数量,即指定了 -m 即表示导入方式为并发导入,
这时我们必须同时指定 - -split-by 参数指定根据哪一列来实现m哈希分片,从而将不同分片的数据分发到不同 map 任务上去跑,避免数据倾斜。
重要 tip
1)生产环境中,为了防止主库被Sqoop抽崩,我们一般从备库中抽取数据。
2)一般RDBMS的导出速度控制在60到80m/s,每个 map 任务的处理速度5~10mb/s 估算,即 -m 参数一般设置4到8,表示启动4到8个map任务进行抽取
7.2、导出数据
1.格式:
bin/sqoop export \
--connect jdbc:mysql://IP:3306/数据库名 \
--username MySQL用户名 \
--password MySQL密码 \
--table MySQL数据库表名 \
--export-dir /hive中的文件夹名(数据导出目录)
2.例子:
1.cd /root/sqoop
2.命令:
bin/sqoop export \
--connect jdbc:mysql://192.168.25.100:3306/userdb \
--username root \
--password admin \
--table employee \
--export-dir /emp_data