问题描述:
前段时间使用hive语句建了两张较为相似的数据表,后来在spark上用这两张表跑相同的模型,发现两张表的模型训练时间不同,其中一张表跑起来非常慢。而两张表的字段数量和数据量并没有太大的差别,颇为奇怪。
解决方法:
先说结论:
以上问题是两张表在hdfs上存储的文件数量不一样导致的,初始原因是在执行建表语句的时候两张表用的reducer个数不同。
hive语句建的表在hdfs上存储的file个数( 即fs -ls
命令展示的items个数)等于语句执行时候的reducer个数,而spark又是根据file的读取文件。所以若数据表的数据量过大而文件数量太少,导致每个文件过大,容易拖慢spark的执行速度。
可以通过设置reducer个数调整在hadoop上存储的file个数,从而调节spark读取的每个文件的大小,进一步提高模型训练速度。
需要注意:
若file的大小若超过hdfs设置的block size,则会对应多个block(即,file数量总数大于等于block个数),
hadoop集群上的有block.Size参数的设置,一般是64M、128M、256M等,hive上也有一个dfs.block.size
参数,但是这个应该和map数量有关。
可以从以下原理、命令自行实验理解,此处不再赘述。
Hive部分:
Map与Reducer个数的确定:
Map数的计算公式:
num_Map_tasks = max[${Mapred.min.split.size},
min(${dfs.block.size}, ${Mapred.max.split.size})]
Reducer个数:
1. 直接指定 : set mapred.reduce.tasks=100;
2. 调整每个reducer处理的数据大小:
num_Reduce_tasks = min[${Hive.exec.Reducers.max},
(${input.size} / ${ Hive.exec.Reducers.bytes.per.Reducer})]
Mapred.min.split.size指的是数据的最小分割单元大小。
Mapred.max.split.size指的是数据的最大分割单元大小。
dfs.block.size指的是HDFS设置的数据块大小。
Hadoop命令:
查看表文件
hadoop fs -ls /xx/xx.db/xxtable
查看file和block
hadoop fsck /xx/xx.db/dual -files -blocks
查看某个block的block.size设置值以及备份个数
hadoop fs -stat "%o %r" /xx/xx.db/dual/000000_0