使用ELASTICSEARCH進行近實時索引 - bozho

banq發表於2019-12-10

選擇索引策略很困難。雖然Elasticsearch 文件確實有一些一般建議,有一些小技巧,但它也取決於特定用例。在典型情況下,您有一個資料庫作為事實的來源,並且有一個使事物可搜尋的索引。您可以採用以下策略:
  • 隨著資料的到來而建立索引–您可以同時插入資料庫並建立索引。如果沒有太多資料,這是有道理的。否則索引將變得非常低效。
  • 儲存在資料庫中,並與計劃的作業一起建立索引–這可能是最常見的方法,並且易於實現。但是,如果要索引的資料很多,則可能會出現問題,因為必須使用資料庫中的(從,到)條件來精確地獲取該資料,並且索引落後於實際資料的秒數(或分鐘)在計劃的作業執行之間
  • 推送到訊息佇列並編寫索引使用方–您可以執行RabbitMQ之類的東西,並讓多個使用方輪詢資料併為其編制索引。這不是容易實現的,因為您必須輪詢多個專案才能利用批處理索引,然後僅在成功執行批處理時將它們標記為已使用-有點交易行為。
  • 對記憶體中的專案進行排隊並定期對其進行重新整理–這可能是好的且高效的,但是如果節點死亡,則可能會丟失資料,因此您必須根據資料庫中的資料進行某種執行狀況檢查
  • 混合-結合以上內容;例如,如果需要在以後充實原始資料並更新索引,則可以在記憶體中對專案進行排隊,然後使用“儲存在資料庫中,具有計劃作業的索引”來更新索引並填寫任何缺失的專案。或者,您可以在資料的某些部分出現時建立索引,並對更活躍的資料型別使用另一種策略

我們最近決定實施“記憶體中佇列”方法(與另一方法結合使用,因為無論如何我們都必須進行一些計劃的後處理)。最初的嘗試是使用Elasticsearch客戶端提供的類BulkProcessor。邏輯很清晰:如果達到一定限制或以固定的時間間隔,將索引請求儲存在記憶體中並批次將其重新整理到Elasticsearch。因此,最多每隔X秒,最多每隔Y個記錄將有一個批處理索引請求。這樣就可以實現近實時索引,而不會給Elasticsearch帶來太大的壓力。根據Elasticsearch的建議,它還允許同時多個批次索引請求。

但是,我們使用了BulkProcessor不支援的REST API(透過Jest)。我們嘗試插入REST索引邏輯,而不是當前的本機邏輯,儘管它幾乎可以正常工作,但在此過程中,我們注意到了一些令人擔憂的問題- internalAdd每次將索引請求新增到批次請求時都會呼叫該方法synchronized。這意味著執行緒將阻塞,等待彼此新增內容。對於生產環境來說,這聽起來不太理想且有風險。

因此我們進行了單獨的實施:可以在這裡看到– ESBulkProcessor

它允許多個執行緒同時重新整理到Elasticsearch,但是隻有一個執行緒(使用鎖)要從佇列中使用以形成批處理。由於這是一項快速的操作,因此最好對其進行序列化。並不是因為併發佇列無法處理從中讀取的多個執行緒,而是可以;但是達到同時由多個執行緒形成批次的條件將導致幾個小批次而不是一個大批次,因此一次只需要一個消費者。這不是一個大問題,因此可以將其刪除。但重要的是要注意它沒有阻塞。

這已經生產了一段時間了,似乎沒有任何問題。如果由於負載增加或邊緣情況而發生更改,我將報告任何更改。
如果這是唯一的索引邏輯,則必須重申該問題–您的應用程式節點可能會失敗,並且最終可能會導致Elasticsearch中的資料丟失。我們不在那種情況下,我不確定哪種方法是最好的補救方法–是在伺服器發生故障的情況下對近期資料進行部分重新索引,或者透過批處理檢查是否沒有資料庫和索引之間不匹配。當然,我們還應該說您可能並不總是擁有一個資料庫–有時,Elasticsearch就是您用於資料儲存的全部,在這種情況下,需要某種佇列永續性。
最終目標是實現近乎實時的索引編制,因為使用者期望儘快看到他們的資料,同時又不影響Elasticsearch叢集。
“什麼是對資料建立索引的最佳方法”這一主題非常重要,我希望至少已經澄清了一點,並且我們的貢獻對於其他情況也很有意義。







 

相關文章