Ifood如何使用Golang實現每天消耗超過10億條 Kafka 訊息

banq發表於2021-12-22

Ifood它是一家巴西食品科技公司,每天交付超過100 萬個訂單,並且每年增長約 110%。作為一家食品技術公司,該平臺的流量時間主要是在午餐和晚餐時間,而且在週末會更高。
 
我們有一個微服務,用於儲存 Ifoo d的客戶後設資料(我們內部稱其為帳戶後設資料),並且在高峰時段每分鐘達到超過 200 萬個請求。該系統由網路和移動應用程式以及許多內部團隊呼叫以獲取客戶資料。資料儲存在單個 DynamoDB 表中(13 億個專案使用 757.3GB)。
我們在那裡儲存什麼樣的資料?每個 Ifood 使用者的特點。一些特徵示例:

  • - 訂單總數的計數器
  • - 前 3 名最喜歡的菜餚
  • - 最喜歡的餐廳
  • - 使用者所在的細分


 

主要問題
資料團隊的管道,將資料從資料匯出湖使用Databricks和Airflow對其進行處理,最後將其傳送到帳戶的後設資料,包括大量的步驟,並 能很容易失敗。經常有些事情會失敗,因為我們並不總是對每一件事情都有最好的監控。這意味著它不可靠。
鑑於我們的資料質量是我們關注和興趣的核心,這對我們作為使用者配置檔案團隊來說是一個大問題。
這總是一個巨大的痛苦,所以我們開始環顧四周,思考如何改變基礎設施的那部分。這意味著,每天更改數億條記錄的攝取。
 
當我們正在尋找替代方案並試圖找出如何替換整個攝取過程時,Ifood 內部的一個 ML 團隊正在構建一個新的很棒的工具:功能特徵儲存 (FS) 專案。總之,Feature Store 是一種非常輕鬆地提供和共享資料以支援 ML 應用程式、模型訓練和實時預測的方式。一方面,FS 從某處(資料湖、資料倉儲、Kafka 主題等)讀取資料,將其聚合,進行某種處理或計算,然後在另一側(API,在某些資料庫中,Kafka主題等)。
當我們聽到這個訊息時,很明顯這正是我們所需要的:一種集中、獨特且非常有組織的方式來消費來自資料湖的資料。即使我們將 FS 用於與 ML 應用程式並不真正相關的事情,這對我們來說也是一個非常合適的用例。這會讓我們的事情變得非常容易:他們會以某種方式匯出資料,然後我們只需要將其儲存在我們的資料庫中。我們會將超級複雜且非常脆弱的管道更改為強大而可靠的機制。在與 Feature Store 團隊交談後,我們決定他們將透過 Kafka 主題將功能匯出給我們。
但是,FS 無法批次匯出功能,這意味著對於每個 Ifood 客戶(大約 6000 萬)和每個功能,都會匯出一條訊息。當時,我們有大約 20 個功能,但已經計劃將其增加到 ~ 30 或 40。這意味著每天 60mi * 20 = 12 億條訊息,但幾個月後這個數字可能會增加到 1.5bi 以上。
因此,我們每天應該能夠消耗大約 1.5 條 Kafka 訊息。
 

使用特徵儲存 (FS) 中的資料
正如我所說,FS 會將資料匯出到 Kafka 主題中。我們將架構定義為如下所示:

{ 
  account_id: string 
  feature_name: string 
  feature_value: string 
  namespace: string 
  timestamp: int 
}


有了這個,我們可以建立一個消費者來監聽 Kafka 主題並將功能儲存在 DynamoDB 表中。
在 Dynamo 表中,我們將account_id用作分割槽鍵和namespace排序鍵。顧名思義,名稱空間將帳戶後設資料系統提供的資料拆分到不同的上下文中。
這就是我們的表的樣子:

| account_id | namespace | columns and its values… |
| 283a385e-8822–4e6e-a694-eafe62ea3efb | orders | total_orders: 3 | total_orders_lunch: 2 |
| c26d796a-38f9–481f-87eb-283e9254530f | rewards | segmentation: A |

消費者從 Kafka 主題中讀取資料並將資料儲存到 DynamoDB 中。
我們第一次使用 Java 實現了我們的消費者。它表現得相當好,但與我們需要的相差甚遠:每個 pod/消費者每秒消耗 4k 功能。我們嘗試了一些調整和不同的配置,但離 1.5 bi 還很遠。
之後,我們使用goka嘗試了不同的 Go 實現,goka是與 Kafka 互動的高階 Go 庫。效果更好:每個 pod/消費者每秒消耗 8.5k 個功能。然而,離​​我們需要的還很遠。
最後,仍然使用 Go,但使用sarama,我們能夠實現一個工作器每分鐘消耗 100 萬個事件(每個 pod/消費者每秒消耗 20k 個功能。)。每個 pod/consumer 建立三個 goroutine 來處理從 Kafka 收到的訊息。是的,我們做到了!這是第三次嘗試,所以我們學習了一些關於如何正確配置 Kafka 客戶端、設定正確的資料批讀取大小等的知識。
 
Kafka實需要一些調整,這樣Kafka的消費者非常快。主要引數:"fetch.min.bytes”, “auto commiting” and “setting max intervals”.

 

相關文章