由Impala-3316导致的并发查询缓慢问题

时间:2022-06-02
本文章向大家介绍由Impala-3316导致的并发查询缓慢问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看。

Fayson的github: https://github.com/fayson/cdhproject

提示:代码块部分可以左右滑动查看噢

1.文档编写目的


我们在前面的文章中介绍了《当Impala碰到由Hive生成的timestamp数据》,当Hive生成的parquet文件带有timestamp字段时,使用Impala查询时会出现时区与OS本地时区不一致的问题,因为Impala默认使用的是UTC时区。通过在Impala Daemon配置中增加-convert_legacy_hive_parquet_utc_timestamps,可以解决该问题。但是却又会带来Impala并发查询缓慢的问题,本文将重现该问题,并在文末给出总结以及解决方案建议。

  • 内容概述:

1.问题重现

2.解决方案建议

3.总结

  • 测试环境:

1.操作系统:Redhat7.2

2.CDH和CM的版本为5.13.1

3.Impala已配置负载均衡

4.采用root用户进行操作

2.问题重现


确认Impala Daemon已启用-convert_legacy_hive_parquet_utc_timestamps,具体参考《当Impala碰到由Hive生成的timestamp数据》。

2.1.创建测试表


1.使用Hive创建测试表

建表语句如下,其中“statsdate”字段为TIMESTAMP类型:

[root@cdh4 scripts]# cat createSourceTable.sql 
create database if not exists iot_test;
use iot_test;
create table if not exists hive_table_text (
ordercoldaily BIGINT, 
smsusedflow BIGINT, 
gprsusedflow BIGINT, 
statsdate TIMESTAMP, 
custid STRING, 
groupbelong STRING, 
provinceid STRING, 
apn STRING ) 
PARTITIONED BY ( subdir STRING )
ROW FORMAT DELIMITED FIELDS TERMINATED BY "," ;

(可左右滑动)

执行./hivesql_exec.sh createSourceTable.sql命令创建测试表

2.在beeline中查看,测试表已成功创建

执行show create table hive_table_test;命令,查看表结构,与预期一致。

2.2.准备测试数据


1.生成测试数据

gendata.sh脚本内容如下:

[root@cdh4 scripts]# cat gendata.sh 
function rand(){  
    min=$1  
    max=$(($2-$min+1))  
    num=$(($RANDOM+1000000000))
    echo $(($num%$max+$min))  
}  
let i=1
while [ $i -le 3 ];
do
 let n=1
 while [ $n -le $1 ];
 do
  let month=$n%12+1
  if [ $month -eq 2 ];then
    let day=$n%28+1
  else
    let day=$n%30+1
  fi  
  let hour=$n%24
  rnd=$(rand 10000 10100) 
  echo "$i$n,$i$n,$i$n,2017-$month-$day $hour:20:00,${rnd},$n,$n,$n" >> data$i.txt
  let n=n+1
 done
let i=i+1
done

(可左右滑动)

执行./gendata.sh 300000命令,生成3个测试文件,每个文件包含30万条样例数据。

2.上传测试数据

运行upLoad.sh脚本,将测试数据上传至HDFS的/tmp/hive目录下

[root@cdh4 scripts]# cat upLoadData.sh 
#!/bin/sh

num=3
path='/tmp/hive'
#create directory
sudo -u hdfs hdfs dfs -mkdir -p $path
sudo -u hdfs hdfs dfs -chmod 777 $path
#upload file
let i=1
while [ $i -le $num ];
do
  hdfs dfs -put data${i}.txt $path
  let i=i+1
done
#list file
hdfs dfs -ls $path

(可左右滑动)

3.验证数据是否正确

可以看到,三个文件共包含90万条数据,与原始文件数据总数一致

4.加载数据进入测试表

执行./hivesql_exec.sh loadData.sql命令,加载数据

[root@cdh4 scripts]# cat loadData.sql 
use iot_test;
LOAD DATA INPATH '/tmp/hive/data1.txt' INTO TABLE hive_table_test partition (subdir="10");
LOAD DATA INPATH '/tmp/hive/data2.txt' INTO TABLE hive_table_test partition (subdir="20");
LOAD DATA INPATH '/tmp/hive/data3.txt' INTO TABLE hive_table_test partition (subdir="30");

(可左右滑动)

5.在Hive中验证,在beeline中查看数据总数

执行select count(*) from hive_table_test;命令,可以看到测试表数据总数与导入数据条数一致。

2.3.由Hive生成包含timestamp的parquet表


1.使用Hive创建Parquet表

生成Parquet表语句如下,其中“statsdate”字段为TIMESTAMP类型:

[root@cdh4 scripts]# cat genParquet.sql 
use iot_test;
create table hive_table_parquet (
ordercoldaily BIGINT, 
smsusedflow BIGINT, 
gprsusedflow BIGINT, 
statsdate TIMESTAMP, 
custid STRING, 
groupbelong STRING, 
provinceid STRING, 
apn STRING ) 
PARTITIONED BY ( subdir STRING ) 
STORED AS PARQUET;
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict; 
insert overwrite table hive_table_parquet partition (subdir) select * from hive_table_test

(可左右滑动)

执行./hivesql_exec.sh genParquet.sql命令,生成包含时间戳的parquet表

2.在Impala中查看数据总数

执行select count(*) from hive_table_parquet;命令,与生成Parquet表的源表数据总数一致。

3.验证Parquet文件是否由Hive生成

[root@cdh4 scripts]# hdfs dfs -ls -R /user/hive/warehouse/iot_test.db/hive_table_parquet/

(可左右滑动)

