『壹』 Hive優化之Hive的配置參數優化
Hive是大數據領域常用的組件之一,主要用於大數據離線數倉的運算,關於Hive的性能調優在日常工作和面試中是經常涉及的一個點,因此掌握一些Hive調優是必不可少的一項技能。影響Hive效率的主要因素有數據傾斜、數據冗餘、job的IO以及不同底層引擎配置情況和Hive本身參數和HiveSQL的執行等。本文主要從建表配置參數方面對Hive優化進行講解。
1. 創建一個普通表
table test_user1(id int, name string,code string,code_id string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
2. 查看這張表的信息
DESCRIBE FORMATTED test_user1;
我們從該表的描述信息介紹建表時的一些可優化點。
2.1 表的文件數
numFiles表示表中含有的文件數,當文件數過多時可能意味著該表的小文件過多,這時候我們可以針對小文件的問題進行一些優化,HDFS本身提供了解決方案:
(1)Hadoop Archive/HAR:將小文件打包成大文件。
(2)SEQUENCEFILE格式:將大量小文件壓縮成一個SEQUENCEFILE文件。
(3)CombineFileInputFormat:在map和rece處理之前組合小文件。
(4)HDFS Federation:HDFS聯盟,使用多個namenode節點管理文件。
除此之外,我們還可以通過設置hive的參數來合並小文件。
(1)輸入階段合並
需要更改Hive的輸入文件格式,即參數hive.input.format,默認值是org.apache.hadoop.hive.ql.io.HiveInputFormat,我們改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat。這樣比起上面對mapper數的調整,會多出兩個參數,分別是mapred.min.split.size.per.node和mapred.min.split.size.per.rack,含義是單節點和單機架上的最小split大小。如果發現有split大小小於這兩個值(默認都是100MB),則會進行合並。具體邏輯可以參看Hive源碼中的對應類。
(2)輸出階段合並
直接將hive.merge.mapfiles和hive.merge.mapredfiles都設為true即可,前者表示將map-only任務的輸出合並,後者表示將map-rece任務的輸出合並,Hive會額外啟動一個mr作業將輸出的小文件合並成大文件。另外,hive.merge.size.per.task可以指定每個task輸出後合並文件大小的期望值,hive.merge.size.smallfiles.avgsize可以指定所有輸出文件大小的均值閾值,默認值都是1GB。如果平均大小不足的話,就會另外啟動一個任務來進行合並。
2.2 表的存儲格式
通過InputFormat和OutputFormat可以看出表的存儲格式是TEXT類型,Hive支持TEXTFILE, SEQUENCEFILE, AVRO, RCFILE, ORC,以及PARQUET文件格式,可以通過兩種方式指定表的文件格式:
(1)CREATE TABLE ... STORE AS <file_format>:在建表時指定文件格式,默認是TEXTFILE
(2)ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT <file_format>:修改具體表的文件格式
如果要改變創建表的默認文件格式,可以使用set
hive.default.fileformat=<file_format>進行配置,適用於所有表。同時也可以使用set
hive.default.fileformat.managed = <file_format>進行配置,僅適用於內部表或外部表。
擴展:不同存儲方式的情況
TEXT,
SEQUENCE和
AVRO文件是面向行的文件存儲格式,不是最佳的文件格式,因為即便只查詢一列數據,使用這些存儲格式的表也需要讀取完整的一行數據。另一方面,面向列的存儲格式(RCFILE,
ORC, PARQUET)可以很好地解決上面的問題。關於每種文件格式的說明,如下:
(1)TEXTFILE
創建表時的默認文件格式,數據被存儲成文本格式。文本文件可以被分割和並行處理,也可以使用壓縮,比如GZip、LZO或者Snappy。然而大部分的壓縮文件不支持分割和並行處理,會造成一個作業只有一個mapper去處理數據,使用壓縮的文本文件要確保文件不要過大,一般接近兩個HDFS塊的大小。
(2)SEQUENCEFILE
key/value對的二進制存儲格式,sequence文件的優勢是比文本格式更好壓縮,sequence文件可以被壓縮成塊級別的記錄,塊級別的壓縮是一個很好的壓縮比例。如果使用塊壓縮,需要使用下面的配置:set
hive.exec.compress.output=true; set io.seqfile.compression.type=BLOCK
(3)AVRO
二進制格式文件,除此之外,avro也是一個序列化和反序列化的框架。avro提供了具體的數據schema。
(4)RCFILE
全稱是Record Columnar File,首先將表分為幾個行組,對每個行組內的數據進行按列存儲,每一列的數據都是分開存儲,即先水平劃分,再垂直劃分。
(5)ORC
全稱是Optimized Row Columnar,從hive0.11版本開始支持,ORC格式是RCFILE格式的一種優化的格式,提供了更大的默認塊(256M)
(6)PARQUET
另外一種列式存儲的文件格式,與ORC非常類似,與ORC相比,Parquet格式支持的生態更廣,比如低版本的impala不支持ORC格式。
配置同樣數據同樣欄位的兩張表,以常見的TEXT行存儲和ORC列存儲兩種存儲方式為例,對比執行速度。
TEXT存儲方式
總結: 從上圖中可以看出列存儲在對指定列進行查詢時,速度更快, 建議在建表時設置列存儲的存儲方式 。
2.3 表的壓縮
對Hive表進行壓縮是常見的優化手段,一些存儲方式自帶壓縮選擇,比如SEQUENCEFILE支持三種壓縮選擇:NONE,RECORD,BLOCK。Record壓縮率低,一般建議使用BLOCK壓縮;
ORC支持三種壓縮選擇:NONE,ZLIB,SNAPPY。我們以TEXT存儲方式和ORC存儲方式為例,查看錶的壓縮情況。
配置同樣數據同樣欄位的四張表,一張TEXT存儲方式,另外三張分別是默認壓縮方式的ORC存儲、SNAPPY壓縮方式的ORC存儲和NONE壓縮方式的ORC存儲,查看在hdfs上的存儲情況:
TEXT存儲方式
默認壓縮ORC存儲方式
SNAPPY壓縮的ORC存儲方式
NONE壓縮的ORC存儲方式
總結 :可以看到ORC存儲方式將數據存放為兩個block,默認壓縮大小加起來134.69M,SNAPPY壓縮大小加起來196.67M,NONE壓縮大小加起來247.55M,TEXT存儲方式的文件大小為366.58M,且默認block兩種存儲方式分別為256M和128M,ORC默認的壓縮方式比SNAPPY壓縮得到的文件還小,原因是ORZ默認的ZLIB壓縮方式採用的是deflate壓縮演算法,比Snappy壓縮演算法得到的壓縮比高,壓縮的文件更小。 ORC不同壓縮方式之間的執行速度,經過多次測試發現三種壓縮方式的執行速度差不多,所以建議採用ORC默認的存儲方式進行存儲數據。
2.4 分桶分區
Num Buckets表示桶的數量,我們可以通過分桶和分區操作對Hive表進行優化:
對於一張較大的表,可以將它設計成分區表,如果不設置成分區表,數據是全盤掃描的,設置成分區表後,查詢時只在指定的分區中進行數據掃描,提升查詢效率。要注意盡量避免多級分區,一般二級分區足夠使用。常見的分區欄位:
(1)日期或者時間,比如year、month、day或者hour,當表中存在時間或者日期欄位時,可以使用些欄位。
(2)地理位置,比如國家、省份、城市等
(3)業務邏輯,比如部門、銷售區域、客戶等等
與分區表類似,分桶表的組織方式是將HDFS上的一張大表文件分割成多個文件。分桶是相對分區進行更細粒度的劃分,分桶將整個數據內容按照分桶欄位屬性值得hash值進行區分,分桶可以加快數據采樣,也可以提升join的性能(join的欄位是分桶欄位),因為分桶可以確保某個key對應的數據在一個特定的桶內(文件),所以巧妙地選擇分桶欄位可以大幅度提升join的性能。通常情況下,分桶欄位可以選擇經常用在過濾操作或者join操作的欄位。
創建分桶表
create
table test_user_bucket(id int, name string,code string,code_id string )
clustered by(id) into 3 buckets ROW FORMAT DELIMITED FIELDS TERMINATED
BY ',';
查看描述信息
DESCRIBE FORMATTED test_user_bucket
多出了如下信息
查看該表的hdfs
同樣的數據查看普通表和分桶表查詢效率
普通表
分桶表
普通表是全表掃描,分桶表在按照分桶欄位的hash值分桶後,根據join欄位或者where過濾欄位在特定的桶中進行掃描,效率提升。
本文首發於: 數棧研習社
數棧是雲原生—站式數據中台PaaS,我們在github上有一個有趣的開源項目: FlinkX
FlinkX是一個基於Flink的批流統一的數據同步工具,既可以採集靜態的數據,比如MySQL,HDFS等,也可以採集實時變化的數據,比如MySQL
binlog,Kafka等,是全域、異構、批流一體的數據同步引擎,大家如果有興趣,歡迎來github社區找我們玩~
『貳』 如何遠程調試hadoop app在yarn服務端
配置hbase遠程調試
打開/etc/hbase/conf/hbase-env.sh,找到以下內容:
# Enable remote JDWP debugging of major HBase processes. Meant for Core Developers
# export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8070"
# export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8071"
# export HBASE_THRIFT_OPTS="$HBASE_THRIFT_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8072"
# export HBASE_ZOOKEEPER_OPTS="$HBASE_ZOOKEEPER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8073"
如果想遠程李世調式hbase-master進程,請去哪答肢掉對HBASE_MASTER_OPTS的注釋,其他依次類推。注意,我這里使用的是cdh-4.3.0中舉虛的hbase。
配置hive遠程調試
停止hive-server2進程,然後以下面命令啟動hive-server2
hive --service hiveserver --debug
進程會監聽在8000埠等待調試連接。如果想更改監聽埠,可以修改配置文件:${HIVE_HOME}bin/ext/debug.sh
如果Hadoop是0.23以上版本,debug模式啟動Cli會報錯:
ERROR: Cannot load this JVM TI agent twice, check your java command line for plicate jdwp options.
打開${Hadoop_HOME}/bin/hadoop,注釋掉以下代碼
# Always respect HADOOP_OPTS and HADOOP_CLIENT_OPTS
HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
配置yarn遠程調試
請在以下代碼添加調試參數:
if [ "$COMMAND" = "classpath" ] ; then
if $cygwin; then
CLASSPATH=`cygpath -p -w "$CLASSPATH"`
fi
echo $CLASSPATH
exit
elif [ "$COMMAND" = "rmadmin" ] ; then
CLASS='org.apache.hadoop.yarn.client.RMAdmin'
YARN_OPTS="$YARN_OPTS $YARN_CLIENT_OPTS"
elif [ "$COMMAND" = "application" ] ; then
class="org".apache.hadoop.yarn.client.cli.ApplicationCLI
YARN_OPTS="$YARN_OPTS $YARN_CLIENT_OPTS"
elif [ "$COMMAND" = "node" ] ; then
class="org".apache.hadoop.yarn.client.cli.NodeCLI
YARN_OPTS="$YARN_OPTS $YARN_CLIENT_OPTS"
elif [ "$COMMAND" = "resourcemanager" ] ; then
CLASSPATH=${CLASSPATH}:$YARN_CONF_DIR/rm-config/log4j.properties
CLASS='org.apache.hadoop.yarn.server.resourcemanager.ResourceManager'
YARN_OPTS="$YARN_OPTS $YARN_RESOURCEMANAGER_OPTS"
if [ "$YARN_RESOURCEMANAGER_HEAPSIZE" != "" ]; then
JAVA_HEAP_MAX="-Xmx""$YARN_RESOURCEMANAGER_HEAPSIZE""m"
fi
elif [ "$COMMAND" = "nodemanager" ] ; then
CLASSPATH=${CLASSPATH}:$YARN_CONF_DIR/nm-config/log4j.properties
CLASS='org.apache.hadoop.yarn.server.nodemanager.NodeManager'
YARN_OPTS="$YARN_OPTS -server $YARN_NODEMANAGER_OPTS"
if [ "$YARN_NODEMANAGER_HEAPSIZE" != "" ]; then
JAVA_HEAP_MAX="-Xmx""$YARN_NODEMANAGER_HEAPSIZE""m"
fi
elif [ "$COMMAND" = "proxyserver" ] ; then
CLASS='org.apache.hadoop.yarn.server.webproxy.WebAppProxyServer'
YARN_OPTS="$YARN_OPTS $YARN_PROXYSERVER_OPTS"
if [ "$YARN_PROXYSERVER_HEAPSIZE" != "" ]; then
JAVA_HEAP_MAX="-Xmx""$YARN_PROXYSERVER_HEAPSIZE""m"
fi
例如: 如果你想調試resourcemanager代碼,請在elif [ "$COMMAND" = "resourcemanager" ] 分支內添加如下代碼:
YARN_RESOURCEMANAGER_OPTS="$YARN_RESOURCEMANAGER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=6001"
其他進程,參照上面即可。
注意:埠不要沖突。
配置maprece遠程調試
如果想要調試Map 或Rece Task,則修改bin/hadoop已經沒用了,因為bin/hadoop中沒有Map Task的啟動參數。
此時需要修改mapred-site.xml
<property>
<name>mapred.child.java.opts</name>
<value>-Xmx800m -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000</value>
</property>
在一個TaskTracker上,只能啟動一個Map Task或一個Rece Task,否則啟動時會有埠沖突。因此要修改所有TaskTracker上的conf/hadoop-site.xml中的配置項:
<property>
<name>mapred.tasktracker.map.tasks.maximum</name>
<value>1</value>
</property>
<property>
<name>mapred.tasktracker.rece.tasks.maximum</name>
<value>1</value>
</property>
在Eclipse中使用方法:
打開eclipse,找到Debug Configurations...,添加一個Remout Java Application:
在source中可以關聯到hive的源代碼,然後,單擊Debug按鈕進入遠程debug模式。
編寫個jdbc的測試類,運行代碼,這時候因為hive-server2端沒有設置端點,故程序可以正常運行直到結束。
在hive代碼中設置一個斷點,如ExecDriver.java的execute方法中設置斷點,然後再運行jdbc測試類。
『叄』 Hive內置函數之時間函數
零、生產埋凳滲常用組合方式
(0.1)離線數倉獲取昨天的日期作為分區,格式yyyyMMdd
regexp_replace(date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) ,'-','')
或者
date_format(date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1),'yyyyMMdd')
一、源碼部分
Hive的函數類為:org.apache.hadoop.hive.ql.exec.FunctionRegistry
二、常用時間函數
對於函數,除了知道怎麼用,還需要知道返回值是什麼類型,這里給出官方文檔,文檔中給出了函數的返回值類型
官方文檔見: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-DateFunctions
(2.1)from_unixtime(bigint unixtime[, string format])
示例:
select from_unixtime(1591627588); -- 2020-06-08 22:46:28
select from_unixtime(1591627588,'yyyyMMddHHmmss'); -- 20200608224628
(2.2)unix_timestamp()、彎脊unix_timestamp(string date)、unix_timestamp(string date, string pattern)
示例:
select unix_timestamp('2020-06-08 22:50:00'); -- 1591627800
select unix_timestamp('20200608225000','yyyyMMddHHmmss'); -- 1591627800
(2.3)to_date(string timestamp)
示例:
SELECT to_date('2009-07-30 04:17:52'); -- 2009-07-30
(2.4)year(string date)、month(string date)、day(string date)、hour(string date)、minute(string date)、second(string date)
這些函數是差不多的,都是從一個時間字元串中抽取出某個特定的時間欄位。具有相同功能的還有extract(field FROM source)函數
示例:
SELECT day('2009-07-29 20:30:40'); -- 29
SELECT minute('2009-07-29 20:30:40'); -- 30
(2.5)date_add(date/timestamp/string startdate, tinyint/smallint/int days)、date_sub(date/timestamp/string startdate, tinyint/smallint/int days)
這兩個功能是類似的
示粗搏例:
SELECT date_add('2009-07-30 20:50:59', 1); -- 2009-07-31
(2.6)datediff(string enddate, string startdate)
截圖中結果是錯誤的,應該為-1。
示例:
SELECT datediff('2009-06-30', '2009-07-02'); -- -2
SELECT datediff('2009-07-30', '2009-07-28'); -- 2
(2.7)current_date、current_timestamp
這兩個函數使用desc function extended 查看會報錯
示例:
(2.8)date_format(date/timestamp/string ts, string fmt)
示例:
SELECT date_format('2015-04-08', 'yyyyMMdd'); -- 20150408
『肆』 hive起不來,命令行輸hive時,報錯信息如下:
可以再/hive/bin目錄下輸入 hive -hiveconf hive.root.logger=debug,console 然後再輸入你報錯的hql語句,會有更詳細的錯誤提示,這個調試模式很管用的,希望能幫上。