使用 ElasticSearch 對 Highload 項目進行負載優化

嘿哈布爾! 我叫 Maxim Vasiliev,在 FINCH 擔任分析師和項目經理。 今天我想告訴您,我們如何使用 ElasticSearch 在 15 分鐘內處理 6 萬個請求並優化我們一位客戶網站上的每日負載。 不幸的是,我們將不得不沒有名字,因為我們有保密協議,我們希望文章的內容不會受到影響。 我們走吧。

項目如何運作

在我們的後端,我們創建服務以確保我們客戶的網站和移動應用程序的性能。 大致結構可以看圖:

使用 ElasticSearch 對 Highload 項目進行負載優化

在工作過程中,我們處理大量交易:購買、支付、用戶餘額操作,我們為此存儲大量日誌,以及將這些數據導入和導出到外部系統。

當我們從客戶端接收數據並將其傳遞給用戶時,也有相反的過程。 此外,還有處理付款和獎金計劃的流程。

簡要背景

最初,我們使用 PostgreSQL 作為唯一的數據存儲。 它對於 DBMS 的標準優勢:事務的存在、開發的數據採樣語言、廣泛的集成工具; 結合良好的性能,滿足了我們很長一段時間的需求。

我們將所有數據都存儲在 Postgres 中:從交易到新聞。 但是用戶數量增加了,請求數量也隨之增加。

據了解,2017 年僅桌面網站的年會話數為 131 億。2018 年為 125 億。2019 年再次為 130 億。再加上移動版網站和移動應用程序的 100-200 億,你將收到大量請求。

隨著項目的增長,Postgres 停止處理負載,我們沒有時間 - 出現了大量不同的查詢,我們無法為其創建足夠數量的索引。

我們知道需要其他數據存儲來滿足我們的需求並減輕 PostgreSQL 的負擔。 Elasticsearch 和 MongoDB 被認為是可能的選擇。 後者在以下幾點上失利:

  1. 隨著索引中數據量的增長,索引速度變慢。 使用 Elastic,速度不取決於數據量。
  2. 沒有全文搜索

所以我們為自己選擇了 Elastic 並為過渡做好了準備。

過渡到 Elastic

1. 我們從銷售點搜索服務開始轉型。 我們的客戶總共有大約 70 個銷售點,這需要在網站和應用程序中進行多種類型的搜索:

  • 按城市名稱進行文本搜索
  • 從某個點在給定半徑內進行地理搜索。 例如,如果用戶想查看哪些銷售點離他家最近。
  • 按給定的正方形搜索 - 用戶在地圖上繪製一個正方形,並向他顯示該半徑內的所有點。
  • 按其他過濾器搜索。 銷售點在分類上各不相同

如果我們談論組織,那麼在 Postgres 中,我們有地圖和新聞的數據源,而在 Elastic 中,快照是從原始數據中獲取的。 事實上,最初 Postgres 無法處理所有標準的搜索。 不僅有很多索引,它們還可能重疊,所以 Postgres 調度器迷路了,不知道該使用哪個索引。

2. 接下來是新聞版塊。 網站上每天都會出現出版物,這樣用戶就不會迷失在信息流中,必須在發布前對數據進行分類。 這就是搜索的用途:您可以通過文本匹配來搜索網站,同時連接額外的過濾器,因為它們也是通過 Elastic 製作的。

3.然後我們把事務處理搬過來了。 用戶可以在網站上購買某種產品並參加抽獎。 此類購買後,我們會處理大量數據,尤其是在周末和節假日。 相比之下,如果平時的購買量在1,5萬到2萬之間,那麼節假日這個數字就可以達到53萬。

同時,必須在盡可能短的時間內處理數據——用戶不喜歡等待幾天的結果。 無法通過 Postgres 實現這樣的截止日期——我們經常收到鎖,當我們處理所有請求時,用戶無法檢查他們是否收到獎品。 這對業務來說不是很愉快,所以我們將處理轉移到 Elasticsearch。

週期性