[root@cdh4 scripts]# parquet-tools meta hdfs://cdh3.macro.com:8020/user/hive/warehouse/iot_test.db/hive_table_parquet/subdir=10/000000_0
creator:       parquet-mr version 1.5.0-cdh5.13.1 (build ${buildNumber}) 
file schema:   hive_schema

(可左右滑动)

注:parquet-tools meta $Parquet文件绝对路径

2.4.准备并发测试脚本


1.并发测试脚本如下,Impala负载均衡地址为:cdh4.macro.com:25003

[root@cdh4 scripts]# cat impala-test.sh 
#!/bin/sh

#Concurrency test
let i=1
while [ $i -le $1 ];
do
 impala-shell -B -i cdh4.macro.com:25003 -u hive -f $2 -o log/${i}.out &
 let i=i+1
done
wait

(可左右滑动)

2.测试SQL语句如下

SELECT 
 nvl(A.TOTALGPRSUSEDFLOW,0) as TOTALGPRSUSEDFLOW, nvl(A.TOTALSMSUSEDFLOW,0) as TOTALSMSUSEDFLOW, B.USEDDATE AS USEDDATE 
FROM ( SELECT SUM(GPRSUSEDFLOW) AS TOTALGPRSUSEDFLOW, SUM(SMSUSEDFLOW) AS TOTALSMSUSEDFLOW, cast(STATSDATE as timestamp) AS USEDDATE 
FROM hive_table_parquet SIMFLOW 
WHERE SIMFLOW.subdir = '10' AND SIMFLOW.CUSTID = '10099' 
 AND cast(SIMFLOW.STATSDATE as timestamp) >= to_date(date_sub(current_timestamp(),7)) 
 AND cast(SIMFLOW.STATSDATE as timestamp) < to_date(current_timestamp()) 
 GROUP BY STATSDATE ) A 
RIGHT JOIN ( 
 SELECT to_date(date_sub(current_timestamp(),7)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),1)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),2)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),3)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),4)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),5)) AS USEDDATE UNION ALL
 SELECT to_date(date_sub(current_timestamp(),6)) AS USEDDATE 
) B on to_date(A.USEDDATE) = to_date(B.USEDDATE) ORDER BY B.USEDDATE

(可左右滑动)

2.5.Impala并发测试


使用相同的测试SQL,在不同并发测试场景下做并发测试,为了避免单次测试结果的偶然性,针对3种并发测试场景分别作了三次测试。

1.测试1个并发查询

第一次测试:1.09秒返回查询结果

第二次测试:0.76秒返回查询结果

第三次测试:0.78秒返回查询结果

可以看到,1个并发查询,能在秒级内返回结果

2.测试10个并发查询

第一次测试:所有并发查询均在6.4秒内完成

第二次测试:所有并发查询均在6.8秒内完成

第三次测试:所有并发查询均在6.8秒内完成

可以发现,在10个并发查询的场景下,Impala查询性能已经有明显的下降了。

3.测试30个并发查询

第一次测试:前6个查询均在5秒内完成,但是随着并发数的增大,查询返回结果的时间越长,花费时间最长的为11.81秒。

第二次测试:前4个查询均在5秒内完成,30个并发查询中,花费时间最长的为12.24秒。

第三次测试:前5个查询均在5秒内完成,30个并发查询中,花费时间最长的为12.20秒。

从并发测试结果来看,在30个并发查询的测试场景下,Impala查询性能急剧下降,即随着并发查询数量的增多,Impala查询性能越差。

3.总结


如果Parquet表是由Hive/Spark产生的,包含TIMESTAMP字段类型,并且Impala高级配置包含--convert_legacy_hive_parquet_utc_timestamps=true启用选项,那么使用Impala做并发查询时,随着并发的增加,查询性能会慢慢下降,并发越高,性能下降越厉害。根据我们在上一章的测试效果,可以看出,1个用户单独查询能秒级返回查询结果,10个用户并发查询需要3秒左右返回查询结果,30个用户并发查询需要耗时15秒左右。

该性能问题是由IMPALA-3316(https://issues.apache.org/jira/browse/IMPALA-3316)导致的,Impala在读取Hive或者Spark生成的Parquet表时,如果表包含TIMESTAMP字段类型,并且Impala高级配置包含--convert_legacy_hive_parquet_utc_timestamps=true启用选项。Impala会调用Linux本地的时间转换函数(localtime_r)将Timestamp数据转换成系统的当地时间,而缺省情况下,Impala并不做任何转换,且将Timestamp时间都作为UTC时间处理。但是localtime_r函数内部实现会加上进程全局锁,因此当有大量并发的Parquet读取时会影响性能。而并发越高,全局锁的问题就越严重,从而导致性能下降就越厉害。

4.解决方案建议


在Impala的该bug修复前,我们建议通过以下三种方式来规避这个问题:

1.如果不要求 Impala 返回本地时间, 可以去掉

--convert_legacy_hive_parquet_utc_timestamps=true启动选项

2.将相关的 Parquet表用 Impala 生成

3.Hive/Spark 产生 Parquet 表时使用STRING类型代表时间, 并且时间格式采用 yyyy-MM-dd HH:mm:ss.SSS 或者 yyyy-MM-dd HH:mm:ss,这种方式下,使用 Impala 的date/time函数时, Impala 会自动将其转换成TIMESTAMP类型

对于该三种方法的比较,我们会在后续的文章中持续进行说明。

测试脚本源码:

https://github.com/fayson/cdhproject/tree/master/ScriptFiles

提示:代码块部分可以左右滑动查看噢

为天地立心,为生民立命,为往圣继绝学,为万世开太平。 温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看。

推荐关注Hadoop实操,第一时间,分享更多Hadoop干货,欢迎转发和分享。

原创文章,欢迎转载,转载请注明:转载自微信公众号Hadoop实操