技術選型:spring-boot + elasticsearch + canal
GitHub地址:https://github.com/HappyWjl/es-home.git
如果該項目對您有幫助,您可以點右上角 “Star” 支持一下 謝謝!
或者您可以 “follow” 一下,該項目將持續更新,不斷完善功能。
轉載還請註明出處,謝謝了
博主QQ:820155406
一、準備工作:
-
IDEA: 略
-
JDK1.8: 略
-
mysql數據庫: 略
安裝完mysql數據庫後,把bin_log設置打開,如果不確定是否已經打開,可執行 show variables like ‘log_bin%’;
如果顯示如下,那說明已經開啓bin_log日誌,如果沒有,如果想使用canal進行數據同步,自行百度開啓bin_log
接下來,新建數據庫:db_search 並運行準備好的sql文件 db_search.sql (項目源碼中包含這個sql文件,可自行下載)
執行完sql後,數據庫中數據應該是這樣的:
-
elasticsearch安裝:https://blog.csdn.net/u012888052/article/details/79710429
-
elasticsearch-head插件安裝 :https://blog.csdn.net/u012888052/article/details/79710429
-
elasticsearch分詞器插件安裝 :https://blog.csdn.net/u012888052/article/details/81941912
如果不需要進行字段的分詞查詢,可不安裝分詞器,但是絕大多數業務場景,都是需要分詞查詢的,並且目前Demo中有分詞代碼,建議安裝。
- canal服務端安裝,官方下載地址:https://github.com/alibaba/canal/releases
-
附:canal Api地址:https://www.bookstack.cn/read/canal/1.md
-
canal 官方GitHub:https://github.com/alibaba/canal
打開鏈接,下載第一個壓縮包,然後解壓,解壓後應該是這個樣子的:
bin爲啓動文件夾
conf爲配置文件夾
lib爲相關jar包文件夾
logs爲日誌文件夾
前面我們已經安裝好Mysql數據庫,並且已經建好了一個測試數據庫,那麼我們接下來進行 Mysql + canal 服務端的配置
打開canal的conf文件夾,在裏面新建 articlesubscibe 文件夾,再在 articlesubscibe 文件夾中,複製conf文件夾下example中的instance.properties 文件並修改配置,如下圖(配置是我本機的配置,可根據實際需要改成自己的):
接下來,找到 canal.properties 配置文件進行編輯,找到 canal.destinations 配置參數,進行文件夾掃描配置,如下圖:
文件夾名稱可自行定義,與上一步新建的文件夾名稱相同即可。然後將conf文件夾下自帶的 example 文件夾刪除,爲什麼要刪除呢?因爲實際開發中需要同步的數據庫、數據表是很多的,自帶的文件夾是個案例,用於第一次配置時copy,後面我們應該根據實際需要,新建多個文件夾,區分不同的業務監聽,便於後續維護。
至此,conf文件夾應該是這個樣子:
-
git安裝(用於代碼管理,主要是爲下一步下載Demo做準備):略
-
項目源程序Demo(已經是最精簡的例子了,單表同步,單表查詢)GitHub地址(喜歡的朋友幫忙點個star):https://github.com/HappyWjl/es-home.git
以上,就是項目的準備工作,接下來就着重講解項目結構,以及數據是如何同步、如何查詢的乾貨。
二、項目結構:
-
具體描述項目前,我經常想到大象裝冰箱的步驟:
-
打開冰箱門、將大象放進去、關上冰箱門
-
現在做這個項目,也分爲三個步驟:
-
同步實時數據(data-dump)、同步歷史數據(data-migration)、按條件查詢es數據(data-search)
-
同步實時數據:
當數據庫中 新增/刪除/更新 一條數據時,需要實時同步到es
注意!這裏進行實時同步時,需要避免監聽表的批量修改數據,不然會造成數據積壓,一時間同步不過來。
如果必須要批量修改Mysql表數據時,應先把canal服務端停掉 -
同步歷史數據:
當數據庫中已經有舊的數據,且數據量很多,es中沒有時,需要將歷史數據批量灌入到es
如果沒有歷史數據,需要同步到es,就不需要這一步了 -
按條件查詢es數據:
前兩步能夠保證es中的數據完整性,只能算前提條件,這一步是最出活的,做完這一步,能夠查詢出想要的,就算完成
利用git下載完項目後,就可以進行項目部署了,將項目導入到IDEA中,可以看到es-home主項目,下圖是項目主要結構:
項目採用的相關技術:spring-boot、mybatis、maven、elasticsearch、canal
具體可查看詳細腦圖:
data-dump模塊:
-
這個項目主要的功能是實時同步數據,其中包含了canal客戶端代碼,用於接收canal服務端傳來的數據庫數據
-
首先啓動 DataDumpApplication.java ,可以看到啓動文件會加載數據源、掃描spring下的配置文件、指定啓動順序(@Order註解)、執行run方法,建立es鏈接
-
在啓動完後,ElasticsearchEnvInitRunner.java文件會接下來運行,因爲實現了CommandLineRunner,並且有@Order(2)註解
這裏會進行索引檢查,如果es中沒有代碼中的索引,會新建一個索引名稱
-
在新建索引過程中,可以對新建的索引進行設置,例如:設置字段分詞、設置字段經緯度,用於距離排序
-
接下來,CanalClientRunner.java文件會繼續執行,因爲實現了CommandLineRunner
這個文件會和canal服務端建立鏈接
注:在使用SpringBoot構建項目時,我們通常有一些預先數據的加載。那麼SpringBoot提供了一個簡單的方式來實現–CommandLineRunner。
CommandLineRunner是一個接口,我們需要時,只需實現該接口就行。如果存在多個加載的數據,我們也可以使用@Order註解來排序。
-
當canal服務端接收到mysql傳過來的bin_log日誌,會通過和客戶端的鏈接,傳到客戶端 AbstractCanalCoreManager.java 類,客戶端可根據設置批量讀取傳過來的數據,取決於業務數據的變動速度,以及canal客戶端同步到es中的消費速度
-
消費過程中,由於真正企業中的數據量變動比較大,所以採用多線程的方式去消費數據
-
接下來,通過 entry.getEntryType() 可進行數據庫事物判斷,並分別對數據進行處理,再通過多線程依次處理這些數據
-
分別判斷每條數據是 增/刪/改 哪種類型,分別進行處理。當是刪除時,進行es刪除操作;當是 增/改 時,進行es增改操作
-
在向es中修改數據前,調用了analysisColumn(rowData.getBeforeColumnsList()); 方法,這是對數據庫特殊字段的處理,因爲es接收數據的類型和Mysql不完全一致,所以需要將特殊字段處理下,目前已知的特殊字段有:timestamp、datetime、date、time、blob 真的是萬惡的時間,費我青春,害我敲碼!
注:時間類型存儲到es中會自動有時區轉換,例如傳入時間是2018-08-21 18:00:00 es中會存儲成 2018-08-21 10:00:00 中間會差8小時,所以需要在查詢數據時,進行時間差的轉換
-
刪除操作,調用的是封裝的刪除方法
-
getDateMap()方法,是在對es進行操作的最後一步之前,可對特殊數據進行處理,根據實際的需求來,簡單的需求或者優質的表結構,不需要這一步,經過封裝好的es新增/更新方法,就可以到es了
-
新增/修改操作,調用的是封裝的方法
data-migration模塊:
-
這個項目主要的功能是同步歷史數據,當數據庫中已經有舊的數據,且數據量很多,es中沒有時,需要將歷史數據批量灌入到es。如果沒有歷史數據,需要同步到es,就不需要這一步了
-
這個項目和data-dump項目有相當一部分相同的代碼,下面講到的話就簡單略過
-
首先啓動 DataMigrationApplication.java ,可以看到啓動文件會掃描spring下的配置文件
-
spring下的配置文件被掃描,mybatis相關配置也會被加載,此處省略,這裏不是重點。。。
-
在啓動完後,ElasticSearchInitRunner.java文件會接下來運行,因爲實現了CommandLineRunner
這裏會進行es連接池檢查 -
在啓動完後,可以看到項目啓動端口爲:8082
-
接下來在瀏覽器中請求url:http://localhost:8082/api/article/checkindex
可以進行索引檢查,如果沒有這個索引,會新建索引,這裏同上面data-dump一樣,索引可以設置分詞等屬性 -
然後請求url:http://localhost:8082/api/article/articletoes
就可以進行數據批量同步,接下來我簡單講下歷史數據批量同步的步驟 -
請求接口經過網絡中的層層傳遞,一直訪問到ArticleController.java
-
然後通過 articleSyncToEsManager.syncDataControl(); 同步數據到ES主控方法
這個方法,首先通過mybatis批量查詢出要同步錶的歷史數據,再進行循環,逐條處理數據
-
當看到 getDateMap()時,如果上面data-dump模塊的結構看的夠仔細,那就能接上了,後面是完全一樣的數據處理,接下來的介紹省略~可以參考上面寫到的getDateMap()續讀
data-search模塊:
-
這個模塊是進行數據的查詢,在做這一步前,請確保es中已經有相關數據,不然程序寫對了,也查不出來的,這時es應該可以看到初始數據如下圖:
-
首先啓動 DataSearchApplication.java ,可以看到啓動文件會掃描spring下的配置文件
-
在啓動完後,可以看到項目啓動端口爲:8083
-
接下來在postman中請求url(也可以用其他接口請求工具,注意是post請求):http://localhost:8083/api/article/getArticleList
-
可以看到請求返回結果已經查詢到了結果
-
請求接口經過網絡中的層層傳遞,一直訪問到ArticleController.java
-
再經過service實現層,進行es查詢,由於es查詢後返回結果被封裝成String,所以還需要轉成Object才方便處理數據,再返回
-
由於這個模塊主要實現的是查詢功能,那麼具體的查詢需要仔細講一下了,serviceImpl進行查詢時,調用了 articleSearchManager.queryArticleList(queryArticleSearchVO);
-
進行查詢時,首先通過 elasticSearchInitClientManager.getElasticClient(); 獲取es連接
-
再設置索引、設置查詢文章類型、組裝查詢條件
-
查詢出來時,是es的數據類型 SearchResponse ,然後通過方法轉換成了Map
-
但是這裏有一點需要注意,存數據到es中時,時間類型是有轉換的,現在是查詢出來,es中存儲的經轉換的類型是字符串,需要轉換成Data類型,並且可以留意下有沒有時差,之前提到過的時差如果出現了,這裏也可以進行數據修正
-
再經過最後數據的組裝,轉成通用型的JSON字符串,返回
-
組裝邏輯應該根據實際情況封裝
暫時寫到這裏吧,項目整體就是這個樣子,實際使用中會比這個業務場景更復雜,這個Demo還是比較接近實際應用場景的,當然很多高級用法我沒有加在裏面,Demo複雜了就更難上手es了。
關於更多的查詢業務,可自行探索,我也在慢慢探索中,加油。
有什麼問題可以加QQ問,或者留言,看到就回。
作者:Happy王子樂
QQ:820155406