hive和hadoop

mr程序的执行过程

 MapReduce程序的主体思想是分而治之。构建抽象模型:Map和Reduce

MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现:

map: (k1; v1) → [(k2; v2)]    分,可以高度并行

reduce: (k2; [v2]) → [(k3; v3)]  合,将同一个分区的数据拉到一起处理

MapReduce处理的数据类型是<key,value>键值对。

编写mr程序的代码片段如下

public class PartitionerMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        String jobName = PartitionerMain.class.getSimpleName();
        Job job = Job.getInstance(super.getConf(),jobName);

        job.setJarByClass(PartitionerMain.class);

        //第一步:读取 文件,解析成key,value对
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job,new Path(args[0]));

        //第二步:设置mapper类
        job.setMapperClass(PartitionerMapper.class);
        job.setMapOutputKeyClass(PairSort.class);//PairSort通过compareTo可以自定义排序,分组时默认也是通过compareTo来确定是否相等,toString可以自定义输出字符串形式
        job.setMapOutputValueClass(Text.class);

        //第三步:设置分区类,以及reducetask的个数,注意reduceTask的个数要与分区的个数一致
        job.setPartitionerClass(PartitionerOwn.class);
        job.setNumReduceTasks(2);

        //第五步:设置combiner类
        job.setCombinerClass(MyCombiner.class);

        //设置自定义分组器   
        //覆写无参构造,将自定义的JavaBean(如PairSort)注册到自定义的分组器中
        //通过重写compare方法可以重写分组逻辑
        job.setGroupingComparatorClass(GroupingComparator.class);

        //第三至六步都可省略,用框架的默认值

        //第七步:设置reducer类
        job.setReducerClass(PartitionerReducer.class);
        job.setOutputKeyClass(PairSort.class);
        job.setOutputValueClass(NullWritable.class);
        //第八步:设置输出类及输出的路径
        job.setOutputFormatClass(TextOutputFormat.class);
        TextOutputFormat.setOutputPath(job,new Path(args[1]));

        boolean b = job.waitForCompletion(true);

        return b?0:1;
    }

    public static void main(String[] args) throws Exception {
        int run = ToolRunner.run(new Configuration(), new PartitionerMain(), args);
        System.exit(run);
    }
}

粗略来说,mapTask的数量是与输入文件在hdfs上的block数相同。

更准确的来说,读取数据组件InputFormat(默认TextInputFormat)会通过getSplits方法对输入目录中文件进行逻辑切片规划得到splits,bytesRemaining < splitSize * 1.1 时为一块,然后有多少个split就对应启动多少个MapTask。split与block的对应关系默认是一对一。

在重写的map函数执行完之后,每条数据写入内存前会默认使用HashPartitioner进行分区,内存中的环形缓存区写满后就会溢写到磁盘(spill)。溢写时会进行排序和规约数据处理结束后合并溢写的临时文件,最终一个mapTask只会生成一个磁盘文件,并且为这个文件提供了一个索引文件,以记录每个reduce对应数据的偏移量。

reduceTask的数据与分区数一致。可通过job.setNumReduceTasks(2)来设置。

每个reduceTask会根据索引文件拉取属于自己分区的数据。当copy到内存的数据达到一定阈值时,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,溢写时会排序,如果设置有Combiner,也是会启用的,然后合并溢写文件,一个reduceTask最终只生成一个磁盘文件。数据合并时会进行排序,排序后调用用户定义的reduce方法,然后把输出写入到HDFS中。

nameNode管理元数据

        nameNode在内存中会保存全部的完整的元数据信息,如何保证内存中的元数据0丢失?

        如果是正常命令停止nameNode,会直接把元数据信息刷到磁盘里。如果是非正常关机是如何保证不丢失元数据信息的呢?

        fsimage : 镜像文件,存的就是元数据信息,非常容易恢复,更新不及时

        edits : 操作日志文件,即时存储除了查询之外的所有操作日志,恢复成元数据时效率低

        secondarynameNode会定期拉取fsimage和edits合并成新的fsimage文件,拉取后nameNode会写新的edits文件,这样edits不会越来越大,且合并完成后的fsimage是非常接近内存中的真实元数据信息的。当重启时,会在根据fsimage和edits恢复出元数据存到内存里。

