要好好使用 Impala 就得好好梳理一下他得結構以及他存在得一些問題或者需要注意得地方。本系列博客主要想記錄一下對 Impala 架構梳理以及使用上的 workaround。
Impala 簡介
首先我們來了解一下在 Impala Guide 中 Impala 對自己的定位
Impala is an addition to tools available for querying big data. Impala does not replace the batch processing frameworks built on MapReduce such as Hive. Hive and other frameworks built on MapReduce are best suited for long running batch jobs, such as those involving batch processing of Extract, Transform, and Load (ETL) type jobs.
Impala 認為自己是大數據查詢工具的補充,對於長時間的 batch work 還是推薦使用基於 mapreduce 的方式來處理超大量數據。因為那更穩定可靠。
Impala 目前已經從 Apache 孵化項目中畢業,由 Cloudera 公司捐贈后 Impala 由 Cloudera Impala => Apache Impala
Impala 架構部分


Impala 守護進程(Impala Daemon)
Impala 的核心組件一個守護進程,運行在集群的每個數據節點上,它是一個叫 impalad 的進程負責讀取和寫入數據文件。接受從impala-shell傳遞過來的命令,Hue、JDBC或ODBC傳輸過來的查詢;並行化查詢請求並在整個集群中分配工作;將中間查詢結果傳輸回中央協調器節點。
注意上面我 CDH 上運行的跟 impala 相關的實例,我只在一個計算節點上啟動了 impala daemon,所以說我要使用 hue 或者 impala 請求該節點來構建查詢和返回結果。
如果有多個 impala daemon ,那么我可以向任意有 impala daemon 節點上提交任務。該實例將作為該查詢協調節點。其他節點將部分查詢結果返回協調節點,它將構建最終的結果集。
Impala 狀態存儲進程(Impala StateStore)
被稱為 StateStore 的 Impala 組件負責檢查集群中的所有數據節點上的 Impala Daemon 的健康狀況,並不斷的將結果轉發給每個 Impala Daemon。它是一個名為 StateStored 的守護進程。而且只需要在集群中某一個主機上運行該進程即可。如果一個 Impala Daemon 失敗或者脫機卡斯,那么 StateStored 會復雜同志其他守護進程,來避免后來的查詢請求被發送到一些無效的節點。
StateStore 是被設計用來當 daemon 進程刮了之后將消息廣播至協調者的,它對 Impala 集群的正常運行沒有那么重要,如果這玩意失效了,只要守護進程還在繼續運行,那么整個集群的 Impala 工作還是可以繼續開展。但是 StateStore 由於會用來維護健康狀況等信息,所以當它失效之后集群將會變得沒有那么強健。包括 metadata 在內的變動在 StateStore 失效的時候是無法保持一致的。而當我們回復 StateStore 的正常運行之后,它會重新和 Impala daemons 建立連接和監控,然后重新運行廣播函數等。同樣的,當 StateStore 掛了的時候,我們進行一些對表的 DDL 操作可能會失敗,這和上面 metadata 無法被廣播更新有一定關系。
負載平衡和高可用性的大多數考慮都適用於 Impala 守護進程。StateStored 和 Catalogd 守護進程對高可用性沒有特殊要求,因為這些守護進程的問題不會導致數據丟失。如果這些守護進程由於某個主機的中斷而不可用,我們立即停止這台機器上的 Impala 服務並且刪除 Impala StateStore 和 Impala Catelog Server,然后在另一個主機上添加這些角色,並重新啟動Impala服務即可。
Impala 目錄服務進程(Impala Catalog Service)
被稱為目錄服務的 Impala Catalog Service 組件,維護着從 Impala SQL 語句到集群中的所有 Impala 守護進程需要用到的元數據,它是一個名為 Catalogd 的守護進程,只需要在集群中的某個主機上執行這個進程即可。因為請求是通過 StateStore 進行傳遞的,所以如果 StateStored 和 catalogd 兩個服務在一個機器上會比較不錯。
這個進程涉及一系列關於 Impala 的功能:
有 Catalog Service 之后當我們通過 Impala 使用 CREATE TABLE, INSERT, 或者其他對表進行 DDL 操作的時候我們不需要進行 Refresh 和 INVALIDATE METADATA 申明了。而如果這些 DDL 是通過 Hive 或者 直接在 HDFS 中操作數據文件來完成的,那么我們在查詢的時候就必須提前執行一下以上命令。
這里我要多說一句,我們經常有這種場景,就是晚上我們會通過 DATAX 或者 Sqoop 對表進行同步或者建立新的分區然后刷入數據,其實 Impala 是無法獲取這些新的信息的,所以當我們無論是使用 HUE 還是接口去訪問 Impala 的時候都無法查詢到這些新的數據,這個時候我們就需要 Refresh 一下新的表,或者直接使用 INVALIDATE METADATA 對元數據進行重建。就可以看到這些新的表和數據了,這里要注意。

無論在 HUE 上執行還是代碼里面直接獲取 Impala cursor 直接執行相關命令
impala_cursor.execute("refresh {}".format(table))
impala_cursor.execute("INVALIDATE METADATA {}".format(table))
都可以刷新元數據,在一個地方執行之后所有節點都會同步,就能使用 Impala 查找到直接修改文件生成的數據了。
使用 --load_catalog_in_background 選項可以控制 Impala 在何時進行 metadata 的 load。
CDH 里面也有這個選項

