簡體   English   中英

AWS Athena查詢分區

[英]AWS Athena Query Partitioning

我正在嘗試使用AWS Athena為現有平台提供分析。 當前流程如下:

  1. 數據作為JSON事件被抽入Kinesis Firehose。
  2. Firehose使用AWS Glue中的表格將數據轉換為實木復合地板,並每15分鍾或當流達到128 MB(最大支持值)時寫入S3。
  3. 將數據寫入S3時,將使用路徑/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/...分區/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/...
  4. AWS Glue搜尋器每24小時使用最新的分區數據更新一個表,並使該表可用於查詢。

基本流程起作用。 但是,這有兩個問題……

第一個(也是最重要的)是此數據是多租戶應用程序的一部分。 每個事件中都有一個名為account_id的屬性。 將會發出的每個查詢都將由一個特定的帳戶發出,我不想為每個查詢掃描所有帳戶數據。 我需要找到一種可伸縮的方式,僅查詢相關數據。 我確實嘗試過向我們Kinesis提取account_id並將其用作分區。 但是,當前不支持此功能,並且擁有10,000多個帳戶時,AWS 20k分區限制很快就成為問題。

第二個問題是文件大小! AWS建議文件大小不要小於128 MB,因為這會對查詢時間產生不利影響,因為執行引擎可能會花費更多時間來打開Amazon S3文件。 考慮到Firehose的性質,每個文件最大只能達到128 MB。

擁有這么多帳戶,出於多種原因,您可能不想使用account_id作為分區鍵。 我認為您是很好的限制, 每個表的分區限制為1M ,但這並不意味着它是一個好主意。

但是,通過對部分帳戶ID進行分區,可以大大減少掃描的數據量。 如果您的帳戶ID是均勻分布的(例如AWS帳戶ID),則可以在前綴上進行分區。 如果您的帳戶ID是數字分區,則在第一個數字上進行分區將使每個查詢將掃描的數據量減少90%,在兩位數的基礎上減少99%,同時仍將分區數保持在非常合理的水平。

不幸的是,我也不知道如何用Glue做到這一點。 我發現在進行ETL時,Glue通常非常無用。 就我而言,即使簡單的事情也很難。 使用Athena的CTAS功能與一些簡單的S3操作相結合,將CTAS操作產生的數據添加為現有表中的分區,我獲得了更大的成功。

如果您想出一種提取帳戶ID的方法, 也可以對每個帳戶使用單獨的表進行試驗, 則數據庫中可以有100K個表 它與表中的分區沒有太大區別,但是可以更快,具體取決於Athena如何確定要查詢的分區。

不必太擔心128 MB文件大小的經驗法則。 毫無疑問,擁有很多小文件比擁有幾個大文件要糟-但是,也確實要掃描大量數據以過濾出一小部分,這對性能和成本都非常不利。 即使對數百個文件大小只有幾KB的文件進行查詢,Athena都可以在一秒鍾內提供結果。 我會擔心確保Athena首先讀取正確的數據,然后再確保理想的文件大小。

如果您告訴我有關每個帳戶的數據量和帳戶的預期壽命的更多信息,我可以針對目標提供更詳細的建議。


更新:鑒於Firehose不允許您更改輸入數據的目錄結構,並且Glue通常非常糟糕,並且您在注釋中提供了其他上下文,因此我將執行以下操作:

  • 創建一個Athena表,其中包含數據中所有屬性的列,並將日期作為分區鍵。 這是您的輸入表,將僅對該表運行ETL查詢。 不必擔心輸入數據具有用於年,月和日的單獨目錄,您只需要一個分區鍵。 將它們作為單獨的分區鍵只會使事情變得復雜,並且具有一種意味着它可以是DATE類型,而不是每次要進行日期計算時都必須將其組合成一個日期的三個單獨的STRING列。

  • 創建具有相同列的另一個Athena表,但按account_id_prefix以及日期或月份進行分區。 這將是您對其運行查詢的表。 account_id_prefix將是您帳戶ID中的一兩個字符–您必須測試最有效的方法。 您還必須決定是按日期分區還是更長的時間跨度。 日期將使ETL更容易和更便宜,但是更長的時間跨度將產生更少和更大的文件,這可以使查詢效率更高(但可能更昂貴)。

  • 創建一個執行以下操作的“步函數”狀態機(在Lambda函數中):

    • 將新分區添加到輸入表。 如果您將狀態機計划為每天運行一次,則只需添加與當前日期相對應的分區即可。 使用Glue CreatePartition API調用來創建分區(不幸的是,這需要大量信息才能工作,但是您可以運行GetTable調用來獲取它。例如,將["2019-04-29"]用作Values"s3://some-bucket/firehose/year=2019/month=04/day=29"作為StorageDescriptor.Location 。這等效於運行ALTER TABLE some_table ADD PARTITION (date = '2019-04-29) LOCATION 's3://some-bucket/firehose/year=2019/month=04/day=29'但是通過Glue進行操作比在Athena中運行查詢更快,並且更適合Lambda。
    • 使用當前日期的過濾器在輸入表上啟動CTAS查詢 ,該過濾器按第一個字符或帳戶ID和當前日期進行分區。 將CTAS輸出的位置使用在查詢表的位置下方。 為CTAS操作創建的表生成一個隨機名稱,該表將在以后的步驟中刪除。 使用Parquet作為格式。
    • 查看“ 作業狀態輪詢”示例狀態機,以獲取有關如何等待CTAS操作完成的靈感。
    • 當CTAS操作完成時,列出使用Glue GetPartitions創建的臨時表中創建的分區,並使用BatchCreatePartitions在查詢表中創建相同的分區。
    • 最后,刪除屬於已刪除查詢表分區的所有文件,並刪除由CTAS操作創建的臨時表。

如果您決定對某個日期進行更長的分區,您仍然可以使用上面的過程,但是您還需要刪除查詢表中的分區以及S3上的相應數據,因為每次更新都將替換現有數據(例如,按月進行分區) ,我建議您每天嘗試嘗試創建一個月的新文件,這意味着需要刪除舊文件。 如果您想每天多次更新查詢表,那將是相同的。

這看起來很像,並且看起來像Glue Crawlers和Glue ETL所做的一樣-但以我的經驗來看,他們做起來並不容易。

在您的情況下,數據使用Hive樣式分區進行了分區,這是Glue Crawlers理解的,但是在許多情況下,您不會獲得Hive樣式分區,而僅是Y / M / D(而且我實際上並不知道Firehose可以提供此數據方式,我以為只做Y / M / D)。 Glue Crawler每次運行時也會做很多額外的工作,因為它不知道在何處添加了數據,但是您知道自昨天以來添加的唯一分區是昨天的分區,因此減少了爬網一鍵交易。

膠水ETL也使事情變得非常困難,與Lambda和Step Functions相比,它是一項昂貴的服務。 您要做的就是將原始數據格式從JSON轉換為Parquet並重新分區。 據我所知,用比雅典娜CTAS查詢更少的代碼來做到這一點是不可能的。 即使您可以使用更少的代碼使用Glue ETL進行轉換操作,您仍然必須編寫大量代碼來替換目標表中的分區-因為那是Glue ETL和Spark根本不支持的東西。

Athena CTAS並不是真正要做ETL的工具,我認為我上面概述的方法比應該的復雜得多,但是我相信它比嘗試做相同的事情要簡單(即不斷更新)並有可能根據另一個表中的數據替換表中的分區,而無需每次都重新構建整個表)。

通過此ETL過程,您獲得的數據不必擔心按時間划分分區,但是您仍然可以獲得針對查詢進行優化的表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM