溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么理解Impala元數(shù)據(jù)

發(fā)布時間:2021-11-23 10:48:14 來源:億速云 閱讀:135 作者:柒染 欄目:大數(shù)據(jù)

本篇文章給大家分享的是有關(guān)怎么理解Impala元數(shù)據(jù),小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

背景

Impala是一個高性能的OLAP查詢引擎,與其它SQL-on-Hadoop的ROLAP解決方案如Presto、SparkSQL 等不同的是,Impala對元數(shù)據(jù)(Metadata/Catalog)做了緩存,因此在做查詢計劃生成時不再依賴外部系統(tǒng)(如Hive、HDFS、Kudu),能做到毫秒級別的生成時間。另外緩存元數(shù)據(jù)也能極大減少對底層系統(tǒng)Master節(jié)點(Hive Metastore、HDFS NameNode、Kudu Master)的負(fù)載。

然而事情總有兩面性,元數(shù)據(jù)緩存給Impala的系統(tǒng)設(shè)計引入了極大的復(fù)雜性。一方面在功能上為了維護(hù)緩存的正確性,引入了兩個Impala特有的SQL語句:Invalidate Metadata 和 Refresh,另外還引入了query option SYNC_DDL。這些都讓用戶參與了緩存的維護(hù)。另一方面在架構(gòu)設(shè)計上,有許多元數(shù)據(jù)相關(guān)的復(fù)雜設(shè)計,比如元數(shù)據(jù)的增量傳播、緩存一致性的維護(hù)等。

在數(shù)倉規(guī)模較大時,Impala的元數(shù)據(jù)設(shè)計暴露出了許多問題,比如大表的元數(shù)據(jù)加載和刷新時間特別長、元數(shù)據(jù)的廣播會被DDL阻塞導(dǎo)致廣播延遲很大、元數(shù)據(jù)緩存導(dǎo)致節(jié)點Full GC或OOM等。因此Impala元數(shù)據(jù)設(shè)計也一直在演化之中,最新進(jìn)展主要集中在Fetch-on-demand coordinator(又稱local catalog mode、catalog-v2等)的設(shè)計。

Impala Server簡介

Impala集群包含一個 Catalog Server (Catalogd)、一個 Statestore Server (Statestored) 和若干個 Impala Daemon (Impalad)。Catalogd 主要負(fù)責(zé)元數(shù)據(jù)的獲取和DDL的執(zhí)行,Statestored主要負(fù)責(zé)消息/元數(shù)據(jù)的廣播,Impalad主要負(fù)責(zé)查詢的接收和執(zhí)行。

怎么理解Impala元數(shù)據(jù)

Impalad 又可配置為 coordinator only、 executor only 或 coordinator and executor(默認(rèn))三種模式。Coordinator角色的Impalad負(fù)責(zé)查詢的接收、計劃生成、查詢的調(diào)度等,Executor角色的Impalad負(fù)責(zé)數(shù)據(jù)的讀取和計算。默認(rèn)配置下每個Impalad既是Coordinator又是Executor。生產(chǎn)環(huán)境建議做好角色分離,即每個Impalad要么是Coordinator要么是Executor,且可以以1:50的比例配置。更多細(xì)節(jié)可參考官方文檔[1].

Impala元數(shù)據(jù)的構(gòu)成

Impala的元數(shù)據(jù)緩存在catalogd和各個Coordinator角色的Impalad中。Catalogd中的緩存是最新的,各個Coordinator都緩存的是Catalogd內(nèi)元數(shù)據(jù)的一個復(fù)本。如下圖所示,元數(shù)據(jù)由Catalogd向外部系統(tǒng)獲取,并通過 Statestored 傳播給各個 Coordinator。

怎么理解Impala元數(shù)據(jù)

元數(shù)據(jù)緩存主要由Java代碼實現(xiàn),主體代碼在FE中。另有一些C++實現(xiàn)的代碼,主要處理FE跟BE的交互,以及元數(shù)據(jù)的廣播。代碼中把 Catalogd 和 Coordinator (Impalad) 中相同的元數(shù)據(jù)管理邏輯抽出來放在了 Catalog.java 中,Catalogd 里的實現(xiàn)是 CatalogServiceCatalog.java,Coordinator 里的實現(xiàn)是 ImpaladCatalog.java. 

