寫在前面
在當今網際網路行業,尤其是現在分散式、微服務開發環境下,為了提高搜尋效率,以及搜尋的精準度,會大量使用Redis、Memcached等NoSQL資料庫,也會使用大量的Solr、Elasticsearch等全文檢索服務。那麼,這個時候,就會有一個問題需要我們來思考和解決:那就是資料同步的問題!如何將實時變化的資料庫中的資料同步到Redis/Memcached或者Solr/Elasticsearch中呢?
網際網路背景下的資料同步需求
在當今網際網路行業,尤其是現在分散式、微服務開發環境下,為了提高搜尋效率,以及搜尋的精準度,會大量使用Redis、Memcached等NoSQL資料庫,也會使用大量的Solr、Elasticsearch等全文檢索服務。那麼,這個時候,就會有一個問題需要我們來思考和解決:那就是資料同步的問題!如何將實時變化的資料庫中的資料同步到Redis/Memcached或者Solr/Elasticsearch中呢?
例如,我們在分散式環境下向資料庫中不斷的寫入資料,而我們讀資料可能需要從Redis、Memcached或者Elasticsearch、Solr等服務中讀取。那麼,資料庫與各個服務中資料的實時同步問題,成為了我們亟待解決的問題。
試想,由於業務需要,我們引入了Redis、Memcached或者Elasticsearch、Solr等服務。使得我們的應用程式可能會從不同的服務中讀取資料,如下圖所示。
本質上講,無論我們引入了何種服務或者中介軟體,資料最終都是從我們的MySQL資料庫中讀取出來的。那麼,問題來了,如何將MySQL中的資料實時同步到其他的服務或者中介軟體呢?
注意:為了更好的說明問題,後面的內容以MySQL資料庫中的資料同步到Solr索引庫為例進行說明。
資料同步解決方案
1.在業務程式碼中同步
在增加、修改、刪除之後,執行操作Solr索引庫的邏輯程式碼。例如下面的程式碼片段。
public ResponseResult updateStatus(Long[] ids, String status){
try{
goodsService.updateStatus(ids, status);
if("status_success".equals(status)){
List<TbItem> itemList = goodsService.getItemList(ids, status);
itemSearchService.importList(itemList);
return new ResponseResult(true, "修改狀態成功")
}
}catch(Exception e){
return new ResponseResult(false, "修改狀態失敗");
}
}
優點:
操作簡便。
缺點:
業務耦合度高。
執行效率變低。
2.定時任務同步
在資料庫中執行完增加、修改、刪除操作後,通過定時任務定時的將資料庫的資料同步到Solr索引庫中。
定時任務技術有:SpringTask,Quartz。
哈哈,還有我開源的mykit-delay框架,開源地址為:https://github.com/sunshinelyz/mykit-delay。
這裡執行定時任務時,需要注意的一個技巧是:第一次執行定時任務時,從MySQL資料庫中以時間欄位進行倒序排列查詢相應的資料,並記錄當前查詢資料的時間欄位的最大值,以後每次執行定時任務查詢資料的時候,只要按時間欄位倒序查詢資料表中的時間欄位大於上次記錄的時間值的資料,並且記錄本次任務查詢出的時間欄位的最大值即可,從而不需要再次查詢資料表中的所有資料。
注意:這裡所說的時間欄位指的是標識資料更新的時間欄位,也就是說,使用定時任務同步資料時,為了避免每次執行任務都會進行全表掃描,最好是在資料表中增加一個更新記錄的時間欄位。
優點:
同步Solr索引庫的操作與業務程式碼完全解耦。
缺點:
資料的實時性並不高。
3.通過MQ實現同步
在資料庫中執行完增加、修改、刪除操作後,向MQ中傳送一條訊息,此時,同步程式作為MQ中的消費者,從訊息佇列中獲取訊息,然後執行同步Solr索引庫的邏輯。
我們可以使用下圖來簡單的標識通過MQ實現資料同步的過程。
我們可以使用如下程式碼實現這個過程。
public ResponseResult updateStatus(Long[] ids, String status){
try{
goodsService.updateStatus(ids, status);
if("status_success".equals(status)){
List<TbItem> itemList = goodsService.getItemList(ids, status);
final String jsonString = JSON.toJSONString(itemList);
jmsTemplate.send(queueSolr, new MessageCreator(){
@Override
public Message createMessage(Session session) throws JMSException{
return session.createTextMessage(jsonString);
}
});
}
return new ResponseResult(true, "修改狀態成功");
}catch(Exception e){
return new ResponseResult(false, "修改狀態失敗");
}
}
優點:
業務程式碼解耦,並且能夠做到準實時。
缺點:
需要在業務程式碼中加入傳送訊息到MQ的程式碼,資料呼叫介面耦合。
4.通過Canal實現實時同步
Canal是阿里巴巴開源的一款資料庫日誌增量解析元件,通過Canal來解析資料庫的日誌資訊,來檢測資料庫中表結構和資料的變化,從而更新Solr索引庫。
使用Canal可以做到業務程式碼完全解耦,API完全解耦,可以做到準實時。
Canal開源地址:https://github.com/alibaba/canal。
重磅福利
關注「 冰河技術 」微信公眾號,後臺回覆 “設計模式” 關鍵字領取《深入淺出Java 23種設計模式》PDF文件。回覆“Java8”關鍵字領取《Java8新特性教程》PDF文件。回覆“限流”關鍵字獲取《億級流量下的分散式限流解決方案》PDF文件,三本PDF均是由冰河原創並整理的超硬核教程,面試必備!!
好了,今天就聊到這兒吧!別忘了點個贊,給個在看和轉發,讓更多的人看到,一起學習,一起進步!!
寫在最後
如果你覺得冰河寫的還不錯,請微信搜尋並關注「 冰河技術 」微信公眾號,跟冰河學習高併發、分散式、微服務、大資料、網際網路和雲原生技術,「 冰河技術 」微信公眾號更新了大量技術專題,每一篇技術文章乾貨滿滿!不少讀者已經通過閱讀「 冰河技術 」微信公眾號文章,吊打面試官,成功跳槽到大廠;也有不少讀者實現了技術上的飛躍,成為公司的技術骨幹!如果你也想像他們一樣提升自己的能力,實現技術能力的飛躍,進大廠,升職加薪,那就關注「 冰河技術 」微信公眾號吧,每天更新超硬核技術乾貨,讓你對如何提升技術能力不再迷茫!