默認是 False.
如果設置成 False 這個關於表級別的 metadata 被加載是在第一次對表引用的時候。這意味着第一次跑某些 query 的時候可能要比已經加載過 metadata 的時候要慢一些。從 Impala2.2 開始這個選項就默認是 False 了。
如果我們設置成 True 這個 Catalog Service 會嘗試為所有表去加載 metadata,即使這個查詢不需要重新加載某個表的 metadata。現在這個選項不建議被設置成 True 因為以下原因。。。
1. 從后台去加載 metadata 可能會干擾指定的 metadata 加載,這種情況可能在啟動的時候發生,也可能在失效的時候發生,持續事件取決於元數據數量,並且可能導致隨機的長時間運行查詢,這些耗時的查詢很難被診斷出來是為啥。。。說到底就是可能引起一些奇怪的 bug ,不如需要的話手動自己刷。
2. Impala 開啟這個會去加載很多自己用不到的元數據導致數據膨脹。這可能會增加目錄大小,從而增加目錄服務和守護進程的內存使用量。總之就是不要開。
負載平衡和高可用性的大多數考慮因素都適用於 Impalad。StateStored 和 Catalogd 對高可用性沒有特殊的要求,因為這些守護進程的問題不會導致數據丟失。如果這些守護進程由於特定主機的宕機而變得不可用,您可以停止Impala服務,刪除Impala狀態存儲和Impala目錄服務器角色,在不同的主機上添加角色,並重新啟動Impala服務。
Impala 性能調優
1. 文件格式上,與基於文本的文件格式相比,使用二進制的文件格式將會獲得更好的性能。最好能將密集查詢的或者很大的表使用二進制格式存儲例如使用 Parquet | Avro。Parquet 是最被推薦的數據倉庫查詢格式(。。。一家開發的可能優化得更好吧)。雖然 Impala 在文本格式上也能順利執行查詢例如 RCFILE SequenceFile 等格式,但是基於行存儲的他們並不會的到查詢上的優化。並且 Impala 也不支持在類似文件格式上進行 INSERT 操作。
2. 在可行的地方使用 Snappy 壓縮,他的解壓消耗很小並且可以給我們帶來非常多的空間節省。
3. 在 Strings 和 numeric 的類型選擇上選擇 numeric。主要還是在空間節省上面的優化。
4. 可以分區,但是不要對數據進行過度分區以保證高效的數據處理能力,主要碎片大小。如果一個核心可以處理一個文件的話,可以拆出更多的文件,如將 256M 的塊拆成兩個使其得到並行處理,最大程度將 cpu 利用起來。其實我覺得這一點都控制得太細了。可能只有很高頻的表值得如此進行細粒度的優化。
5. 在我們 Loading data 之后總是使用 compute stats 命令計算表的統計結果。當我們同步表或者 Loading 數據之后 Impala 的 stats 處於懵逼的狀態,包括不知道數據有多少行,不知道數據是否被改變。然而 Impala 又廣泛的使用了 stats 特性包括表中列統計信息以幫助其計算一些資源密集型的操作比如 join insert into partition 操作。因為信息只在 loading 數據之后可用,所以我們可以在增加分區、加載替換數據之后執行 compute stats 幫助該表建立自己的 stats 用於優化數據查詢。
舉個栗子:
我們有很多周期性任務,每隔一段事件會將 OLTP 的數據表通過 Sqoop 導上集群。

可以看到我們現在並沒有 rows 的信息。
我們來執行一下最典型的 count(*) 操作需要時間。因為有 2.28gb 所以花費了近 10s。然后我們清理一下緩存執行
compute stats analytics_db.hd_new_yanzhi_record
再執行查看 stats 命令可以看到

統計概要已經有該文件的條數,我們再執行 count 操作類似的操作就可以秒出結果。
這只是我舉例說明的一個非常小的點,使用 compute stats 還將獲得 join 等操作的性能提升,我們都知道 join 的時候表的左右關系也十分影響性能,這有助於幫我們找到小表作為驅動表進行優化。所以當我們 loading 數據之后計算一下 stats 吧。
需要多提一點的是 Cloudera 的官方文檔給到這里一點補充,還有一個計算增量 stats 的命令
COMPUTE INCREMENTAL STATS
這兩個命令不要混用,如果使用其中一個請一直使用下去,他們的不同其實僅僅在如果你針對一個超級大表直接計算全表 stats 可能需要耗費非常多時間。
但是你使用 incremental stats 可以只計算分區信息。
如果我們要換用 可以先使用
DROP INCREMENTAL STATS
然后再進行正常計算,切記不要混用!
6. 使用 EXPLAIN AND SUMMARY 命令來查看自己的執行計划,和執行之后的 profile 。這個大家自己去探索吧,Impala 給到的執行計划還是比較多信息的,包括會提醒你涉及表是否進行過 stats 的計算,如果沒有提醒你去計算以提升執行性能和優化程度。Summary 只能使用在 Impala-shell 中,用於在執行完 DML 操作之后查看運行詳情。如果想要更多詳情還可以使用 profile 命令獲得更詳細的信息。
Reference:
https://zhuanlan.zhihu.com/p/77463503 Apache Impala概念和架構
https://impala.apache.org/docs/build/impala-3.2.pdf Apache Impala Guide
https://impala.apache.org/impala-docs.html Apache Impala Doc
https://docs.cloudera.com/documentation/enterprise/5-14-x/topics/impala_compute_stats.html impala_compute_stats
https://zhuanlan.zhihu.com/p/80354571
