您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關怎么理解Impala元數據,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
Impala是一個高性能的OLAP查詢引擎,與其它SQL-on-Hadoop的ROLAP解決方案如Presto、SparkSQL 等不同的是,Impala對元數據(Metadata/Catalog)做了緩存,因此在做查詢計劃生成時不再依賴外部系統(如Hive、HDFS、Kudu),能做到毫秒級別的生成時間。另外緩存元數據也能極大減少對底層系統Master節點(Hive Metastore、HDFS NameNode、Kudu Master)的負載。
然而事情總有兩面性,元數據緩存給Impala的系統設計引入了極大的復雜性。一方面在功能上為了維護緩存的正確性,引入了兩個Impala特有的SQL語句:Invalidate Metadata 和 Refresh,另外還引入了query option SYNC_DDL。這些都讓用戶參與了緩存的維護。另一方面在架構設計上,有許多元數據相關的復雜設計,比如元數據的增量傳播、緩存一致性的維護等。
在數倉規模較大時,Impala的元數據設計暴露出了許多問題,比如大表的元數據加載和刷新時間特別長、元數據的廣播會被DDL阻塞導致廣播延遲很大、元數據緩存導致節點Full GC或OOM等。因此Impala元數據設計也一直在演化之中,最新進展主要集中在Fetch-on-demand coordinator(又稱local catalog mode、catalog-v2等)的設計。
Impala集群包含一個 Catalog Server (Catalogd)、一個 Statestore Server (Statestored) 和若干個 Impala Daemon (Impalad)。Catalogd 主要負責元數據的獲取和DDL的執行,Statestored主要負責消息/元數據的廣播,Impalad主要負責查詢的接收和執行。
Impalad 又可配置為 coordinator only、 executor only 或 coordinator and executor(默認)三種模式。Coordinator角色的Impalad負責查詢的接收、計劃生成、查詢的調度等,Executor角色的Impalad負責數據的讀取和計算。默認配置下每個Impalad既是Coordinator又是Executor。生產環境建議做好角色分離,即每個Impalad要么是Coordinator要么是Executor,且可以以1:50的比例配置。更多細節可參考官方文檔[1].
Impala的元數據緩存在catalogd和各個Coordinator角色的Impalad中。Catalogd中的緩存是最新的,各個Coordinator都緩存的是Catalogd內元數據的一個復本。如下圖所示,元數據由Catalogd向外部系統獲取,并通過 Statestored 傳播給各個 Coordinator。
元數據緩存主要由Java代碼實現,主體代碼在FE中。另有一些C++實現的代碼,主要處理FE跟BE的交互,以及元數據的廣播。代碼中把 Catalogd 和 Coordinator (Impalad) 中相同的元數據管理邏輯抽出來放在了 Catalog.java 中,Catalogd 里的實現是 CatalogServiceCatalog.java,Coordinator 里的實現是 ImpaladCatalog.java.
Catalog是一個層級結構,第一層是 db name 到 db 的映射,每二層是每個db下的 function map和 table map:
Catalog
|-- dbCache_ = Map<String, Db>
|-- functions_ = Map<String, List<Function>>
|-- tableCache_ = CatalogObjectCache<Table>
functions_ Map 里的 value 是 Function 列表,主要表示同名函數的不同重載。tableCache_ 由 CatalogObjectCache 來維護。CatalogObjectCache 封裝了一個 ConcurrentHashMap,另加了版本管理的邏輯,比如避免低版本的更新覆蓋高版本的緩存、追蹤所有緩存的版本號等。這些版本管理邏輯在Impalad中尤其重要。我們在后續的文章中會詳細介紹。
Table 在代碼里有五個具體的子類:HdfsTable、KuduTable、HBaseTable、View、IncompleteTable、DataSourceTable。前4個都比較直白,解釋下最后兩個:
IncompleteTable 表示未加載元數據的表或視圖(View)。Catalogd 啟動時,為了減少啟動時間,只加載了所有表的表名,每個表用IncompleteTable來表示。如果執行了INVALIDATE METADATA,則表的元數據也會被清空,其表現就是回置成了IncompleteTable。IncompleteTable可能代表一個視圖,但這在元數據未加載時是無法確定的。因此在HUE等可視化界面中使用Impala時,常常會看到一個View是用Table的圖標表示的,但一旦有被使用過,就又變回成了View的圖標。
DataSourceTable 屬于external data source的實現,這塊沒有任何文檔提及,因為一直處于實驗狀態。其初衷是提供一個Java接口來自定義外部數據源,只需要實現 prepare、open、getNext、close 這幾個接口。具體可參考代碼里的 EchoDataSource 和 AllTypesDataSource。
接下來我們重點介紹下前三個的元數據構成。
HdfsTable 代表一張底層存儲為 HDFS 的 Hive 表。無分區表的元數據比較簡單,少了各個分區對應的元數據。這里以分區表為例,其元數據如圖所示:
其中 msTable 和 msPartition 表示 HMS API 里返回的對象:
org.apache.hadoop.hive.metastore.api.Tableorg.apache.hadoop.hive.metastore.api.Partition
HdfsPartition 代表一個分區的元數據,其一大部分內容是 HDFS 文件和塊的信息。圖中的 FileDescriptor 和 BlockDescriptor,就是從 HDFS API 里返回的 FileStatus 和 BlockLocation 對象抽取數據后生成的。為了節省空間,實際緩存的并不是上圖展示的 FileDescriptor 和 FileBlock。IMPALA-4029 引入了 FlatBuffer 來壓縮 FileDescriptor 和 FileBlock。FlatBuffer 的好處是不需要像 protobuf 或 thrift 一樣做序列化和反序列化,但卻可以直接訪問對象里的內容,同時帶來了一定的壓縮比。更多關于 FlatBuffer 參見文末文檔 [2].
HdfsPartition 的另一大部分內容是增量統計信息,緩存的是deflate算法壓縮后的數據,具體詳見:PartitionStatsUtil#partStatsFromCompressedBytes()。解壓之后是一個 TPartitionStats 對象,主要包含了各列在該partition里的統計信息,每列的統計信息用一個 TIntermediateColumnStats 表示:
struct TIntermediateColumnStats {
1: optional binary intermediate_ndv // NDV HLL 計算的中間結果
2: optional bool is_ndv_encoded // HLL中間結果是否有用 RLE 壓縮
3: optional i64 num_nulls // 該列在該分區的 NULL 數目
4: optional i32 max_width // 該列在該分區的最大長度
5: optional double avg_width // 該列在該分區的平均長度
6: optional i64 num_rows // 該分區行數,用于聚集HLL中間結果
}
關于 Impala 里 ndv() 的實現,可參考 be/src/exprs/aggregate-functions-ir.cc 中的 HllInit()、HllUpdate()、HllMerge()、HllFinalEstimate() 的邏輯。ndv 的中間結果用一個string表示,長度為 1024。在傳輸時一般會用 RLE (Run Length Encoding) 壓縮。
Impala的統計信息受限于Hive(因為要保存在Hive Metastore中),目前并沒有統計數值類型列的最大最小、平均值等信息。這塊有個古老的 JIRA: IMPALA-2416,目前還沒有進展。
一個HDFS分區表的元數據在各種壓縮后,在內存中的大小約為
分區數*2048 + 分區數*列數*400 + 文件數*500 + 塊數目*150
實際應用中要降低大表的元數據大小,就需要在分區數、列數、文件數、塊數目上尋求優化的空間。其中 2048、400、500、150 這些數都是各對象壓縮大小的估計值,"分區數 * 列數 * 200" 指的是增量統計信息的大小,如果表的統計信息是非增量的,即一直用 Compute Stats 來統計,則不需要這部分。實際應用中很少直接對大表做 Compute Stats,因為執行時間可能很長,一般都是使用 Compute Incremental Stats,因此這部分的內存占用不可忽略。
HdfsTable 代表一張底層存儲為 Kudu 的 Hive 表。Impala 緩存的 Kudu 元數據特別有限:
msTable: HMS API 返回的 Table 對象,主要是 Hive 中的元數據
TableStats: HMS 中存的統計信息,主要是各列統計信息和整張表的行數等
kuduTableName: Kudu 存儲中的實際表名,該名字可以跟 Hive 中的表名不同。
kuduMasters: Kudu 集群的 master 列表
primaryKeyColumnNames: Kudu 表的主鍵列
partitions: Kudu 表的分區信息
kuduSchema: Kudu API 返回的 Schema 信息
關于分區信息,只緩存了分區的列是哪些,以及 hash 分區的分區數,并沒有緩存 Range 分區的各個 Range 是什么,因此在用 SHOW CREATE TABLE 語句時,看到的 range partition 信息只包含了列名。比如下面這個例子,"Partition by range(id)" 部分的各個 range 被省略了:
Query: show create table functional_kudu.dimtbl
+-------------------------------------------------------------------------------------------------------------------------------------------+
| result |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| CREATE TABLE functional_kudu.dimtbl ( |
| id BIGINT NOT NULL ENCODING AUTO_ENCODING COMPRESSION DEFAULT_COMPRESSION, |
| name STRING NULL ENCODING AUTO_ENCODING COMPRESSION DEFAULT_COMPRESSION, |
| zip INT NULL ENCODING AUTO_ENCODING COMPRESSION DEFAULT_COMPRESSION, |
| PRIMARY KEY (id) |
| ) |
| PARTITION BY RANGE (id) (...) |
| STORED AS KUDU |
| TBLPROPERTIES ('STATS_GENERATED'='TASK', 'impala.lastComputeStatsTime'='1573922577', 'kudu.master_addresses'='localhost', 'numRows'='10') |
+-------------------------------------------------------------------------------------------------------------------------------------------+
如果需要查看具體有哪些 range 分區,還是需要用 SHOW RANGE PARTITIONS 語句,Impala 會從 Kudu 中獲取結果來返回,然而還是不會緩存這些 range 信息。
Query: show range partitions functional_kudu.dimtbl
+-----------------------+
| RANGE (id) |
+-----------------------+
| VALUES < 1004 |
| 1004 <= VALUES < 1008 |
| VALUES >= 1008 |
+-----------------------+
Fetched 3 row(s) in 0.07s
這塊個人覺得還有很多工作可做,比如把 range 分區的分界點緩存下來后,可以用來優化 Insert 語句,提升批量導入 Kudu 的性能(IMPALA-7751)。另外關于更細節的信息如每個 kudu tablet 的復本位置,kudu tserver 地址等都是沒有緩存的,利用這些信息實際也能做很多優化,歡迎大家一起來參與開發!
Impala 對 HBase 的支持始于對 Hive 的兼容(Hive 可以讀 HBase 的數據),但目前已經處于維護狀態,社區不再在這方面投入精力。一方面是 Kudu 更適合替代 HBase 來做 OLAP,另一方面是 Impala 也不適合太高并發的 DML 操作。
HBaseTable 代表底層存儲為 HBase 的 Hive 表,緩存了 HMS 中的 Table 定義和表的大小(行數)這些基本的統計信息,另外也緩存了底層 HBase 表的所有列族名。
Impala 緩存了外部系統(Hive、HDFS、Kudu等)的元數據,主要目的是讓查詢計劃生成階段不再需要跟外部系統交互。元數據統一由Catalogd向外部系統獲得,并通過Statestored廣播給所有Coordinator。
生成查詢計劃需要哪些元數據,哪些元數據就會被緩存下來:
Table: Schema(表名、字段名、字段類型、分區字段等)、各列統計信息
HdfsTable: 分區目錄、文件路徑、文件分塊及復本位置、各分區的增量統計信息
KuduTable: 分區列及分區類型(Hash、Range)
HBaseTable: 各列族名
View: 具體的查詢語句
以上就是怎么理解Impala元數據,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。