從MongoDB遷移到ES后,我們減少了80%的服務(wù)器
來(lái)自:DBAplus社群
作者介紹
李猛(ynuosoft),Elastic-stack產(chǎn)品深度用戶,ES認(rèn)證工程師,2012年接觸Elasticsearch,對(duì)Elastic-Stack開(kāi)發(fā)、架構(gòu)、運(yùn)維等方面有深入體驗(yàn),實(shí)踐過(guò)多種Elasticsearch項(xiàng)目,最暴力的大數(shù)據(jù)分析應(yīng)用,最復(fù)雜的業(yè)務(wù)系統(tǒng)應(yīng)用;業(yè)余為企業(yè)提供Elastic-stack咨詢培訓(xùn)以及調(diào)優(yōu)實(shí)施。
圖示:MongoDB與Elasticsearch熱度排名
本文內(nèi)容涉及到MongoDB與Elasticsearch兩大陣營(yíng),可能會(huì)引起口水之爭(zhēng),僅代表個(gè)人經(jīng)驗(yàn)之談,非陣營(yíng)之說(shuō),圍繞兩個(gè)話題展開(kāi):
為什么要從MongoDB遷移到Elasticsearch?
如何從MongoDB遷移到Elasticsearch?
MongoDB本身定位與關(guān)系型數(shù)據(jù)庫(kù)競(jìng)爭(zhēng),但工作中幾乎沒(méi)有見(jiàn)到哪個(gè)項(xiàng)目會(huì)將核心業(yè)務(wù)系統(tǒng)的數(shù)據(jù)放在上面,依然選擇傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)。
公司所在物流速運(yùn)行業(yè),業(yè)務(wù)系統(tǒng)復(fù)雜且龐大,用戶操作者很多,每日有大量業(yè)務(wù)數(shù)據(jù)產(chǎn)生,同時(shí)業(yè)務(wù)數(shù)據(jù)會(huì)有很多次流轉(zhuǎn)狀態(tài)變化,為了便于記錄追蹤分析,系統(tǒng)操作日志記錄項(xiàng)目應(yīng)運(yùn)而生,考慮到原有的日均數(shù)據(jù)量,操作日志數(shù)據(jù)基于MongoDB存儲(chǔ)。
操作日志記錄系統(tǒng)需要記錄兩種數(shù)據(jù),如下說(shuō)明:
1)變更主數(shù)據(jù),什么人在什么時(shí)間在系統(tǒng)哪個(gè)模塊做了什么操作,數(shù)據(jù)編號(hào)是什么,操作跟蹤編號(hào)是什么。
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": "張三",
"departmentId": 1000,
"departmentName": "客戶部",
"operationContent": "拜訪客戶。。。"
}
2)變更從數(shù)據(jù),實(shí)際變更數(shù)據(jù)的變化前后,此類(lèi)數(shù)據(jù)條數(shù)很多,一行數(shù)據(jù)多個(gè)字段變更就記錄多條。
[
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": "張三",
"departmentId": 1000,
"departmentName": "客戶部",
"operationContent": "拜訪客戶",
"beforeValue": "20",
"afterValue": "30",
"columnName": "customerType"
},
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": "張三",
"departmentId": 1000,
"departmentName": "客戶部",
"operationContent": "拜訪客戶",
"beforeValue": "2019-11-02",
"afterValue": "2019-11-10",
"columnName": "lastVisitDate"
}
]
項(xiàng)目架構(gòu)描述如下:
業(yè)務(wù)系統(tǒng)新增或者編輯數(shù)據(jù),產(chǎn)生操作日志記錄發(fā)送到Kafka集群,基于dataid字段作為key;
新增或編輯數(shù)據(jù)實(shí)際存儲(chǔ)到MySQL數(shù)據(jù)庫(kù);
canal集群訂閱MySQL集群,按照業(yè)務(wù)系統(tǒng)模塊配置監(jiān)控的數(shù)據(jù)庫(kù)與表;
canal將監(jiān)控到的變更業(yè)務(wù)數(shù)據(jù)發(fā)送到Kafka集群,基于dataid字段作為key;
操作日志系統(tǒng)從Kafka獲取主記錄數(shù)據(jù)與從記錄數(shù)據(jù);
操作日志系統(tǒng)寫(xiě)入數(shù)據(jù)到MongoDB,同時(shí)需要反查詢。
圖示:操作日志記錄業(yè)務(wù)流程說(shuō)明
集群架構(gòu)說(shuō)明:
服務(wù)器配置8c/32gb/500gb ssd;
Router路由服務(wù)器部署了3個(gè)節(jié)點(diǎn);
Config配置服務(wù)器部署了3個(gè)節(jié)點(diǎn);
Shard分片服務(wù)器部署了9個(gè)節(jié)點(diǎn);
主操作記錄設(shè)計(jì)3個(gè)分片;
從操作記錄設(shè)計(jì)3個(gè)分片。
MongoDB的信徒們可能懷疑我們沒(méi)有使用好,或者我們的運(yùn)維能力欠缺,或者認(rèn)為我們有Elasticsearch的高手在。不是這樣的,棄用MongoDB選擇Elasticsearch其實(shí)并非技術(shù)偏見(jiàn)問(wèn)題,而是我們的實(shí)際場(chǎng)景需求,原因如下:
MongoDB內(nèi)部采用B-Tree作為索引結(jié)構(gòu),此索引基于最左優(yōu)先原則,且必須保證查詢順序與索引字段的順序一致才有效,這個(gè)即是優(yōu)點(diǎn),但在現(xiàn)在復(fù)雜業(yè)務(wù)場(chǎng)景也是致命的;
業(yè)務(wù)系統(tǒng)查詢操作日志記錄會(huì)有很多過(guò)濾條件,且查詢條件是任意組合的,現(xiàn)有MongoDB是不支持的,或者說(shuō)所有關(guān)系型數(shù)據(jù)庫(kù)都不支持,如果要支持,得創(chuàng)建好多組合的B+數(shù)索引,想法很不理智,這個(gè)我們已經(jīng)在《DB與ES混合之應(yīng)用系統(tǒng)場(chǎng)景分析探討》文中探討過(guò),詳細(xì)可以閱讀;
同時(shí)主記錄與從記錄中有很多字符類(lèi)的數(shù)據(jù),這些數(shù)據(jù)查詢即要支持精確查詢,也要支持全文檢索,這幾個(gè)方面MongoDB功能很單一,性能也很糟糕,業(yè)務(wù)系統(tǒng)查詢時(shí)經(jīng)常超時(shí),反倒是Elasticsearch非常合適。
分片與副本實(shí)現(xiàn)問(wèn)題,MongoDB集合數(shù)據(jù)在設(shè)計(jì)時(shí)是需要綁定到具體的機(jī)器實(shí)例的,哪些分片分布在哪些節(jié)點(diǎn)上,哪些副本分布在哪些節(jié)點(diǎn)上,這些都需要在配置集群時(shí)就要綁定死,跟傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)做分庫(kù)分表本質(zhì)上沒(méi)有什么兩樣,其實(shí)現(xiàn)在很多數(shù)據(jù)產(chǎn)品的集群還是這種模式偏多,比如Redis-cluster,ClickHouse等。而Elasticsearc的集群與分片和副本沒(méi)有直接的綁定關(guān)系,可以任意的平衡調(diào)整,且節(jié)點(diǎn)的性能配置也可以很容易差異化;
操作日志數(shù)據(jù)量增加很快,單日寫(xiě)入超過(guò)千萬(wàn)條,不用多久,運(yùn)維人員就需要對(duì)服務(wù)器進(jìn)行擴(kuò)容,且相對(duì)Elasticsearch復(fù)雜很多;
MongoDB單集合數(shù)據(jù)量超過(guò)10億條,此情況下即使簡(jiǎn)單條件查詢性能也不理想,不如Elasticsearch倒排索引快;
公司對(duì)于ES與MongoDB技術(shù)棧的經(jīng)驗(yàn)積累不同,Elasticsearc在很多項(xiàng)目中運(yùn)用,非常核心的項(xiàng)目也是大量運(yùn)用,對(duì)于其技術(shù)與運(yùn)維經(jīng)驗(yàn)更豐富,而MongoDB如果除去核心業(yè)務(wù)場(chǎng)景,幾乎找不到合適的切入口,實(shí)際沒(méi)有人敢在核心項(xiàng)目中使用MongoDB,這就很尷尬。
MongoDB與Elasticsearch都屬于文檔型數(shù)據(jù)庫(kù) ,Bson類(lèi)同與Json,_objectid與_id原理一樣,所以主數(shù)據(jù)與從數(shù)據(jù)遷移到Elasticsearch平臺(tái),數(shù)據(jù)模型幾乎無(wú)需變化。
異構(gòu)數(shù)據(jù)系統(tǒng)遷移,主要圍繞這兩大塊內(nèi)容展開(kāi):
上層應(yīng)用系統(tǒng)遷移,原來(lái)是針對(duì)MongoDB的語(yǔ)法規(guī)則,現(xiàn)在要修改為面向Elasticsearch語(yǔ)法規(guī)則;
下層MongoDB數(shù)據(jù)遷移到Elasticsearch。
原有MongoDB集群采用了15臺(tái)服務(wù)器,其中9臺(tái)是數(shù)據(jù)服務(wù)器,遷移到Elastic集群需要多少臺(tái)服務(wù)器?我們采取簡(jiǎn)單推算辦法,如假設(shè)生產(chǎn)環(huán)境上某個(gè)MongoDB集合的數(shù)據(jù)有10億條數(shù)據(jù), 我們先在測(cè)試環(huán)境上從MongoDB到ES上同步100萬(wàn)條數(shù)據(jù),假設(shè)這100萬(wàn)條數(shù)據(jù)占用磁盤(pán)10G,那生產(chǎn)上環(huán)境上需要1個(gè)T磁盤(pán)空間,然后根據(jù)業(yè)務(wù)預(yù)期增加量擴(kuò)展一定冗余。根據(jù)初步評(píng)估,Elastic集群設(shè)置3臺(tái)服務(wù)器, 配置8c/16g內(nèi)存/2T機(jī)械磁盤(pán)。服務(wù)器數(shù)量一下從15臺(tái)縮減到3臺(tái),且配置也降低不少。
系統(tǒng)操作日志是時(shí)序性數(shù)據(jù),寫(xiě)完整后基本上無(wú)需再次修改。操作日志記錄查詢主要是當(dāng)月的居多,后續(xù)的歷史性數(shù)據(jù)查詢頻率很低,根據(jù)評(píng)估,核心數(shù)據(jù)索引按月創(chuàng)建生成, 業(yè)務(wù)查詢時(shí)候必須帶上操作時(shí)間范圍,后端根據(jù)時(shí)間反推需要查詢哪些索引,Elastic-Api支持多索引匹配查詢,完美利用Elastic的特性解決跨多個(gè)月份的查詢合并。對(duì)于非核心數(shù)據(jù)索引,按年創(chuàng)建索引生成足以。
圖示:Elastic操作日志索引創(chuàng)建規(guī)則
Elasticsearch不是關(guān)系型數(shù)據(jù)庫(kù),不具備事務(wù)的機(jī)制。操作日志系統(tǒng)的數(shù)據(jù)來(lái)源都是Kafka,消費(fèi)數(shù)據(jù)是有順序機(jī)制的,有2種場(chǎng)景特別注意,如下:
主數(shù)據(jù)先到操作日志系統(tǒng),從數(shù)據(jù)后到,從數(shù)據(jù)寫(xiě)的時(shí)候先拼湊主數(shù)據(jù)記錄和Binlog字段數(shù)據(jù);
從數(shù)據(jù)先到操作日志系統(tǒng),主數(shù)據(jù)后到,主數(shù)據(jù)更新從索引的相關(guān)的索引字段。
Elasticsearch索引數(shù)據(jù)更新是近實(shí)時(shí)的刷新機(jī)制,數(shù)據(jù)提交后不能馬上通過(guò)Search-Api查詢到,主記錄的數(shù)據(jù)如何更新到從記錄呢?而且業(yè)務(wù)部門(mén)不規(guī)范的使用,多條主記錄的dataId和tracId可能一樣。
由于主數(shù)據(jù)與從數(shù)據(jù)關(guān)聯(lián)字段是dataId和traceId。如果主數(shù)據(jù)與從數(shù)據(jù)在同時(shí)達(dá)到操作日志系統(tǒng),基于update_by_query 命令肯定失效不 準(zhǔn)確, 主從數(shù)據(jù)也可能是多對(duì)多的關(guān)聯(lián)關(guān)系,dataId 和traceId不能唯一決定一條記錄。
Elasticsearch其實(shí)也是一個(gè)NoSQL數(shù)據(jù)庫(kù), 可以做key-value緩存。這時(shí)新建一個(gè)Elastic索引作為中間緩存, 原則是主數(shù)據(jù)與從數(shù)據(jù)誰(shuí)先到緩存誰(shuí),索引的 _id=(dataId+traceId) , 通過(guò)這個(gè)中間索引可以找到主數(shù)據(jù)記錄的Id或者從記錄Id, 索引數(shù)據(jù)模型多如下,detailId為從索引的_id的數(shù)組記錄。
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operationId": 100,
"operationName": "張三",
"departmentId": 1000,
"departmentName": "客戶部",
"operationContent": "拜訪客戶",
"detailId": [
1,
2,
3,
4,
5,
6
]
}
前面我們講過(guò)主記錄和從記錄都是一個(gè)Kafka的分區(qū)上,我們拉一批數(shù)據(jù)的時(shí)候,操作ES用的用到的核心API:
#批量獲取從索引的記錄
_mget
#批量插入
bulk
#批量刪除中間臨時(shí)索引
_delete_by_query
選擇DataX作為數(shù)據(jù)同步工具由以下幾個(gè)因素:
歷史型數(shù)據(jù)。操作日志記錄數(shù)據(jù)屬于歷史性的數(shù)據(jù),記錄產(chǎn)生之后幾乎無(wú)需二次修改,等同于離線數(shù)據(jù);
非持續(xù)性遷移。項(xiàng)目全部完工之后,原有的MongoDB集群會(huì)全部銷(xiāo)毀,不會(huì)有二次遷移需求;
數(shù)據(jù)量問(wèn)題。原有MongoDB操作日志數(shù)據(jù)量有幾十億條,遷移過(guò)程不能太快也不能太慢,速度太快,MongoDB集群會(huì)出現(xiàn)性能問(wèn)題,速度太慢,項(xiàng)目周期太長(zhǎng),增加運(yùn)維的成本與復(fù)雜度。否則可以選擇Hadoop作為中轉(zhuǎn)平臺(tái)的遷移;
DataX源碼特定場(chǎng)景改造。如日期類(lèi)型的轉(zhuǎn)換、索引主鍵_id的生成、索引主鍵_id映射,支持重復(fù)同步;
多實(shí)例多線程并行。主數(shù)據(jù)同步部署多個(gè)實(shí)例,從數(shù)據(jù)同步也部署多個(gè)實(shí)例,單實(shí)例中配置多個(gè)Channel。
圖示:DataX同步數(shù)據(jù)示意圖
臨時(shí)修改索引的一些設(shè)置,當(dāng)數(shù)據(jù)同步完之后再修改回來(lái),如下:
"index.number_of_replicas": 0,
"index.refresh_interval": "30s",
"index.translog.flush_threshold_size": "1024M"
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
操作日志項(xiàng)目采用Springboot構(gòu)建,增加了自定義配置項(xiàng),如下:
#應(yīng)用寫(xiě)入mongodb標(biāo)識(shí)
writeflag.mongodb: true
#應(yīng)用寫(xiě)入elasticsearch標(biāo)識(shí)
writeflag.elasticsearch: true
項(xiàng)目改造說(shuō)明:
第一次上線的時(shí)候,先將2個(gè)寫(xiě)入標(biāo)識(shí)設(shè)置為true,雙寫(xiě)MongoDB和ES;
對(duì)于讀,提供2個(gè)不同接口,前端自由的切換;
等數(shù)據(jù)遷移完,沒(méi)有差異的時(shí)候,重新更改flag的值。
圖示:應(yīng)用平衡遷移
棄用MongoDB使用ElasticSearch作為存儲(chǔ)數(shù)據(jù)庫(kù),服務(wù)器從原來(lái)的15臺(tái)MongoDB,變成了3臺(tái)ElasticSearch,每月為公司節(jié)約了一大筆費(fèi)用。同時(shí)查詢性能提高了10倍以上,而且更好的支持了各種查詢,得到了業(yè)務(wù)部門(mén)的使用者,運(yùn)維團(tuán)隊(duì)和領(lǐng)導(dǎo)的一致贊賞。
整個(gè)項(xiàng)目前后歷經(jīng)幾個(gè)月,多位同事參與,設(shè)計(jì)、研發(fā),數(shù)據(jù)遷移、測(cè)試、數(shù)據(jù)驗(yàn)證、壓測(cè)等各個(gè)環(huán)節(jié)。技術(shù)方案不是一步到位,中間也踩了很多坑,最終上線了。ES的技術(shù)優(yōu)秀特點(diǎn)很多,靈活的使用,才能發(fā)揮最大的威力。
特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒(méi)關(guān)注的小伙伴,可以長(zhǎng)按關(guān)注一下:
長(zhǎng)按訂閱更多精彩▼
如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!