當業務量上升后,由於mysql對全文檢索或模糊查詢支持的能力不強,在系統中查詢的地方,往往會出現慢sql等,拖累系統其他模塊,造成性能低下。
隨着ES使用普及率的升高,ES是mysql的一個有效補充。我們可以將數據發送到搜索引擎(如ES)上,由搜索引擎來提供專業的服務。
接下來,就結合工作中實際用到的場景,對數據從mysql到es的同步進行一些分析。
在實踐中我總結出了以下幾種方式。
第1種:同步雙寫
這是一種最為簡單的方式,在將數據寫到mysql時,同時將數據寫到ES,實現數據的雙寫。
優點:
業務邏輯簡單。
缺點:
硬編碼:有需要寫入mysql的地方都需要添加寫入ES的代碼;業務強耦合;存在雙寫失敗丟數據風險;性能較差:本來mysql的性能就不是很高,再加寫一個ES,系統的性能必然會下降。說明:
上面第3點講到的雙寫失敗風險,包括以下3種:
ES系統不可用;應用系統和ES之間的網絡故障;應用系統重啟,導致系統來不及寫入ES等。針對這種情況,有數據強一致性要求的,就必須雙寫放到事物中來處理,但是一旦用上事物,則性能下降更加明顯。
第2種:異步雙寫(MQ方式)
針對第一種同步雙寫的性能和數據丟失問題,可以考慮引入MQ,從而形成了異步雙寫的方案,如下圖所示:
由於MQ的性能基本比mysql高出一個數量級,所以性能可以得到顯著的提高。
優點:
性能高;不存在丟數據問題。缺點:
硬編碼問題:依然存在業務強耦合:依然存在復雜度增加:系統中增加了mq的代碼,;可能存在時延問題:程序的寫入性能提高了,但是由於MQ的消費可能由於網絡或其它原因導致用戶寫入的數據不一定可以馬上看到,造成延時。第3種:異步雙寫(Worker方式)
上面兩種方案中都存在硬編碼問題,也就是有任何對mysq進行增刪改查的地方要么植入ES代碼,要么替換為MQ代碼,代碼的侵入性太強。
如果對實時性要求不高的情況下,可以考慮用定時器來處理,具體步驟如下:
數據庫的相關表中增加一個字段為timestamp的字段,任何crud操作都會導致該字段的時間發生變化;原來程序中的CURD操作不做任何變化;增加一個定時器程序(京東內部叫Worker),讓該程序按一定的時間周期掃描指定的表,把該時間段內發生變化的數據提取出來;逐條寫入到ES中。入下圖所示
優點:
不改變原來代碼,沒有侵入性、沒有硬編碼;沒有業務強耦合;不改變原來程序的性能;Worker代碼編寫簡單不需要考慮增刪改查。缺點:
時效性較差,由於定時器工作周期不可能設在秒級,所以實時性沒有上面2中好;對數據庫有一定的輪詢壓力,一種改進方法是將輪詢放到壓力不大的重庫上。第4種:Binlog 同步方式:
上面三種方案要么有代碼侵入,要么有硬編碼,要么有時延,第4中方案,可以利用mysql的binlog來進行同步
具體步驟如下:
1) 讀取mysql的binlog日志,獲取指定表的日志信息;
2) 將讀取的信息轉為MQ;
3) 編寫一個MQ消費程序;
4) 不斷消費MQ,每消費完一條消息,將消息寫入到ES中。
優點:
沒有代碼侵入、沒有硬編碼;原有系統不需要任何變化,沒有感知;性能高;業務解耦,不需要關注原來系統的業務邏輯。缺點:
構建Binlog系統復雜;也像方案二,存在MQ延時的風險