hive中的优化

存储文件的压缩比总结:

ORC >  Parquet >  textFile

建表语句中 create table ...(...) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS orc tblproperties ("orc.compress"="SNAPPY"); 可指定文件存储格式,orc默认的压缩是ZLIB,比SNAPPY压缩的还要小。在实际的项目开发当中,hive表的数据存储格式一般选择列式存储格式:orcparquet。压缩方式一般选择snappy,压缩效率与读取效率相对比较平衡。

执行顺序

在 hive 和 mysql 中都可以通过 explain+sql 语句,来查看执行顺序。对于一条标准 sql 语句,它的书写顺序是这样的:

select … from … where … group by … having … order by … limit …

(1)mysql 语句执行顺序:

from... where...group by... having.... select ... order by... limit …

(2)hive 语句执行顺序:

FROM —> WHERE —> GROUP BY—> 聚合函数 —> HAVING—> SELECT —> ORDER BY —> LIMIT

Hive 的顺序

hive 基于 MapReduce 程序,它的执行顺序决定了 hive 语句的执行顺序,Map 阶段:

  • 执行 from 加载,进行表的查找与加载
  • 执行 where 过滤,进行条件过滤与筛选
  • 执行 select 查询:进行输出项的筛选
  • 执行 group by 分组:描述了分组后需要计算的函数
  • map 端文件合并:map 端本地溢出写文件的合并操作,每个 map 最终形成一个临时文件。

然后按列映射到对应的 reduceReduce 阶段:

  • group by:对map端发送过来的数据进行分组并进行计算。
  • select:最后过滤列用于输出结果
  • limit:排序后进行结果输出到HDFS文件

优化要点

根据执行顺序,我们平时编写时需要记住以下几点:

  • 使用分区剪裁、列剪裁,分区一定要加
  • 少用 COUNT DISTINCT,group by 代替 distinct
  • 是否存在多对多的关联
  • 连接表时使用相同的关键词,这样只会产生一个 job
  • 减少每个阶段的数据量,只选出需要的,在 join 表前就进行过滤
  • 大表放后面
  • 谓词下推:where 谓词逻辑都尽可能提前执行,减少下游处理的数据量
  • sort by 代替 order by,用同一个key进行cluster by 后的两张表join时可以不用全表join.

当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤。

