前言
我們一般會(huì)使用Mysql用來存儲(chǔ)數(shù)據(jù),用Es來做全文檢索和特殊查詢,用redis來做數(shù)據(jù)的緩存
那么如何將數(shù)據(jù)優(yōu)雅的從Mysql同步到Es以及redis呢?
一、數(shù)據(jù)同步方案
1.同步雙寫
這是一種最為簡單的方式,在將數(shù)據(jù)寫到mysql時(shí),同時(shí)將數(shù)據(jù)寫到ES或者redis。
這個(gè)方法的缺點(diǎn)是代碼嚴(yán)重耦合,需要手動(dòng)維護(hù)Mysql和Es數(shù)據(jù)關(guān)系,非常不便于維護(hù)。
偽代碼:
/**
* 新增商品
*/
@Transactional(rollbackFor = Exception.class)
public void addGoods(GoodsDto goodsDto) {
//1、保存Mysql
Goods goods = new Goods();
BeanUtils.copyProperties(goodsDto,goods);
goodsMapper.insert();
//2、保存ES
IndexRequest indexRequest = new IndexRequest("goods_index","_doc");
indexRequest.source(JSON.toJSONString(goods), XContentType.JSON);
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
highLevelClient.index(indexRequest);
}
- 優(yōu)點(diǎn):
1、業(yè)務(wù)邏輯簡單
2、實(shí)時(shí)性高 - 缺點(diǎn):
1、 硬編碼,有需要寫入mysql的地方都需要添加寫入ES的代碼;
2、 業(yè)務(wù)強(qiáng)耦合;
3、 存在雙寫失敗丟數(shù)據(jù)風(fēng)險(xiǎn);
4、 性能較差:本來mysql的性能不是很高,再加一個(gè)ES,系統(tǒng)的性能必然會(huì)下降。 - 雙寫失敗風(fēng)險(xiǎn),包括以下幾種:
1) ES系統(tǒng)不可用;
2) 程序和ES之間的網(wǎng)絡(luò)故障;
3) 程序重啟,導(dǎo)致系統(tǒng)來不及寫入ES等。
針對這種情況,有數(shù)據(jù)強(qiáng)一致性要求的,就必須雙寫放到事務(wù)中來處理,而一旦用上事物,則性能下降更加明顯。
2.異步雙寫(MQ方式)
針對多數(shù)據(jù)源寫入的場景,可以借助MQ實(shí)現(xiàn)異步的多源寫入,這種情況下各個(gè)源的寫入邏輯互不干擾,不會(huì)由于單個(gè)數(shù)據(jù)源寫入異?;蚓徛绊懫渌麛?shù)據(jù)源的寫入,雖然整體寫入的吞吐量增大了,但是由于MQ消費(fèi)是異步消費(fèi),所以不適合實(shí)時(shí)業(yè)務(wù)場景。
在執(zhí)行完向Mysql中寫入數(shù)據(jù)的邏輯后,發(fā)送MQ,告訴消費(fèi)端這個(gè)數(shù)據(jù)需要寫入Es,消費(fèi)端收到消息后執(zhí)行向Es寫入數(shù)據(jù)的邏輯。這個(gè)方式的優(yōu)點(diǎn)是Mysql和Es數(shù)據(jù)維護(hù)分離,開發(fā)Mysql和Es的人員只需要關(guān)心各自的業(yè)務(wù)。缺點(diǎn)是依然需要維護(hù)發(fā)送、接收MQ的邏輯,并且引入了MQ組件,增加了系統(tǒng)的復(fù)雜度。
偽代碼:
@Transactional(rollbackFor = Exception.class)
public boolean parseJdDb(String keyword) throws IOException {
//向數(shù)據(jù)庫中插入
List<JdGoods> jdGoods = htmlParseUtil.parseJd(keyword);
//批量更新Mysql
boolean b = this.saveBatch(jdGoods);
log.info("異步同步至ES");
rabbitTemplate.convertAndSend("es.exchange","es.renew.key", jdGoods);
return b;
}
優(yōu)點(diǎn):
1、性能高
2、不易出現(xiàn)數(shù)據(jù)丟失問題,主要基于MQ消息的消費(fèi)保障機(jī)制,比如ES宕機(jī)或者寫入失敗,還能重新消費(fèi)MQ消息。
3、多源寫入之間相互隔離,便于擴(kuò)展更多的數(shù)據(jù)源寫入
缺點(diǎn):
1、硬編碼問題,接入新的數(shù)據(jù)源需要實(shí)現(xiàn)新的消費(fèi)者代碼
3、系統(tǒng)復(fù)雜度增加:引入了消息中間件
4、可能出現(xiàn)延時(shí)問題:MQ是異步消費(fèi)模型,用戶寫入的數(shù)據(jù)不一定可以馬上看到,造成延時(shí)。
3.基于Mysql表定時(shí)掃描同步
上面兩種方案中都存在硬編碼問題,也就是有任何對mysq進(jìn)行增刪改查的地方要么植入ES代碼,要么替換為MQ代碼,代碼的侵入性太強(qiáng)。
如果對實(shí)時(shí)性要求不高的情況下,可以考慮用定時(shí)器來處理,具體步驟如下:
1、數(shù)據(jù)庫的相關(guān)表中增加一個(gè)字段為timestamp的字段,任何crud操作都會(huì)導(dǎo)致該字段的時(shí)間發(fā)生變化;
2、原來程序中的CURD操作不做任何變化;
3、增加一個(gè)定時(shí)器程序,讓該程序按一定的時(shí)間周期掃描指定的表,把該時(shí)間段內(nèi)發(fā)生變化的數(shù)據(jù)提取出來;
4、逐條寫入到ES中。
如下圖所示:
該方案的典型實(shí)現(xiàn)是借助logstash
實(shí)現(xiàn)數(shù)據(jù)同步,其底層實(shí)現(xiàn)原理就是根據(jù)配置定期使用sql查詢新增的數(shù)據(jù)寫入ES中,實(shí)現(xiàn)數(shù)據(jù)的增量同步。
具體實(shí)現(xiàn)可以參考:通過Logstash實(shí)現(xiàn)mysql數(shù)據(jù)定時(shí)增量同步到ES
優(yōu)點(diǎn):
1、不改變原來代碼,沒有侵入性、沒有硬編碼;
2、沒有業(yè)務(wù)強(qiáng)耦合,不改變原來程序的性能;
3、Worker代碼編寫簡單不需要考慮增刪改查;
缺點(diǎn):
1、時(shí)效性較差,由于是采用定時(shí)器根據(jù)固定頻率查詢表來同步數(shù)據(jù),盡管將同步周期設(shè)置到秒級,也還是會(huì)存在一定時(shí)間的延遲。
2、對數(shù)據(jù)庫有一定的輪詢壓力,一種改進(jìn)方法是將輪詢放到壓力不大的從庫上。
業(yè)界目前較為流行的方案:Canal實(shí)現(xiàn)Mysql數(shù)據(jù)同步至Redis、Elasticsearch
4.基于Binlog實(shí)時(shí)同步
上面三種方案要么有代碼侵入,要么有硬編碼,要么有延遲,那么有沒有一種方案既能保證數(shù)據(jù)同步的實(shí)時(shí)性又沒有代入侵入呢?
當(dāng)然有,可以利用mysql的binlog來進(jìn)行同步。其實(shí)現(xiàn)原理如下:
具體步驟如下:
1) 讀取mysql的binlog日志,獲取指定表的日志信息;
2) 將讀取的信息轉(zhuǎn)為MQ;
3) 編寫一個(gè)MQ消費(fèi)程序;
4) 不斷消費(fèi)MQ,每消費(fèi)完一條消息,將消息寫入到ES中。
優(yōu)點(diǎn):
1、沒有代碼侵入、沒有硬編碼;
2、原有系統(tǒng)不需要任何變化,沒有感知;
3、性能高;
4、業(yè)務(wù)解耦,不需要關(guān)注原來系統(tǒng)的業(yè)務(wù)邏輯。
缺點(diǎn):
1、構(gòu)建Binlog系統(tǒng)復(fù)雜;
2、如果采用MQ消費(fèi)解析的binlog信息,也會(huì)像方案二一樣存在MQ延時(shí)的風(fēng)險(xiǎn)。
二、數(shù)據(jù)遷移同步工具選型
數(shù)據(jù)遷移同步工具的選擇比較多樣,下表僅從 MySQL 同步 ES 這個(gè)場景下,對一些筆者深度使用研究過的數(shù)據(jù)同步工具進(jìn)行對比,用戶可以根據(jù)自己的實(shí)際需要選取適合自己的產(chǎn)品。文章來源:http://www.zghlxwxcb.cn/news/detail-774877.html
特性\產(chǎn)品 | Canal | DTS | CloudCanal |
---|---|---|---|
是否支持自建ES | 是 | 否 | 是 |
ES對端版本支持豐富度 | 中 支持ES6和ES7 | 高 支持ES5,ES6和ES7 | 中 支持ES6和ES7 |
嵌套類型支持 | join/nested/object | object | nested/object |
join支持方式 | 基于join父子文檔&反查 | 無 | 基于寬表預(yù)構(gòu)建&反查 |
是否支持結(jié)構(gòu)遷移 | 否 | 是 | 是 |
是否支持全量遷移 | 是 | 是 | 是 |
是否支持增量遷移 | 是 | 是 | 是 |
數(shù)據(jù)過濾能力 | 中 -僅全量可添加where條件 | 高 -全增量階段where條件 | 高 -全增量階段where條件 |
是否支持時(shí)區(qū)轉(zhuǎn)換 | 否 | 是 | 是 |
同步限流能力 | 無 | 有 | 有 |
任務(wù)編輯能力 | 無 | 有 | 無 |
數(shù)據(jù)源支持豐富度 | 中 | 高 | 中 |
架構(gòu)模式 | 訂閱消費(fèi)模式 需先寫入消息隊(duì)列 | 直連模式 | 直連模式 |
監(jiān)控指標(biāo)豐富度 | 中 性能指標(biāo)監(jiān)控 | 中 性能指標(biāo)監(jiān)控 | 高 性能指標(biāo)、資源指標(biāo)監(jiān)控 |
報(bào)警能力 | 無 | 針對延遲、異常的電話報(bào)警 | 針對延遲、異常的釘釘、短信、郵件報(bào)警 |
任務(wù)可視化創(chuàng)建&配置&管理能力 | 無 | 有 | 有 |
是否開源 | 是 | 否 | 否 |
是否免費(fèi) | 是 | 否 是社區(qū)版、 | SAAS版免費(fèi) |
是否支持獨(dú)立輸出 | 是 | 否依賴云平臺(tái)整體輸出 | 是 |
是否支持SAAS化使用 | 否 | 是 | 是 |
總結(jié)
本文主要對Mysql和ES進(jìn)行數(shù)據(jù)同步的常見方案進(jìn)行了匯總說明。文章來源地址http://www.zghlxwxcb.cn/news/detail-774877.html
- 同步雙寫是最簡單的同步方式,能最大程度保證數(shù)據(jù)同步寫入的實(shí)時(shí)性,最大的問題是代碼侵入性太強(qiáng)。
- 異步雙寫引入了消息中間件,由于MQ都是異步消費(fèi)模型,所以可能出現(xiàn)數(shù)據(jù)同步延遲的問題。好處是在大規(guī)模消息同步時(shí)吞吐量更、高性能更好,便于接入更多的數(shù)據(jù)源,且各個(gè)數(shù)據(jù)源數(shù)據(jù)消費(fèi)寫入相互隔離互不影響。
- 基于Mysql表定時(shí)掃描同步 ,原理是通過定時(shí)器定時(shí)掃描表中的增量數(shù)據(jù)進(jìn)行數(shù)據(jù)同步,不會(huì)產(chǎn)生代碼侵入,但由于是定時(shí)掃描同步,所以也會(huì)存在數(shù)據(jù)同步延遲問題,典型實(shí)現(xiàn)是采用 Logstash 實(shí)現(xiàn)增量同步。
- 基于Binlog實(shí)時(shí)同步 ,原理是通過監(jiān)聽Mysql的binlog日志進(jìn)行增量同步數(shù)據(jù)。不會(huì)產(chǎn)生代碼侵入,數(shù)據(jù)同步的實(shí)時(shí)也能得到保障,弊端是Binlog系統(tǒng)都較為復(fù)雜。典型實(shí)現(xiàn)是采用 canal 實(shí)現(xiàn)數(shù)據(jù)同步。
到了這里,關(guān)于Mysql和ES、Redis數(shù)據(jù)同步方案匯總的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!