Catalog是一個層級結(jié)構(gòu),第一層是 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 列表,主要表示同名函數(shù)的不同重載。tableCache_ 由 CatalogObjectCache 來維護(hù)。CatalogObjectCache 封裝了一個 ConcurrentHashMap,另加了版本管理的邏輯,比如避免低版本的更新覆蓋高版本的緩存、追蹤所有緩存的版本號等。這些版本管理邏輯在Impalad中尤其重要。我們在后續(xù)的文章中會詳細(xì)介紹。

Table 在代碼里有五個具體的子類:HdfsTable、KuduTable、HBaseTable、View、IncompleteTable、DataSourceTable。前4個都比較直白,解釋下最后兩個:

  • IncompleteTable 表示未加載元數(shù)據(jù)的表或視圖(View)。Catalogd 啟動時,為了減少啟動時間,只加載了所有表的表名,每個表用IncompleteTable來表示。如果執(zhí)行了INVALIDATE METADATA,則表的元數(shù)據(jù)也會被清空,其表現(xiàn)就是回置成了IncompleteTable。IncompleteTable可能代表一個視圖,但這在元數(shù)據(jù)未加載時是無法確定的。因此在HUE等可視化界面中使用Impala時,常常會看到一個View是用Table的圖標(biāo)表示的,但一旦有被使用過,就又變回成了View的圖標(biāo)。

  • DataSourceTable 屬于external data source的實現(xiàn),這塊沒有任何文檔提及,因為一直處于實驗狀態(tài)。其初衷是提供一個Java接口來自定義外部數(shù)據(jù)源,只需要實現(xiàn) prepare、open、getNext、close 這幾個接口。具體可參考代碼里的 EchoDataSource 和 AllTypesDataSource。

接下來我們重點介紹下前三個的元數(shù)據(jù)構(gòu)成。

HdfsTable

HdfsTable 代表一張底層存儲為 HDFS 的 Hive 表。無分區(qū)表的元數(shù)據(jù)比較簡單,少了各個分區(qū)對應(yīng)的元數(shù)據(jù)。這里以分區(qū)表為例,其元數(shù)據(jù)如圖所示:

怎么理解Impala元數(shù)據(jù)

其中 msTable 和 msPartition 表示 HMS API 里返回的對象:

org.apache.hadoop.hive.metastore.api.Tableorg.apache.hadoop.hive.metastore.api.Partition

HdfsPartition 代表一個分區(qū)的元數(shù)據(jù),其一大部分內(nèi)容是 HDFS 文件和塊的信息。圖中的 FileDescriptor 和 BlockDescriptor,就是從 HDFS API 里返回的 FileStatus 和 BlockLocation 對象抽取數(shù)據(jù)后生成的。為了節(jié)省空間,實際緩存的并不是上圖展示的 FileDescriptor 和 FileBlock。IMPALA-4029 引入了 FlatBuffer 來壓縮 FileDescriptor 和 FileBlock。FlatBuffer 的好處是不需要像 protobuf 或 thrift 一樣做序列化和反序列化,但卻可以直接訪問對象里的內(nèi)容,同時帶來了一定的壓縮比。更多關(guān)于 FlatBuffer 參見文末文檔 [2].

HdfsPartition 的另一大部分內(nèi)容是增量統(tǒng)計信息,緩存的是deflate算法壓縮后的數(shù)據(jù),具體詳見:PartitionStatsUtil#partStatsFromCompressedBytes()。解壓之后是一個 TPartitionStats 對象,主要包含了各列在該partition里的統(tǒng)計信息,每列的統(tǒng)計信息用一個 TIntermediateColumnStats 表示:

struct TIntermediateColumnStats {
 1: optional binary intermediate_ndv // NDV HLL 計算的中間結(jié)果
 2: optional bool is_ndv_encoded     // HLL中間結(jié)果是否有用 RLE 壓縮
 3: optional i64 num_nulls           // 該列在該分區(qū)的 NULL 數(shù)目
 4: optional i32 max_width           // 該列在該分區(qū)的最大長度
 5: optional double avg_width        // 該列在該分區(qū)的平均長度
 6: optional i64 num_rows            // 該分區(qū)行數(shù),用于聚集HLL中間結(jié)果
}

關(guān)于 Impala 里 ndv() 的實現(xiàn),可參考 be/src/exprs/aggregate-functions-ir.cc 中的 HllInit()、HllUpdate()、HllMerge()、HllFinalEstimate() 的邏輯。ndv 的中間結(jié)果用一個string表示,長度為 1024。在傳輸時一般會用 RLE (Run Length Encoding) 壓縮。