with temp as() 这种语句并不是真正的建立了临时表,sql中每次用到temp表,都会把所有的逻辑都执行一遍,并不是直接读取缓存的结果。所以如果temp的逻辑复杂,最好是落成一张hive表,这也是数据仓库分层清晰的意义所在。(数仓分层,维度建模等内容待记录

数据倾斜优化:空key过滤,空key转换随机数;map端join;把一个job拆分成多个job逐层聚合执行,例如想把热点key均匀分到1000个分区,就在key前拼接一个0-1000的随机数据后再聚合;手动把数据分成多份分别处理后再合并结果;手动把倾斜的key专门拿出来做map端join等。

hive常用参数

-----------hive参数-------------------------------
-----------------------------------------------------
--Map端运行环境的内存,例子中为4G。在解决GC overhead limit exceeded报错时调此参数有效果。
set mapreduce.map.java.opts=-Xmx4096m;
--一个 Map Task 可使用的内存上限(单位:MB),默认为 1024。如果 Map Task 实际使用的资源量超过该值,则会被强制杀死。
set mapreduce.map.memory.mb=5120;
--reduce端运行环境的内存
set mapreduce.reduce.java.opts=-Xmx3276m;
--一个 Reduce Task 可使用的内存上限(单位:MB),默认为 1024。如果 Reduce Task 实际使用的资源量超过该值,则会被强制杀死。
set mapreduce.reduce.memory.mb=4096;
-------------------------------------------------
--启动压缩
hive本身的参数 set hive.exec.compress.output=true;
对应mr参数  set mapreduce.output.fileoutputformat.compress=true;
set  mapreduce.output.fileoutputformat.compress.codec;  --查看使用的压缩算法
使用默认的org.apache.hadoop.io.compress.DefaultCodec压缩算法,就不支持文件切分,
此时降低mapred.max.split.size的值并不能增加mapTask的数量。

--控制map数量--   mr程序执行时,mapTask的个数默认是由文件在hdfs里的block数决定的
SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat; --防止map端输入合并小文件(当文件体积很小但是行数很多时。实践中很少用到)
此时有以下三个属性值来确定InputSplit的个数:
    set mapred.map.tasks=2;
    set mapred.min.split.size=10000000;
    set dfs.block.size=134217728   --128Mb
    1.goalSize:该值由 totalSize/numSplits  totlasize文件块大小,numslplits=mapred.map.tasks=2
    2.minSize:由配置参数 mapred.min.split.size(或者新版本的mapreduce.input.fileinputformat.split.minsize)mapred.min.split.size=10000000决定
    3.blockSize:HDFS 中的文件存储块block的大小,默认为128MB。
这三个参数决定一个 InputFormat 分片的最终的长度,计算方法如下:
    splitSize = max{minSize,min{goalSize,blockSize}}
--在执行mapTask之前进行小文件的合并
set hive.input.format=org.apache.Hadoop.hive.ql.io.CombineHiveInputFormat;  #执行Map前进行小文件合并,默认开启

如果Hive处理的的文件为非压缩格式或者压缩可切分,且inputFormat为CombineHiveInputFormat时,则控制map个数是由以下四个参数起作用
set mapred.max.split.size=256000000;  #每个Map最大输入大小,不设置,则所有输入只启动一个map任务。对应新版本的mapreduce.input.fileinputformat.split.minsize
set mapred.min.split.size=10000000;   #每个Map最小输入大小。默认值1
set mapred.min.split.size.per.node=100000000;  #一个节点上split的至少的大小 
set mapred.min.split.size.per.rack=100000000;  #一个交换机下split的至少的大小
在开启了org.apache.hadoop.hive.ql.io.CombineHiveInputFormat后,一个dataNode节点上多个小文件会进行合并,合并文件数由mapred.max.split.size限制的大小决定。
mapred.min.split.size.per.node决定了多个data node上的文件是否需要合并
mapred.min.split.size.per.rack决定了多个交换机上的文件是否需要合并
注意
    1.一般来说这四个参数的配置结果大小要满足如下关系。
    max.split.size >= min.split.size >= min.size.per.node >= min.size.per.rack
    2.这四个参数发生矛盾时作用的优先级分别如下
    max.split.size <= min.split.size <= min.size.per.node <= min.size.per.rack
---------------------------------------------------
--输出合并
MR作业结束后,判断生成文件的平均大小,如果小于阀值,就再启动一个job来合并文件
对应参数:
set hive.merge.mapfiles = true; #在Map-only的任务结束时合并小文件
set hive.merge.mapredfiles = true; #在Map-Reduce的任务结束时合并小文件
set hive.merge.size.per.task = 256*1000*1000; #合并文件的大小
set hive.merge.smallfiles.avgsize=16000000; #当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge。这个值只有当hive.merge.mapfiles或hive.merge.mapredfiles设定为true时,才有效。

--控制reduce个数--
不指定reduce个数的情况下,hive会猜测确定一个reduce个数
参数1 :set hive.exec.reducers.bytes.per.reducer=500000000; (500M) #每个reduce任务处理的数据量,默认为1000^3=1G
参数2 :set hive.exec.reducers.max = 888;(每个任务最大的reduce数,默认为999)
计算reducer数的公式很简单 N=min(参数2,总输入数据量/参数1)
也可以直接指定reduce的数量
set mapred.reduce.tasks = 15; 


--启用map端join的参数
set hive.mapjoin.smalltable.filesize=50000000;
--动态分区,并行执行
set hive.exec.dynamici.partition=true;
set hive.exec.parallel=true;
--查看集群block块大小set dfs.block.size;
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值