現在更新是基於事件配置的,根據以下條件:

  1. 銷售點。 一旦我們從外部來源接收到數據,我們就會立即開始更新。
  2. 消息。 一旦在網站上編輯了任何新聞,它就會自動發送到 Elastic。

這裡再次值得一提的是 Elastic 的優勢。 在 Postgres 中,發送請求時,必須等到它老老實實處理完所有記錄。 您可以將 10 條記錄發送到 Elastic 並立即開始工作,而無需等待記錄分佈到所有分片。 當然,有些 Shard 或者 Replica 可能不會馬上看到數據,但是很快就會有一切。

整合方法

有兩種方法可以與 Elastic 集成:

  1. 通過基於 TCP 的本機客戶端。 本機驅動程序正在逐漸消失:不再支持它,它的語法非常不方便。 因此,我們實際上不使用它並試圖完全放棄它。
  2. 通過可以同時使用 JSON 請求和 Lucene 語法的 HTTP 接口。 最後一個是使用 Elastic 的文本引擎。 在此版本中,我們能夠通過 HTTP 對 JSON 請求進行批處理。 這是我們嘗試使用的選項。

多虧了 HTTP 接口,我們可以使用提供 HTTP 客戶端異步實現的庫。 我們可以利用 Batch 和異步 API,這會產生高性能,這在大促銷的日子裡幫助很大(更多內容見下文)

一些數字進行比較:

  • 在不分組的情況下在 20 個線程中保存 Postgres 賞金用戶:460713 秒內 42 條記錄
  • 10 個線程的彈性 + 反應式客戶端 + 1000 個元素的批處理:596749 秒內 11 條記錄
  • 10 個線程的彈性 + 反應式客戶端 + 1000 個元素的批處理: 23801684 分鐘內 4 個條目

現在我們已經編寫了一個 HTTP 請求管理器,它將 JSON 構建為 Batch/not Batch 並通過任何 HTTP 客戶端發送它,而不考慮庫。 您還可以選擇同步或異步發送請求。

在一些集成中,我們仍然使用官方傳輸客戶端,但這只是下一次重構的事情。 本例採用基於Spring WebClient構建的自定義客戶端進行處理。

使用 ElasticSearch 對 Highload 項目進行負載優化

大促銷

每年一次,該項目都會為用戶舉辦一次大型促銷活動——這是同樣的 Highload,因為此時我們同時與數千萬用戶合作。

通常負載高峰出現在假期期間,但這次促銷活動處於完全不同的水平。 前年大促當天,我們賣出了27萬件商品。 數據處理了半個多小時,給用戶帶來了不便。 用戶因參與而獲得獎品,但很明顯需要加快這一過程。

2019 年初,我們決定需要 ElasticSearch。 整整一年,我們組織了 Elastic 中接收到的數據的處理,以及它們在移動應用程序和網站的 API 中的發布。 結果,在第二年的競選期間,我們處理了 15 分鐘內有 131 個條目。

由於我們有很多人想要購買商品並參與促銷活動中的獎品,這是一個臨時措施。 現在我們正在向 Elastic 發送最新信息,但未來我們計劃將過去幾個月的存檔信息傳輸到 Postgres 作為永久存儲。 為了不堵塞Elastic index,這也有其局限性。

結論/結論

目前,我們已經將我們想要的所有服務轉移到 Elastic 並暫時暫停。 現在我們在 Postgres 的主要持久存儲之上在 Elastic 中構建一個索引,它接管了用戶負載。

將來,如果我們了解數據請求變得過於多樣化並且搜索無限數量的列,我們計劃轉移服務。 這不再是 Postgres 的任務。

如果我們在功能上需要全文搜索,或者如果我們有很多不同的搜索條件,那麼我們已經知道這需要轉化為 Elastic。

⌘⌘⌘

謝謝閱讀。 如果您的公司也使用 ElasticSearch 並且有自己的實施案例,請告訴我們。 知道別人怎麼樣會很有趣🙂

來源: www.habr.com

添加評論