Impala的統(tǒng)計信息受限于Hive(因為要保存在Hive Metastore中),目前并沒有統(tǒng)計數(shù)值類型列的最大最小、平均值等信息。這塊有個古老的 JIRA: IMPALA-2416,目前還沒有進(jìn)展。

一個HDFS分區(qū)表的元數(shù)據(jù)在各種壓縮后,在內(nèi)存中的大小約為

分區(qū)數(shù)*2048 + 分區(qū)數(shù)*列數(shù)*400 + 文件數(shù)*500 + 塊數(shù)目*150

實際應(yīng)用中要降低大表的元數(shù)據(jù)大小,就需要在分區(qū)數(shù)、列數(shù)、文件數(shù)、塊數(shù)目上尋求優(yōu)化的空間。其中 2048、400、500、150 這些數(shù)都是各對象壓縮大小的估計值,"分區(qū)數(shù) * 列數(shù) * 200" 指的是增量統(tǒng)計信息的大小,如果表的統(tǒng)計信息是非增量的,即一直用 Compute Stats 來統(tǒng)計,則不需要這部分。實際應(yīng)用中很少直接對大表做 Compute Stats,因為執(zhí)行時間可能很長,一般都是使用 Compute Incremental Stats,因此這部分的內(nèi)存占用不可忽略。

KuduTable

HdfsTable 代表一張底層存儲為 Kudu 的 Hive 表。Impala 緩存的 Kudu 元數(shù)據(jù)特別有限:

  • msTable: HMS API 返回的 Table 對象,主要是 Hive 中的元數(shù)據(jù)

  • TableStats: HMS 中存的統(tǒng)計信息,主要是各列統(tǒng)計信息和整張表的行數(shù)等

  • kuduTableName: Kudu 存儲中的實際表名,該名字可以跟 Hive 中的表名不同。

  • kuduMasters: Kudu 集群的 master 列表

  • primaryKeyColumnNames: Kudu 表的主鍵列

  • partitions: Kudu 表的分區(qū)信息

  • kuduSchema: Kudu API 返回的 Schema 信息

關(guān)于分區(qū)信息,只緩存了分區(qū)的列是哪些,以及 hash 分區(qū)的分區(qū)數(shù),并沒有緩存 Range 分區(qū)的各個 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 分區(qū),還是需要用 SHOW RANGE PARTITIONS 語句,Impala 會從 Kudu 中獲取結(jié)果來返回,然而還是不會緩存這些 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 分區(qū)的分界點緩存下來后,可以用來優(yōu)化 Insert 語句,提升批量導(dǎo)入 Kudu 的性能(IMPALA-7751)。另外關(guān)于更細(xì)節(jié)的信息如每個 kudu tablet 的復(fù)本位置,kudu tserver 地址等都是沒有緩存的,利用這些信息實際也能做很多優(yōu)化,歡迎大家一起來參與開發(fā)!

HBaseTable

Impala 對 HBase 的支持始于對 Hive 的兼容(Hive 可以讀 HBase 的數(shù)據(jù)),但目前已經(jīng)處于維護(hù)狀態(tài),社區(qū)不再在這方面投入精力。一方面是 Kudu 更適合替代 HBase 來做 OLAP,另一方面是 Impala 也不適合太高并發(fā)的 DML 操作。

HBaseTable 代表底層存儲為 HBase 的 Hive 表,緩存了 HMS 中的 Table 定義和表的大?。ㄐ袛?shù))這些基本的統(tǒng)計信息,另外也緩存了底層 HBase 表的所有列族名。

總結(jié)

Impala 緩存了外部系統(tǒng)(Hive、HDFS、Kudu等)的元數(shù)據(jù),主要目的是讓查詢計劃生成階段不再需要跟外部系統(tǒng)交互。元數(shù)據(jù)統(tǒng)一由Catalogd向外部系統(tǒng)獲得,并通過Statestored廣播給所有Coordinator。

生成查詢計劃需要哪些元數(shù)據(jù),哪些元數(shù)據(jù)就會被緩存下來:

  • Table: Schema(表名、字段名、字段類型、分區(qū)字段等)、各列統(tǒng)計信息

    • HdfsTable: 分區(qū)目錄、文件路徑、文件分塊及復(fù)本位置、各分區(qū)的增量統(tǒng)計信息

    • KuduTable: 分區(qū)列及分區(qū)類型(Hash、Range)

    • HBaseTable: 各列族名

    • View: 具體的查詢語句

以上就是怎么理解Impala元數(shù)據(jù),小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI