2020.10.2(hive优化、文件类型、hiveserver2高可用)

之前在配置hiveserver2的时候,在core-site里添加了两个额外的属性
在这里插入图片描述
这东西到底怎么回事,打开hadoop2.6.5的官网,在common里面有一个superuser
superuser
看对应的解释:
A superuser with username 'super'wants to submit job and access hdfs on behalf of a user joe. The superuser has kerberos credentials but user joe doesn’t ha ve any. The tasks are required to run as user joe and any file accesses on namenode are required to be done as user joe. It is required that user joe can connect to the namenode or job tracker on a connection authenticated with super’s kerberos credentials. In other words super is impersonating the user joe.
所以官网里给的案例就是两个super的名称,但当时我们在自己写属性的时候,改成了root这个属性,那个root属性非常非常关键,因为必须要写上你当前机器的superuser。superuser就是在启动namenode的时候,用的用户是谁,当前的superuser就是谁。这点先达成共识,因为是root启动的hdfs。
想要提交任务并且想访问hdfs,为了一个用户叫joe
这个superuser是一个kerberos安全认证的东西,但是joe并没有这样的权限
当前配置这个属性,要求运行的时候被作为用户joe,任何文件可以被访问在namenode上面。这什么意思啊?
在这里插入图片描述
配置了root可以代理的组是谁,可以代理的主机是什么意思。
在这里插入图片描述
如果不加这个配置,在hdfs里看到的都是root用户,而实际想看到的是A B C这三个用户,在运行hiveserver2这个服务启动好之后,需要一个客户端,那个客户端是beeline,但是beeline在进行输入的时候,必须要给一个用户名和密码,默认情况下,用户名和密码是不做验证的,这个时候,用户名相当于写的A B C创建表的时候,应该正常显示出来A B C而不应该是root用户,但是在访问的时候有一个用户名验证,所以用root做了代理。现在是用root来启动的,所以写的root,当用各种各样用户来启动的时候,它的用户的名称就是对应的superuser,只是起了代理的作用,但是实际访问的时候,还是实际的用户。所以这里在配置的时候,配置了一个组对象,还配了一个主机的名称。可以有选择的去代理哪个用户。

再说一遍,为什么要用代理?
当时如果在我们的集群里面,第三台启动了一个hiveserver2
第四台要启动一个beeline的客户端进行访问
在beeline客户端启动访问的时候,可以在里面创建表做一个其他操作,之前做的更多的是查询,但它也可以创建表。意味着在hdfs里面看到的效果应该是创建了一个目录,而创建目录的时候有一个对应的owner显示都是root,但是在创建那张表的时候,如果用A用户登陆创建的表,那个用户应该是A,不能显示成root。
但是要想访问hdfs,如果不是root的话,不能正确往里面创建文件。而且某些目录owner的权限是root,普通用户可能没有访问权限,所以这时候在验证的时候,使用root做一层代理,hdfs在验证的时候,看到的用户是root,但实际用户是A,绕过验证匹配之后,在存储的时候,某一个对应文件夹,看到的就是A了,而不是root了。

hive调优

这些是通用点,不涉及任何特殊业务,任何业务里面都可以给面试官进行描述。
调优时候要思考,hive的本质是什么?
利用hdfs作为文件存储系统,利用mapreduce作为计算层。在写sql语句的时候,就是把sql语句转化成对应的MR,看到执行效果非常慢,实际是mapreduce执行的慢,
hive优化的核心是把hiveSQL当做MR程序去进行优化

Explain显示执行计划

由sql语句转成对应MR任务的时候,需要经历几个步骤:
抽象语法树,查询块,逻辑查询计划,物理查询计划,优化执行
分这五个步骤。
提交的是sql语句,但实际是怎么执行的

explain select count(*) from psn;

在这里插入图片描述
除此之外,还有另外一种写法,加一个关键字,extended

explain extended select count(*) from psn;

出来的东西类似于刚才的操作,但是更加详细了,里把哪些指标值,怎么读取文件的,文件路径是哪些,怎么进行输出的,使用了哪些输入格式化类以及对应的输出格式化类,都展示出来了,这是一个更详细的描述。
在1.x的时候展示的更多,因为由SQL转换成MR的时候有一个东西叫抽象语法树,但现在并没有看到树型结构,怎么能看到?在1.x的时候
在这里插入图片描述
2.x的时候也是有的,只是没有显示出来而已。

hive抓取策略

哪些sql语句会转成MR任务,哪些sql语句不会转成MR任务?
非常好理解,本质上所有sql操作都要转成MR操作,为什么select *的时候没有转成MR任务,因为hive的 抓取策略
在这里插入图片描述
默认值为more
在这里插入图片描述

本地运行:

在这里插入图片描述
当时在讲mapreduce的时候,写完MR程序,有两种方式,1打成一个jar包,上传到当前集群,hadoop jar运行,第二种方式,在本地的idea也可以进行操作。
所有在运行的时候都可以分为本地模式和集群模式。
现在hive操作的时候每次都要执行MR,执行一个hiveSQL语句大概需要30s左右时间,这个时间太长了。如果在开发测试阶段需要非常快的验证出来当前写的sql语句有没有问题,特别是sql语句写的非常复杂的时候,如果每次都用MR来执行太慢了。因此,他也有一个本地执行的方式。当然只适合开发和测试阶段,不适合项目正式上线之后。因为有很多额外的限制。

set hive.exec.modo.local.auto=true;
select count(*) from psn;

在这里插入图片描述
使用本地模式的时候会有很多的限制,导致本地模式只适用于测试和开发阶段来验证一下sql语句对不对,而线上是不能用的。

在这里插入图片描述
这里会非常快。在开发和测试阶段,平常自己写sql语句的时候,比如非常复杂的需求,sql语句不可能一口气就写对它,特别是多个表进行join的时候,或者包含非常复杂子查询的时候,不可能一口气写对,这时候要测一下结果对不对,可以用本地模式,在很短时间内能达到效果。 如果你的项目已经上线了,必须在集群里面跑。

hive.exec.mode.local.auto.inputbytes.max默认值为128M
这时候即使你设置了本地模式,依然会用集群来跑。

并行计算

写一个sql语句的时候,有多少个任务可以并行执行

select t1.ct,t2.ct from (select count(id) ct from psn2) t1,(select count(name) ct from psn2) t2;

没有实际含义的,就做个测试
在这里插入图片描述

笛卡尔积因为一些安全的原因被禁用了,如果想使用必须要设置这样一个模式,hive.mapred.mode
原来是严格模式的,要改成非严格模式

set hive.mapred.mode=nonstrict;

现在可以执行了。
在这里插入图片描述
在本地模式跑和yarn没有关系,不向yarn提交任务的。
现在是没有并行模式会按顺序往下走,两个子查询的SQL语句之间没有依赖关联关系。这两个可以并行执行,谁先执行完谁后执行完无所谓的。现在设置一下并行模式:

set hive.exec.parallel=true;

在这里插入图片描述
两个任务是并行执行的,但需要的资源也是翻倍的,这里可以看到效果。如果把本地模式改回去,这里执行是非常慢的。

先设置集群为并行模式,这时候当输入sql语句的时候,会根据语句来判断这个sql语句里有没有可以并行执行的任务,如果有就并行执行,如果 没有,就不能并行。在公司里也用的比较多。

并行度是无限提高的么?

不可以的。受到资源的限制

hive.exec.parallel.thread.number

这个默认值是8,8个任务开始跑,需要的资源也是翻倍的

严格模式

set hive.mapred.mode=stict;

在讲动态分区的时候也有一个严格模式。
如果不设置非严格模式,有个要求,首先要设置一个静态分区列,否则写不进去,

set hive.exec.dynamic.partition.mode=strict;

create table dptest
(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (age int,sex string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';

insert into table dptest partition(age=10,sex) select id,name,likes,address,/*age,*/ gender from psn21;

/*age,*/就是这样的写法不是注释的意思,mapjoin也是这样的写法。

在这里插入图片描述

这两个严格模式表示的意思不是同一个意思:
在此处的严格模式是为了限制某些查询来使用的。对于分区表,order by有一些限制。

set hive.mapred.mode=strict;

对于分区表
在这里插入图片描述

我写分区列是为了什么?
为了提高查询效率,既然设置了分区如果没用分区,那设置分区是做什么的,所有在严格模式里限制死了,如果表指定了是分区表,有了分区列,意味着在查询的时候,必须有分区的条件。
在公司里有很多表不是你建的,意味着你在做一些操作的时候,有没有分区不刻意查的话是不知道的,如果设置了严格模式,如果没用分区就报错了,提醒你当前表是有分区的,此时就可以把分区的条件充分利用起来。所以严格模式在公司里也要设置好。

第二个限制:

select * from psn order by id;

在这里插入图片描述
order by 也不能使用了,为什么?如果在严格模式下想要进行排序的话,必须要指定一个limit的操作。这是规定好的死的限制。
在关系型数据库里,除了order by没有其他的排序方式了,而对于hive而言,除了order by还有其他几种排序方式,所有在生产环境里,不建议使用order by,会造成数据倾斜。要使用order by要求把全部的数据都加载到一个reduce里面去执行,如果reduce资源不够,会导致整个任务执行不成功。所以必须要做限制输出的操作了。
后面讲排序和排序算法会讲到这个点。

3.限制笛卡尔积的查询。

hive排序

在这里插入图片描述

四种排序方式:
order by这种方式在hivesql里见的很少,或者压根见不到。如果在公司里面见到有人使用order by那一定是有问题的。慎用!!
下面给出了几种替代的方式:
sort by:对于单个reduce的数据进行排序操作。
之前在运行MR任务的时候,要设置一个reduce task的个数,是自己来指定的。设置完成之后,每个reduce是一个数据集,使用sort by之后,能保证每一个小块里面是有序的,但是这些小块之间是有序的么?不一定。
distribute by 分区排序
可以把这些小格子进行排序,先做sort by 再做distribute by 整体有序了
但此时不会把所有数据加载到同一个reduce里去,是多个reduce来处理的。和hdfs分而治之的思想是一样的。
cluster by 相当于sort by+distribute by
所有在公司里,order by基本不用,cluster by如果是升序的可以用它,但更多的是sort by+distribute by的组合,这两个东西组合起来进行使用

select * from psn cluster by id;

cluster为什么只能升序?相当于是sort by+distribute by的两种方式合到一起的,在使用sort by的时候,可以指定某些列,在使用distribute by的时候也可以指定某些列,这两种排序方式在指定列的时候,可以选择不同的列,有可能造成在id的时候想让他降序,在distribute by的时候想让他升序,两个列是不一样的,在使用cluster by的时候只能指定一个列了,所有做了一个调整,如果你觉得这样的方式不太符合你的需求,你把它换成上面两个方式的组合。

hive join优化

在这里插入图片描述

hive的join和关系型数据库里的join差不多,只不过多了left semi join和exist是一样的
在hive里提供了map端join的方式,实现原理是当我在执行一个大表join小表的时候,可以把小表优先放到内存了,每次只需要读取大表里的数据,去跟内存里的数进行匹配就ok了,这时候不需要shuffle也不需要reduce的过程。

实现方式:
手动实现,自动实现

手动怎么实现:在sql语句里需要添加mapjoin标记,

select /*+ MAPJOIN(smallTable) */ smallTable.key,bigTable.value from smallTable join bigTable on smallTable.key=bigTable.key;

加上/*+ MAPJOIN(小表表名) */这个关键字,这时候就会把小表加载到内存里面,读取的时候就会直接读取大表,然后跟内存里的小表进行一个join操作。也就是说,写sql语句的时候就可以实现。

怎么实现自动实现:
在这里插入图片描述

set hive.auto.convert.join=true;

当把这个属性设置之后,hive会自动对左边的表统计量,如果是小表就加入内存,对小表使用map join 。把小表放在左边
如果既设置的自动mapjoin又手动写了mapjoin,这时候要进行预判了听手动的还是自动的。有一个参数

hive.ignore.mapjoin.hint;   默认值是true

当这个值是true的时候,听自动mapjoin的,如果这个值是false,听手动mapjoin的
这个值默认情况下听自动的。

什么是小表?

第一:当前表里面有多少行记录,行号。
第二:这个数据文件有多大
用文件大小合适,所有往内存里放的时候要给一个具体的文件大小,比如多少M,这个值默认大概25M,不够25M
在这里插入图片描述这个值并不大,可以选择把这个值调大,但是不要调的特别大,在执行MR的过程中,是Map端还是reduce端消耗的资源多。在map端执行MR任务过程中,基本是不消耗资源的,做了一件什么事情,读取记录,把记录变成KV键值对的形式,而reduce的时候,可能做聚合,是需要足够的内存和资源的。此时相当于给map端分配了一定的资源。一般情况下不要特别改,可能造成内存溢出或直接运行不了了。
这个值指的小表数据文件在hdfs上的文件大小。表对应过来是一个目录,一个目录里可以有N多个文件,所有文件加起来的大小就表示这个文件大小。
这两个参数非常关键。

hive join

尽可能使用相同的连接键(会转化成一个MR作业),如果没有就不管了。

大表join大表

在这里插入图片描述实际上,大表join大表,严格意义上来说是没有非常好的优化策略的。不可能造成查询性能成倍提升,所有这里只列出了两个非常小的点,可能起作用,可能不起作用。

第一种条件过滤是有可能用到的,第二种几乎没用,企业里用的比较少。能不能解决问题还要看实际情况而定。

MapSide聚合

在这里插入图片描述
map端的聚合,combiner操作,这个类就等同于是reduce类,执行这个combiner也需要时间,如果10条记录,聚合完还有9条,就没必要聚合了。所需要的时间还远远小于聚合所需要的时间。
所以有这个参数判断在什么情况下需要做聚合,什么情况下不需要做聚合

set hive.map.aggr=true;

聚合的比例值是怎么来的,怎么知道当前数据量在聚合的时候是否需要聚合。 预先拿10W条记录做聚合,若聚合后比例小于0.5则一定要做聚合,如果大于0.5就不聚合了。并不是设置了这个值就一定会聚合的。

hive.groupby.skewindata

比如现在要执行一个MR任务,由于key分布不均匀,导致现在有4个reduce,一个reduce卡着不动了,意味着发生了数据倾斜,当设置完这个属性之后可以做优化,原来这个任务是需要一个MR的,由于数据倾斜了导致执行失败或完成不了,把一个MR任务,分成2个MR任务,它自己进行转换。在进行group by的时候一定要指定partition。当第一次进行转换的时候,按照哈希或随机的方式,把key进行随机分发,第一个MR执行完了,意味着一定得到了一个聚合之后的结果。到第二个MR的时候,再按照指定的分区的规则,再进行一次分发,此时reduce在读取数据的时候,量少了很多。就有可能保证数据倾斜不会发生任务可以顺利执行下去了。

疑问:本身需要一个MR任务,现在变成两个MR任务了,执行时间拉长了,比如原来需要30分钟,现在需要一个小时了。但是时间拉长了总好过当前任务执行不成功。如果有经验的话,经常看到一种效果。在执行MapReduce在到33% 66% 99%是非常容易卡住,几个小时都执行不成功的。这样虽然也不一定能成功。但是减少了MR任务中数据倾斜的可能性,这个参数一般情况下设置成true

合并小文件

在这里插入图片描述
在整个MR运行过程中可能出现两个比较重要的问题,小文件问题,数据倾斜问题。小文件多了为什么不好?IO的问题,数据如果比较小的话,容易对hdfs造成很大压力,影响对应效率。如果读取的文件一共是1M,分了10个100KB的文件,要启动10个MapTask的资源,会占用时间。因此存文件的时候最优的是和块大小保持一致。在企业里可能做不到,但是也是越大越好的,大也不要超过块大小。
如果某一个表里有很多的小文件,可以考虑把这堆文件先进行一次合并。

hive.merge.mapfiles=true;
hive.merge.mapredfiles=true;

这两个默认值都是true
限制合并文件大小,如果文件大小超过256M了就不进行合并了。文件也不是越大越好的。

去重统计

Map端和reduce端task的个数

在这里插入图片描述

reduceTask并不是越多越好的,第一要对整体数据文件的数据量有所了解。第二要对值在聚合的时候产生的key的个数要有了解。在开发过程中有设置过MapTask的个数么?没有。MapTask由谁来决定,切片。split切片是一个逻辑概念。由一个优化的机制:
每一个节点上的最小的切片值,会变成一个切片。剩下了的切片最后会留下来,但是不能出机架。一般不做限制,让它自己来切。

第一个层次: 一个split的最大值,即每个map处理文件的最大值
第二个层次: 一个节点上split的最小值
第三个层次:一个机架上split的最小值

在这里插入图片描述
类似于关系型数据库里面连接池的概念。在任务执行之前先申请一批资源,任务个数如果刚刚好保持一致,直接运行完释放,如果申请了20个,只用10个,剩下20个资源浪费的。最终任务结束同时消亡释放资源。过多了资源浪费,过少了资源不够还需要等待时间。

猜你喜欢

转载自blog.csdn.net/m0_48758256/article/details/108900213
今日推荐