Hive性能调优(二)
第4章 Hive及相关大数据结构
Hive工作流程
- 客户端提交SQL作业到HiveServer2
- HiveServer2根据作业及数据库中元数据信息生成一份可供计算引擎执行的计划
- 每个执行计划对应若干MapReduce作业,Hive把所有MapReduce作业提交到YARN中
- YARN去负责创建MR作业对应的子任务,并协助运行
- 子任务和HDFS进行交互,获取计算所需的数据,完成后把结果写入HDFS或本地
Hive元数据
-
数据库相关元数据
desc databases 库 可查询DBS的信息
desc database extended 库 查询
create function 函数名 创建函数
desc formatted 表
Analyze table 表名 compute statistics 收集表的统计信息
- DBS:描述数据库库名、存储地址、拥有者、拥有者类型
- DATABASE_PARAMS: 数据库属性信息
- DB_PRIVS :权限信息
- FUNCS:记录用户编写的函数 UDF
- FUNCS_RU: 记录函数所在文件路径 JAR包在HDFS存储位置
-
表相关元数据
- TBLS:Hive创建的所有表,包含所属数据库、创建时间、创建者、表的类型(内部、外部)等
- TABLE_PARAMS: 通过收集表的统计信息 存储文件个数、总文件大小、表行数、分区数等
- TAB_COL_STATS:表中列的统计信息,数字类型的最大值,列的平均长度等
- IDXS:索引,Hive3.0 被废弃
-
分区相关元数据
- PARTITIONS :存储分区信息,包括分区列,分区创建信息
- PARTITION_KEY_VALS:分区列对应的值
-
数据存储相关元数据
- SDS:保存数据的存储信息,分区、表的存储路径、输入格式、输出格式、分桶数量、是否压缩等
- CDS:分区、表存储的字段信息
- SORT_COLS:排序列
- SERDES:分区序列化和反序列化的方式
- SKEWED_COL_NAMES: 保存表、分区有数据倾斜的列信息
-
文件相关元数据其他
YARN组件
- ResourceManager
- RM是一个全局的资源管理器,负责整个系统的资源管理和分配,它主要由两个部分组成:调度器(Scheduler)和应用程序管理器(Application Manager)。
- 资源调度器以层序队列方式组织资源
- 先来先服务
- 能力调度器 常用
- 公平调度器 常用
- 应用程序的提交、与调度器协商资源以启动ApplicationMaster、监控ApplicationMaster运行状态并在失败时重启它
- ApplicationMaster
- 用户提交的一个应用程序会对应于一个ApplicationMaster
- 与RM调度器协商以获得资源,资源以Container表示。
- 将得到的任务进一步分配给内部的任务。
- 与NM通信以启动/停止任务。
- 监控所有的内部任务状态,并在任务运行失败的时候重新为任务申请资源以重启任务。
- NodeManager
- NodeManager是每个节点上的资源和任务管理器,
- 一方面,它会定期地向RM汇报本节点上的资源使用情况和各个Container的运行状态;
- 另一方面,他接收并处理来自AM的Container启动和停止请求。
- Container
- 是YARN中的资源抽象,封装了各种资源。一个应用程序会分配一个Container,这个应用程序只能使用这个Container中描述的资源。是一个动态资源的划分单位,更能充分利用资源。
YARN执行流程
- Client向YARN提交作业请求
- NodeManager进程和 ResourceManager 进程通信,根据集群资源,为用户程序分配第一个Container(容器),并将 ApplicationMaster 分发到这个容器上面
- 在启动的Container中创建ApplicationMaster
- ApplicationMaster启动后向ResourceManager注册进程,表示自己可以管理一个job,对需要处理的数据进行切分task,采用轮询的方式向RM申请和领取资源
- ApplicationMaster申请到资源后,向对应的NodeManager申请启动Container,将要执行的程序分发到NodeManager上
- NodeManager设置好运行环境,Container启动后,执行对应的任务 ,定时向AM提供自己状态信息和执行进度
- Task执行完毕之后,向ApplicationMaster返回结果
- ApplicationMaster向ResourceManager 请求kill
HDFS架构
hdfs dfsadmin -report 查看存活节点信息
- Client:客户端
- 切分文件。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行存储
- 与NameNode交互,获取文件的位置信息
- 与DataNode交互,读取或者写入数据
- Client提供一些命令来管理HDFS,比如启动关闭HDFS、访问HDFS目录及内容等
- NameNode节点,负责管理文件系统的命名空间、集群配置信息(block映射信息)和存储块的复制等
- 元数据信息包括文件名,命令空间,文件属性(文件生成的时间、文件的副本数、文件的权限)、文件数据块、文件数据块与所在 DataNode 之间的映射关系等
- 将文件的元数据保存在一个文件目录树中
- Editlog 日志文件,记录每次元数据的变化
- FsImage 镜像文件,存储系统的命名空间,内存中元数据在本地磁盘的映射
- SecondaryNameNode,并不是 NameNode 的备份,在NameNode 发生故障时也不能立刻接管 NameNode 的工作,一个是备份数据镜像,另一个是定期合并日志与镜像,因此可以称其为 Hadoop 的检查点(checkpoint),定期同步NameNode的日志(EditLog)和镜像文件(FsImage),并将日志和镜像合并成新的镜像文件fsimage.ckpt回传给NameNode
- DataNode节点,HDFS的执行者。负责文件的存储,以块为存储单位,数据分散在不同DN节点,支持一次写入多次读取等。相当于正文。
- 一个数据块包含两个文件:一个是存储数据本身的文件,另一个是存储元数据的文件(这些元数据主要包括数据块的长度、数据块的检验和、时间戳)。
- 每个存储数据的节点运行一个 datanode 守护进程。
HDFS读写流程
- 写流程
- 用户在Client向NN节点发起命令,通过RPC与NN建立通讯,namenode检查该用户是否有上传权限,以及上传的文件是否在hdfs对应的目录下重名,
- 将文件分块block(一般128MB一块)和设置副本参数(3个)
- NN节点从管理的DN节点中找到合适的3个节点(两个不同机架、一个同机架),把DN节点地址和路径参数给Client,并记录元数据;
- Client通过NN的回复信息找到第一个DN节点A,数据被分割成一个个的packet数据包在pipeline上依次传输,Client 开始往 A 上传第一个 block(先从磁盘读取数据放到一个本地内存缓存),以 packet 为单位(默认64K),A 收到一个 packet (64kb)就会传给 B,B 传给 C(串形写入)。A 每传一个 packet 会放入一个应答队列等待应答,在 pipeline 反方向上, 逐个发送 ack(命令正确应答)
- **本质上就是RPC调用,建立pipeline,**A收到请求后会继续调用B,B在调用C,将整个pipeline建立完成,逐级返回client
- Client 再次请求 NameNode 上传第二个 block ,namenode重新选择三台DataNode给client
- 读流程
- Client向NN节点发出读请求RPC,包含文件名等信息
- NN收到请求,检查用户权限以及是否有这个文件,NameNode会视情况返回文件的部分或者全部block列表,**对于每个block,NameNode 都会返回含有该 block 副本的 DataNode 地址(不是返回请求块的数据);**按照DN与客户端的距离排序
- Client根据收到的DN节点信息,选取每个块所在路径开销最小的DN节点执行读取操作。如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性)
- 客户端和DN通讯,底层上本质是建立 Socket Stream,重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕,并行的读取block信息,并会checksum验证
hadoop的HA(高可用)实现和zk的作用
- 在典型的HA集群中,一般有两台不同的机器充当nn,(note1 主机 nn ,note2 备用主机nn )。在任何时间,有且只有一台机器处于active状态;另一台机器处于standby状态。 active nn 负责所有客户端的操作,standby nn 主要用于备用,它的主要目的是 active nn宕机时 ,可以提供备用并快速的故障恢复。
- 元数据信息同步在 HA 方案中采用的是“共享存储”。每次写文件时,需要将日志同步写入共享存储,这个步骤成功才能认定写文件成功。然后备份节点定期从共享存储同步日志,以便进行主备切换。
- 监控NN状态采用 zookeeper,两个NN节点的状态存放在ZK中,另外两个NN节点分别有一个进程监控程序,实施读取ZK中有NN的状态,来判断当前的NN是不是已经down机。如果standby的NN节点的ZKFC发现主节点已经挂掉,那么就会强制给原本的active NN节点发送强制关闭请求,之后将备用的NN设置为active。
- standby nn 如何保持与active nn 数据同步 (元数据保持一致)
- 这里有一个JournalNodes守护进程,他俩都会和这个进程通信,当 active nn 执行任何有关命名空间的修改操作,它需要持久化到一半以上的 JournalNodes 上(通过 edits log 持久化存储),而 Standby NN 负责观察 edits log的变化,它能够读取从 JNs 中读取 edits 信息,并更新其内部的命名空间。一旦 Active NN出现故障,Standby NN 将会保证从 JNs 中读出了全部的 Edits,然后切换成 Active 状态。
- QJM 共享存储的基本思想来自于 Paxos 算法,采用多个称为 JournalNode 的节点组成的 JournalNode 集群来存储 EditLog
- 为了提供快速的故障恢复,Standby NN 也需要保存集群中各个文件块的存储位置。为了实现这个,集群中所有的 Database 将配置好 Active NN 和 Standby NN 的位置,并向它们发送块文件所在的位置及心跳
常见HDFS优化
- Hive作业生成的小文件,过多小文加重负担
- 设置合理的HDFS文件块的大小,减轻NameNode的负担
- 适当增大NameNode的Java堆,调整JVM参数
- 集群扩容和缩容时,调整NN服务处理程序计数和处理程序计数
- 启动读取后清理缓存
- 开启快速读取
计算引擎
-
MapReduce
- 在shuffle中,要讲数据序列化到磁盘,再由下游数据拉取,并反序列化
-
Tez
- 把操作简化成一个概念Vertex,把原有的计算处理节点拆分成多个组成部分,绕过MR不必要的中间的数据存储和读取Vertex Input 、Vertex Output、Sorting 、Shuffling 和 Merging
- 计算节点之间的数据通信被称为Edge,这些分解后的元操作,可重组生成一个大DAG作业
- Tez on YARN :不是把作业提交到RM中,而是提交到AMPoolServer的服务器上,AMPoolServer存放预先启动AM的服务,节省资源释放和创建的时间
- MRR(Map-reduce-reduce*)模式: 几个reduce可之间连接,数据可以流水线传输,不需要HDFS临时文件
- 允许一次发送整个查询计划,实现应用程序动态规划,消除IO和各个阶段之间的调度开销
- 可以在内存中处理
-
LLAP长时在线与处理程序
- 一个由长时在线的守护进程和基于DAG的计算缓存框架组成的执行模型,代替原来和HDFS和DataNode的直接交互。
- LLAP把数据缓存、预取,一些简单的查询和访问也放到守护进程处理
- 仅仅增强了Hive的交互
-
Spark
- 重构成一个DAG,对查询操作优化,重新编写物理执行引擎,实现MRR模式
- 接口分为两类
- Transformation:map、flatmap、distinct、reduceByKey 和 join
- Action:reduce、collect、count、first
- 实时计算、批处理、交互式查询
- Spark on YARN
- YARN Client 作业监控管理放在提交作业的节点上 用于测试
- YARN Cluster 交给YARN去决定,根据集群各个节点使用情况选择最为合适的 用于实际生产
第6章 HiveSQL执行计划
查看执行计划 eplain
查看执行计划的基本信息 explain
查看执行计算的扩展信息 explain extended
查看数据输入依赖的信息 explain dependency
查看相关权限的信息 explain authorization
查看向量化描述信息 explain vectorization
开启向量模式 set hive.vectorized.execution.enabled = true;
map端聚合 set hive.map.aggr = true;
- 在2.0后加大了基于成本优化器(CBO)的支持
执行计划的基本信息 explain
- 作业的依赖关系图 STAGE DEPENDENCIES
- 每个作业的详细信息 STAGE PLANS
查看执行计算的扩展信息 explain extended
- 多了抽象语法树AST 3.0后已移除
- 作业的依赖关系图 STAGE DEPENDENCIES
- 每个作业的详细信息 STAGE PLANS 更多信息: 每个表的读取路径和配置信息
数据输入依赖的信息 explain dependency
-
输出的是一个json格式数据
- input_partitions: 描述依赖的数据来源分区表
- {“partitonName”:“库名@表名 @分区列 = 分区列的值”}
- input_tables: 描述依赖的数据来源表
- {“tablename”:“库名@表名”,“tabletype”: “表类型(内部/外部)”}
-
快速排除因读取不到相应分区的数据导致输入异常
-
帮助理清表的输入
-
在内连接中的连接条件中加入非等值的过滤条件后,并不会按照过滤条件过滤
-
在左连接的连接条件中加入非等值过滤的条件,过滤条件作用于右表有过滤效果,过滤的是左表则没起到过滤效果
-
-- 有效果 part会读取大于1的 select a.s_no from a left join b on a.s_no = b.s_no and b.part >= 1 -- 无效果 a所有部分都会扫描到 select a.s_no from a left join b on a.s_no = b.s_no and a.part >= 1
查看相关权限信息 explain authorization
- 访问的数据来源、数据输出、访问的当前用户 和 操作
- Hive在不默认配置的情况下不进行权限验证,所有用户都是超级管理员
查看向量化信息 explain vectorization only
set hive.vectorized.execution.enabled = true;
explain vectorization only|summary|operator|expression|detail
-
向量化模式是Hive的一个特性,一般的查询操作一次只处理一行,向量化查询执行时通过一次处理1024行的块来简化系统底层操作,提高数据处理能力
-
支持向量模式的数据类型:数值、日期、字符串
-
explain vectorization only
- plan vectorization
- Execution Mode: 当前执行模式
- 在Map端开启,但是在Reduce端没开启 因为不满足engine in [tez,spark]
-
explain vectorization summary
- explain vectorization only + explain
-
explain vectorization operator
- 对上面的细化 、显示每个操作步骤是否能用向量化执行模式
-
explain vectorization expression
- explain vectorization operator + explain vectorization summary
简单执行计划解读
-
不含列操作、条件过滤、UDF、聚合和连接的操作,
-
select s_age , s_score from student_tb where s_age = 20
-
归结为 select-from-where
-
SQL 只有Map操作树,从表中读取数据并执行数据行的过滤,不需要把分布式文件存储在其他节点的数据和该节点的数据放在一起处理的必要。
-
表扫描TableScan —> 过滤Filter Operator —> 列投影Select Operator —>文件输出 File Output Operator
带普通函数/操作法的执行计划解读
-
普通函数指除了 UDTF、UDAF和窗口函数外的函数
-
比如 nvl( )、 cast( ) 、case when 、concat()、
-
select nvl (s_no,‘undefine’) sno, concat(s_no, ’ - ', ‘s_name’) sid from student_tb where s_age in (18,19) and s_score is not null
-
归结为select-function(column)-from-where-function(column)|operation
-
SQL 只有Map操作树,从表中读取数据并执行数据行的过滤,不需要把分布式文件存储在其他节点的数据和该节点的数据放在一起处理的必要。
带聚合函数的执行计划解读
-
归结为select-aggr_function-from-where-groupby
-
在Reduce端聚合
- set hive.map.aggr = false;
- select s_age,avg(s_score) avg_score from student_tb where s_age<20 group by s_age
- 表扫描TableScan —> 过滤Filter Operator —> 输出到Reduce操作 Reduce Output Operator
-
Map和Reduce端聚合
- set hive.map.aggr = true;
- map到reduce过程中会进行排序、写内存、写磁盘,然后跨网络传输,可以使用combine和启动数据压缩
- 表扫描TableScan —> 过滤Filter Operator —> 分组聚合Group By Operator—>输出到Reduce操作 Reduce Output Operator
- 在这里聚合只是计算总分和对应的个数 这是在单个map中
-
重要关键字
- key|value expression:输出的key和value
- sort order:+ 正序排序 - 倒序
- Map-reduce partition columns:分区字段
- Group By Operator:分组聚合操作
- Mode:Hive执行过程的模式,complete表示所有聚合操作在Reduce中
- moe: 聚合算法,如Hash表
高级分组聚合
- grouping sets、 cube、rollup
- 要注意Hive是否开启了向量模式 和 map端聚合是否开启
'''
grouping sets 可以按照我们定义的维度(grouping sets的参数)进行分组统计,
就像下面我们定义的维度就是(school,grade),school,grade,(),
也就是说我们定义的什么维度就是什么维度,例如我们这里定义了四个就是四个,定义了一个就是一个
'''
select
grouping__id, nvl(school,'全年级'),nvl(grade,'全学校'),count(1) as userCnt
from
ods.ods_student
group by
school,grade
grouping sets(
(school,grade),school,grade,())
order by
grouping__id ;
'''
cube 在一个group by 的聚合查询中,将分组字段的全部组合作为维度,
你可以认为是grouping sets的一种特殊情况,我们的分组字段是school,grade,
那我们的cube组合指的就是(school,grade),(school,null),(null,grade),(null,null),这个是等价于(school,grade),school,grade,()的
'''
select
grouping__id, nvl(school,'全年级'),nvl(grade,'全学校'),count(1) as userCnt
from
ods.ods_student
group by
school,grade
with cube
order by
grouping__id ;
'''
rollup
是CUBE的子集,以最左侧的维度为主,从该维度进行层级聚合。左侧为空的时候右侧必须为空 ,
例如group by month,day 的rollup 维度是(month,day), (month,null), (null,null)
而group by month,day 的cube 维度是(month,day), (month,null), (null,day),(null,null)
'''
select
grouping__id, nvl(school,'全年级'),nvl(grade,'全学校'),count(1) as userCnt
from
ods.ods_student
group by
school,grade
with rollup
order by
grouping__id ;
-- 没有null,grade这个维度
Hive表的连接
-
inner join 返回匹配的记录
-
full outer join 返回左右两个数据集的全部行
-
left outer join 左+左右交集 如果右没有则用空补齐
-
right outer join 右+左右交集 如果左没有则用空补齐
-
left semi join 左+左右交集
-
左半连接可以用于判断一个表的数据在另一个中是否有相同的数据
-
Hive 2.0 之前不支持in类型子查询 ,之后可以,执行计划和逻辑 与 left semi 一样
-
select * from a where col in (select col from b) -- 等价 select * from a left semi join b on a.col = b.col 通过查看执行计划可以知道 在map operator tree中 扫描b的时候 TableScan —> Filter Operator —> Group By Operator—>Reduce Output Operator 会进行一次group by操作 含义是根据s_no字段进行的分组聚合 减少输出的数据量
-
-
cross join 笛卡尔积