將數據從PostgreSQL同步到Elasticsearch的經驗總結
Elasticsearch是一款基于Apache Lucene構建的開源全文檢索引擎,它能夠輕松地進行大規模的橫向擴展,以支撐PB級的結構化和非結構化海量數據的處理。而關系型數據庫比較擅長對數據的管理,但對全文檢索功能的支持相對不足,所以有時候一些實際項目需要將關系型數據庫中的數據同步到Elasticsearch中,以提供更加強大的全文檢索功能。另外,一些基于關系型數據庫的歷史遺留系統的存在,當遇到全文檢索的新需求時,就更加需要將數據同步到Elasticsearch中。近日,在線銀行支付平臺GoCardless的軟件工程師Chris Sinjakli發表了一篇題為《將數據從PostgreSQL同步到Elasticsearch的經驗教訓》的博文。在文章中,他結合自己的實際經歷(GoCardless使用Elasticsearch增強搜索功能)總結了將數據從關系型數據庫PostgreSQL同步到Elasticsearch的經驗教訓。
Chris首先指出當需要把數據同時存儲到PostgreSQL和Elasticsearch兩個地方時,開發者需要深入考慮的一些問題,如當Elasticsearch處理有很大延遲時將會發生什么未知事情、如果更新時出現異常將會發生什么情況、怎么知道Elasticsearch正確處理了每次更新等。接下來Chris引出要解決以上問題必須做到異步的更新、達到最終一致性、進行索引重建。
關于如何做到異步更新,Chris指出GoCardless開發團隊構造了一個隊列用于數據的異步同步,且通過線程池來協助處理。這樣既可以單獨更新,也可以批量更新,并使用基于JSON格式的數據和利用Elasticsearch的API保證了響應時間和可預知性。
關于如何確保一致性,Chris指出Elasticsearch的更新API不具有線程安全性,尤其在高并發更新時。如果只是調用該更新API來索引更新數據的話,就有可能引起并發問題。不過,Elasticsearch提供了一個具有樂觀鎖的索引版本系統,通過該系統就可以做到安全的更新。但是當在更新索引的同時,用戶還是有可能搜索出臟數據。慶幸的是,Elasticsearch還提供了另一種處理索引版本的方案,該方案是由發起請求的外部程序來設置版本類型并提供版本號,這樣使得Elasticsearch總是保持同步的文檔具有最高版本號。 GoCardless開發團隊考慮到PostgreSQL的事務ID(64位整數)在保證事務情況下能夠實現自增,所以GoCardless開發團隊就使用PostgreSQL的事務ID作為版本號。這樣就可以實現每次同步到Elasticsearch的數據都是最合適的(盡管不是最新的),但最后仍會達到數據的一致性。
關于如何重建索引,Chris指出以上的異步方式仍然存在丟失更新的可能,如網絡分區下引起的問題。為了處理以上問題,GoCardless開發團隊采取周期地將最近寫入到PostgreSQL的記錄進行一次批量同步并使用Elasticsearch的Bulk API重新批量索引所同步數據的方案。該方案以較小的重復記錄為代價徹底解決了更新丟失的問題,并且只需使用與原來同樣的代碼和在無需停止服務器的情況下即可實現索引重建。Chris還特別指出,如果想在無需停止服務器的情況實現重建索引,這就需要從一開始就正確地使用Elasticsearch的索引別名。
最后,Chris指出如果要構建更加良好的搜索體驗,還有很多工作需要做,尤其是不同的應用程序有著不同的約束條件,所以他建議開發者在開始編寫產品代碼前就要深入思考相關問題及處理方案。
來自:http://www.infoq.com/cn/news/2015/01/postgresql-elasticsearch