未明确定义列存储过程没问题_使用Apache Kudu和Impala实现存储分层
當為應用程序的數據選擇一個存儲系統時,我們通常會選擇一個最適合我們業務場景的存儲系統。對于快速更新和實時分析工作較多的場景,我們可能希望使用 Apache Kudu ,但是對于低成本的大規模可伸縮性場景,我們可能希望使用 HDFS 。因此,需要一種解決方案使我們能夠利用多個存儲系統的最佳特性。本文介紹了如何使用 Apache Impala 的滑動窗口模式,操作存儲在 Apache Kudu 和 Apache HDFS 中的數據,使用此模式,我們可以以對用戶透明的方式獲得多個存儲層的所有優點。
Apache Kudu 旨在快速分析、快速變化的數據。 Kudu 提供快速插入/更新和高效列掃描的組合,以在單個存儲層上實現多個實時分析工作負載。因此, Kudu 非常適合作為存儲需要實時查詢的數據的倉庫。此外, Kudu 支持實時更新和刪除行,以支持延遲到達的數據和數據更正。
Apache HDFS 旨在以低成本實現無限的可擴展性。它針對數據不可變的面向批處理的場景進行了優化,與 Apache Parquet 文件格式配合使用時,可以以極高的吞吐量和效率訪問結構化數據。
對于數據小且不斷變化的情況,如維度表,通常將所有數據保存在 Kudu 中。當數據符合 Kudu 的 擴展限制 并且可以從 Kudu 的特性中受益時,在 Kudu 中保留大表是很常見的。如果數據量大,面向批處理且不太可能發生變化,則首選使用 Parquet 格式將數據存儲在 HDFS 中。當我們需要利用兩個存儲層的優點時,滑動窗口模式是一個有用的解決方案。
滑動窗口模式
在此模式中,我們使用 Impala 創建匹配的 Kudu 表和 Parquet 格式的 HDFS 表。根據 Kudu 和 HDFS 表之間數據移動的頻率,這些表按時間單位分區,通常使用每日、每月或每年分區。然后創建一個統一視圖,并使用 WHERE 子句定義邊界,該邊界分隔從 Kudu 表中讀取的數據以及從 HDFS 表中讀取的數據。定義的邊界很重要,這樣我們就可以在 Kudu 和 HDFS 之間移動數據,而不會將重復的記錄暴露給視圖。移動數據后,可以使用原子的 ALTER VIEW 語句向前移動邊界。
注意:此模式最適用于組織到范圍分區( range partitions )中的某些順序數據,因為在此情況下,按時間滑動窗口和刪除分區操作會非常有效。
該模式實現滑動時間窗口,其中可變數據存儲在 Kudu 中,不可變數據以 HDFS 上的 Parquet 格式存儲。通過 Impala 操作 Kudu 和 HDFS 來利用兩種存儲系統的優勢:
- 流數據可立即查詢 (Streaming data is immediately queryable)
- 可以對更晚到達的數據或手動更正進行更新 (Updates for late arriving data or manual corrections can be made)
- 存儲在 HDFS 中的數據具有最佳大小,可提高性能并防止出現小文件 (Data stored in HDFS is optimally sized increasing performance and preventing small files)
- 降低成本 (Reduced cost)
Impala 還支持 S3 和 ADLS 等云存儲方式。此功能允許方便地訪問遠程管理的存儲系統,可從任何位置訪問,并與各種基于云的服務集成。由于這些數據是遠程的,因此針對 S3 數據的查詢性能較差,使得 S3 適合于保存僅偶爾查詢的“冷”數據。通過創建第三個匹配表并向統一視圖添加另一個邊界,可以擴展此模式以將冷數據保存在云存儲系統中。
注意:為簡單起見,下面的示例中僅說明了 Kudu 和 HDFS 。
將數據從 Kudu 移動到 HDFS 的過程分為兩個階段。第一階段是數據移動,第二階段是元數據更改,最后定義一些定期自動運行的數據任務來輔助我們維護滑動窗口。
在第一階段,將當前不可變數據從 Kudu 復制到 HDFS 。即使數據從 Kudu 復制到 HDFS ,視圖中定義的邊界也會阻止向用戶顯示重復數據。此步驟可以包括根據需要進行的任何驗證和重試,以確保數據卸載 (data offload) 成功。
在第二階段,現在數據被安全地復制到 HDFS ,需要更改元數據以對分區進行調整。這包括向前移動邊界,為下一個時段添加新的 Kudu 分區,以及刪除舊的 Kudu 分區。
實現步驟
為了實現滑動窗口模式,需要一些 Impala 基礎,下面介紹實現滑動窗口模式的基本步驟。
移動數據
只要我們使用每種存儲格式定義匹配表,就可以通過 Impala 在存儲系統之間移動數據。為簡潔起見,未描述創建 Impala 表時可用的所有選項,可以參考 Impala 的 CREATE TABLE文檔 來查找創建 Kudu 、 HDFS 和云存儲表的正確語法。下面列出了一些示例,其中包括滑動窗口模式。
創建表后,移動數據就像 INSERT ... SELECT 語句一樣簡單:
INSERT INTO table_foo SELECT * FROM table_bar;SELECT 語句的所有功能都可用于選擇要移動的特定數據。
注意:如果將數據移動到 Kudu ,可以使用 UPSERT INTO 語句來處理重復鍵。
統一查詢
在 Impala 中查詢來自多個表和數據源的數據也很簡單。為簡潔起見,未描述創建 Impala 視圖時可用的所有選項,可以參考 Impala 的 CREATE VIEW文檔 。
創建統一查詢的視圖就像使用兩個 SELECT 子句和 UNION ALL 的 CREATE VIEW 語句一樣簡單:
CREATE VIEW foo_view ASSELECT col1, col2, col3 FROM foo_parquetUNION ALLSELECT col1, col2, col3 FROM foo_kudu;警告:確保使用 UNION ALL 而不是 UNION 。 UNION 關鍵字本身與 UNION DISTINCT 相同,可能會對性能產生重大影響,可以在 Impala UNION文檔 中找到更多信息。
SELECT 語句的所有功能都可用于公開每個基礎表中的正確數據和列,使用 WHERE 子句傳遞和下推任何需要特殊處理或轉換的謂詞非常重要。下面將在滑動窗口模式的討論中進行更多示例。
此外,可以通過 ALTER VIEW 語句更改視圖,當與 SELECT 語句結合使用時,這很有用,因為它可以用于原子地更新視圖正在訪問的數據。
示例
下面是使用滑動窗口模式來操作具有三個月活動可變的月度周期數據的實現示例,超過三個月的數據將使用 Parquet 格式卸載到 HDFS 。
創建Kudu表
首先,創建一個 Kudu 表,該表將保存三個月的活動可變數據。該表由時間列分區,每個范圍包含一個數據周期。擁有與時間周期匹配的分區很重要,因為刪除 Kudu 分區比通過 DELETE 子句刪除數據更有效。該表還由另一個鍵列進行散列分區,以確保所有數據都不會寫入單個分區。
注意:模式設計 (schema design) 應根據我們的數據和讀/寫性能考慮因素而有所不同。此示例模式僅用于演示目的,而不是“最佳”模式。有關選擇模式的更多指導,請參考 Kudu模式設計文檔(schema design documentation) 。例如,如果數據輸入速率較低,則可能不需要任何散列分區,如果數據輸入速率非常高,則可能需要更多散列桶。
CREATE TABLE my_table_kudu( name STRING, time TIMESTAMP, message STRING, PRIMARY KEY(name, time))PARTITION BY HASH(name) PARTITIONS 4, RANGE(time) ( PARTITION '2018-01-01' <= VALUES < '2018-02-01', --January PARTITION '2018-02-01' <= VALUES < '2018-03-01', --February PARTITION '2018-03-01' <= VALUES < '2018-04-01', --March PARTITION '2018-04-01' <= VALUES < '2018-05-01' --April)STORED AS KUDU;注意:有一個額外的月分區( 2018-04-01至2018-05-01 )可以為數據提供一個時間緩沖區,以便將數據移動到不可變表中。
創建HDFS表
創建 Parquet 格式的 HDFS 表,該表將保存較舊的不可變數據。此表按年、月和日進行分區,以便進行有效訪問,即使我們無法按時間列本身進行分區,這將在下面的視圖步驟中進一步討論。有關更多詳細信息,請參考 Impala的分區文檔 。
CREATE TABLE my_table_parquet( name STRING, time TIMESTAMP, message STRING)PARTITIONED BY (year int, month int, day int)STORED AS PARQUET;創建統一視圖
現在創建統一視圖,用于無縫地查詢所有數據:
CREATE VIEW my_table_view ASSELECT name, time, messageFROM my_table_kuduWHERE time >= "2018-01-01"UNION ALLSELECT name, time, messageFROM my_table_parquetWHERE time < "2018-01-01"AND year = year(time)AND month = month(time)AND day = day(time);每個 SELECT 子句都明確列出要公開的所有列,這可確保不會公開 Parquet 表所特有的年、月和日列。如果需要,它還允許處理任何必要的列或類型映射。
應用于 my_table_kudu 和 my_table_parquet 的初始 WHERE 子句定義了 Kudu 和 HDFS 之間的邊界,以確保在卸載數據的過程中不會讀取重復數據。
應用于 my_table_parquet 的附加 AND 子句用于確保單個年、月和日列的良好謂詞下推 (good predicate pushdown) 。
警告:如前所述,請務必使用 UNION ALL 而不是 UNION 。 UNION 關鍵字本身與 UNION DISTINCT 相同,可能會對性能產生重大影響,可以在 Impala UNION文檔 中找到更多信息。
創建定時任務
現在已創建基表和視圖,接著創建定時任務以維護滑動窗口,下面定時任務中使用的 SQL 文件可以接收從腳本和調度工具傳遞的變量。
創建 window_data_move.sql 文件以將數據從最舊的分區移動到 HDFS :
INSERT INTO ${var:hdfs_table} PARTITION (year, month, day)SELECT *, year(time), month(time), day(time)FROM ${var:kudu_table}WHERE time >= add_months("${var:new_boundary_time}", -1)AND time < "${var:new_boundary_time}";COMPUTE INCREMENTAL STATS ${var:hdfs_table};注意: COMPUTE INCREMENTAL STATS 子句不是必需的,但可幫助我們對 Impala 查詢進行優化。
要運行 SQL 語句,請使用 Impala shell 并傳遞所需的變量,示例如下:
impala-shell -i -f window_data_move.sql--var=kudu_table=my_table_kudu--var=hdfs_table=my_table_parquet--var=new_boundary_time="2018-02-01"注意:可以調整 WHERE 子句以匹配給定的數據周期和卸載的粒度,這里, add_months 函數的參數為 -1 ,用于從新的邊界時間移動過去一個月的數據。
創建 window_view_alter.sql 文件以通過更改統一視圖來調整時間邊界:
ALTER VIEW ${var:view_name} ASSELECT name, time, messageFROM ${var:kudu_table}WHERE time >= "${var:new_boundary_time}"UNION ALLSELECT name, time, messageFROM ${var:hdfs_table}WHERE time < "${var:new_boundary_time}"AND year = year(time)AND month = month(time)AND day = day(time);要運行 SQL 語句,請使用 Impala shell 并傳遞所需的變量,示例如下:
impala-shell -i -f window_view_alter.sql--var=view_name=my_table_view--var=kudu_table=my_table_kudu--var=hdfs_table=my_table_parquet--var=new_boundary_time="2018-02-01"創建 window_partition_shift.sql 文件以調整 Kudu 分區:
ALTER TABLE ${var:kudu_table}ADD RANGE PARTITION add_months("${var:new_boundary_time}", ${var:window_length}) <= VALUES < add_months("${var:new_boundary_time}", ${var:window_length} + 1);ALTER TABLE ${var:kudu_table} DROP RANGE PARTITION add_months("${var:new_boundary_time}", -1) <= VALUES < "${var:new_boundary_time}";要運行 SQL 語句,請使用 Impala shell 并傳遞所需的變量,示例如下:
impala-shell -i -f window_partition_shift.sql--var=kudu_table=my_table_kudu--var=new_boundary_time="2018-02-01"--var=window_length=3注意:應該定期在 Kudu 表上運行 COMPUTE STATS ,以確保 Impala 的查詢性能最佳。
試驗
現在我們已經創建了表、視圖和腳本來使用滑動窗口模式,可以通過插入不同時間范圍的數據并運行腳本來向前移動窗口來進行試驗。
將一些示例值插入 Kudu 表:
INSERT INTO my_table_kudu VALUES('joey', '2018-01-01', 'hello'),('ross', '2018-02-01', 'goodbye'),('rachel', '2018-03-01', 'hi');在每個表/視圖中顯示數據:
SELECT * FROM my_table_kudu;SELECT * FROM my_table_parquet;SELECT * FROM my_table_view;將1月數據移動到 HDFS :
impala-shell -i -f window_data_move.sql--var=kudu_table=my_table_kudu--var=hdfs_table=my_table_parquet--var=new_boundary_time="2018-02-01"確認數據在兩個位置,但在視圖中不重復:
SELECT * FROM my_table_kudu;SELECT * FROM my_table_parquet;SELECT * FROM my_table_view;改變視圖將時間邊界向前移至2月:
impala-shell -i -f window_view_alter.sql--var=view_name=my_table_view--var=kudu_table=my_table_kudu--var=hdfs_table=my_table_parquet--var=new_boundary_time="2018-02-01"確認數據仍在兩個位置,但在視圖中不重復:
SELECT * FROM my_table_kudu;SELECT * FROM my_table_parquet;SELECT * FROM my_table_view;調整 Kudu 分區:
impala-shell -i -f window_partition_shift.sql--var=kudu_table=my_table_kudu--var=new_boundary_time="2018-02-01"--var=window_length=3確認1月數據現在僅在 HDFS 中:
SELECT * FROM my_table_kudu;SELECT * FROM my_table_parquet;SELECT * FROM my_table_view;使用 Impala 的 EXPLAIN 語句確認謂詞下推:
EXPLAIN SELECT * FROM my_table_view;EXPLAIN SELECT * FROM my_table_view WHERE time < "2018-02-01";EXPLAIN SELECT * FROM my_table_view WHERE time > "2018-02-01";在 explain 輸出中,我們應該看到“ kudu 謂詞”,其中包括“ SCAN KUDU ”部分中的時間列過濾器和“謂詞”,其中包括“ SCAN HDFS ”部分中的時間、日、月和年列。
總結
以上是生活随笔為你收集整理的未明确定义列存储过程没问题_使用Apache Kudu和Impala实现存储分层的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为如何拍火烧云_华为手机拍照功能介绍-
- 下一篇: 居中符号怎么打_小学语文标点符号的正确书