為什麼要從MongoDB遷移到Elasticsearch?

本文涉及到 MongoDB 與 Elasticsearch 兩大陣營,可能會引起口水之爭,僅代表個人經驗之談,非陣營之說。

為什麼要從MongoDB遷移到Elasticsearch?

圖片來自 Pexels

我將圍繞如下兩個話題展開:

  • 為什麼要從 MongoDB 遷移到 Elasticsearch?
  • 如何從 MongoDB 遷移到 Elasticsearch?
為什麼要從MongoDB遷移到Elasticsearch?

MongoDB 與 Elasticsearch 熱度排名

現狀背景

MongoDB 本身定位與關係型數據庫競爭,但工作中幾乎沒有見到哪個項目會將核心業務系統的數據放在上面,依然選擇傳統的關係型數據庫。

項目背景

公司所在物流速運行業,業務系統複雜且龐大,用戶操作者很多,每日有大量業務數據產生,同時業務數據會有很多次流轉狀態變化。

為了便於記錄追蹤分析,系統操作日誌記錄項目應運而生,考慮到原有的日均數據量,操作日誌數據基於 MongoDB 存儲。

操作日誌記錄系統需要記錄兩種數據,如下說明:

①變更主數據,什麼人在什麼時間在系統哪個模塊做了什麼操作,數據編號是什麼,操作跟蹤編號是什麼。

<code>{ 
  "dataId": 1,  
  "traceId": "abc",         
  "moduleCode": "crm_01",            
  "operateTime": "2019-11-11 12:12:12",  
  "operationId": 100, 
  "operationName": "張三", 
  "departmentId": 1000, 
  "departmentName": "客戶部", 
  "operationContent": "拜訪客戶。。。" 
} /<code>

②變更從數據,實際變更數據的變化前後,此類數據條數很多,一行數據多個字段變更就記錄多條。

<code>[ 
  { 
    "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" 
  } 
] /<code>

項目架構

項目架構描述如下:

  • 業務系統新增或者編輯數據,產生操作日誌記錄發送到 Kafka 集群,基於 dataid 字段作為 key。
  • 新增或編輯數據實際存儲到 MySQL 數據庫。
  • Canal 集群訂閱 MySQL 集群,按照業務系統模塊配置監控的數據庫與表。
  • Canal 將監控到的變更業務數據發送到 Kafka 集群,基於 dataid 字段作為 key。
  • 操作日誌系統從 Kafka 獲取主記錄數據與從記錄數據。
  • 操作日誌系統寫入數據到 MongoDB,同時需要反查詢。
為什麼要從MongoDB遷移到Elasticsearch?

操作日誌記錄業務流程說明

MongoDB 架構

集群架構說明:

  • 服務器配置 8c/32gb/500gb ssd。
  • Router 路由服務器部署了 3 個節點。
  • Config 配置服務器部署了 3 個節點。
  • Shard 分片服務器部署了 9 個節點。
  • 主操作記錄設計 3 個分片。
  • 從操作記錄設計 3 個分片。
為什麼要從MongoDB遷移到Elasticsearch?

問題說明:MongoDB 的信徒們可能懷疑我們沒有使用好,或者我們的運維能力欠缺,或者認為我們有 Elasticsearch 的高手在。

不是這樣的,棄用 MongoDB 選擇 Elasticsearch 其實並非技術偏見問題,而是我們的實際場景需求,原因如下:

①搜索查詢

項目背景:

  • MongoDB 內部採用 B-Tree 作為索引結構,此索引基於最左優先原則,且必須保證查詢順序與索引字段的順序一致才有效,這個即是優點,但在現在複雜業務場景也是致命的。
  • 業務系統查詢操作日誌記錄會有很多過濾條件,且查詢條件是任意組合的,現有 MongoDB 是不支持的,或者說所有關係型數據庫都不支持,如果要支持,得創建好多組合的 B+ 數索引,想法很不理智。
  • 同時主記錄與從記錄中有很多字符類的數據,這些數據查詢即要支持精確查詢,也要支持全文檢索,這幾個方面 MongoDB 功能很單一,性能也很糟糕,業務系統查詢時經常超時,反倒是 Elasticsearch 非常合適。

②技術棧成熟度

項目背景:

  • 分片與副本實現問題,MongoDB 集合數據在設計時是需要綁定到具體的機器實例的,哪些分片分佈在哪些節點上,哪些副本分佈在哪些節點上。

這些都需要在配置集群時就要綁定死,跟傳統的關係型數據庫做分庫分表本質上沒有什麼兩樣,其實現在很多數據產品的集群還是這種模式偏多,比如 Redis-cluster,ClickHouse 等。

而 Elasticsearch 的集群與分片和副本沒有直接的綁定關係,可以任意的平衡調整,且節點的性能配置也可以很容易差異化。

  • 操作日誌數據量增加很快,單日寫入超過千萬條,不用多久,運維人員就需要對服務器進行擴容,且相對 Elasticsearch 複雜很多。
  • MongoDB 單集合數據量超過 10 億條,此情況下即使簡單條件查詢性能也不理想,不如 Elasticsearch 倒排索引快。
  • 公司對於 ES 與 MongoDB 技術棧的經驗積累不同,Elasticsearch 在很多項目中運用,非常核心的項目也是大量運用。

對於其技術與運維經驗更豐富,而 MongoDB 如果除去核心業務場景,幾乎找不到合適的切入口,實際沒有人敢在核心項目中使用 MongoDB,這就很尷尬。

③文檔格式相同

MongoDB 與 Elasticsearch 都屬於文檔型數據庫,Bson 類同與 Json,_objectid與_id 原理一樣,所以主數據與從數據遷移到 Elasticsearch 平臺,數據模型幾乎無需變化。

遷移方案

異構數據系統遷移,主要圍繞這兩大塊內容展開:

  • 上層應用系統遷移,原來是針對 MongoDB 的語法規則,現在要修改為面向 Elasticsearch 語法規則。
  • 下層 MongoDB 數據遷移到 Elasticsearch。

①Elastic 容量評估

原有 MongoDB 集群採用了 15 臺服務器,其中 9 臺是數據服務器,遷移到 Elastic 集群需要多少臺服務器?

我們採取簡單推算辦法,如假設生產環境上某個 MongoDB 集合的數據有 10 億條數據,我們先在測試環境上從 MongoDB 到 ES 上同步 100 萬條數據。

假設這 100 萬條數據佔用磁盤 10G,那生產上環境上需要 1 個 T 磁盤空間,然後根據業務預期增加量擴展一定冗餘。

根據初步評估,Elastic 集群設置 3 臺服務器, 配置 8c/16g 內存/2T 機械磁盤。服務器數量一下從 15 臺縮減到 3 臺,且配置也降低不少。

②Elastic 索引規則

系統操作日誌是時序性數據,寫完整後基本上無需再次修改。

操作日誌記錄查詢主要是當月的居多,後續的歷史性數據查詢頻率很低,根據評估,核心數據索引按月創建生成,業務查詢時候必須帶上操作時間範圍,後端根據時間反推需要查詢哪些索引。

Elastic-Api 支持多索引匹配查詢,完美利用 Elastic 的特性解決跨多個月份的查詢合併。對於非核心數據索引,按年創建索引生成足以。

為什麼要從MongoDB遷移到Elasticsearch?

Elastic 操作日誌索引創建規則

③核心實現邏輯設計

Elasticsearch 不是關係型數據庫,不具備事務的機制。

操作日誌系統的數據來源都是 Kafka,消費數據是有順序機制的,有 2 種場景特別注意,如下:

  • 主數據先到操作日誌系統,從數據後到,從數據寫的時候先拼湊主數據記錄和 Binlog 字段數據。
  • 從數據先到操作日誌系統,主數據後到,主數據更新從索引的相關的索引字段。

Elasticsearch 索引數據更新是近實時的刷新機制,數據提交後不能馬上通過 Search-Api 查詢到,主記錄的數據如何更新到從記錄呢?而且業務部門不規範的使用,多條主記錄的 dataId 和 tracId 可能一樣。

由於主數據與從數據關聯字段是 dataId 和 traceId。如果主數據與從數據在同時達到操作日誌系統,基於 update_by_query 命令肯定失效不 準確,主從數據也可能是多對多的關聯關係,dataId 和 traceId 不能唯一決定一條記錄。

Elasticsearch 其實也是一個 NoSQL 數據庫,可以做 key-value 緩存。

這時新建一個 Elastic 索引作為中間緩存, 原則是主數據與從數據誰先到緩存誰,索引的 _id=(dataId+traceId)。

通過這個中間索引可以找到主數據記錄的 Id 或者從記錄 Id, 索引數據模型多如下,detailId 為從索引的 _id 的數組記錄。

<code>{ 
  "dataId": 1, 
  "traceId": "abc", 
  "moduleCode": "crm_01", 
  "operationId": 100, 
  "operationName": "張三", 
  "departmentId": 1000, 
  "departmentName": "客戶部", 
  "operationContent": "拜訪客戶", 
  "detailId": [ 
    1, 
    2, 
    3, 
    4, 
    5, 
    6 
  ] 
} /<code>

前面我們講過主記錄和從記錄都是一個 Kafka 的分區上,我們拉一批數據的時候,操作 ES 用的用到的核心 API:

<code>#批量獲取從索引的記錄 
_mget  
#批量插入 
bulk 
#批量刪除中間臨時索引 
_delete_by_query  /<code>

遷移過程

①數據遷移

選擇 DataX 作為數據同步工具由以下幾個因素:

  • 歷史型數據。操作日誌記錄數據屬於歷史性的數據,記錄產生之後幾乎無需二次修改,等同於離線數據。
  • 非持續性遷移。項目全部完工之後,原有的 MongoDB 集群會全部銷燬,不會有二次遷移需求。
  • 數據量問題。原有 MongoDB 操作日誌數據量有幾十億條,遷移過程不能太快也不能太慢,速度太快,MongoDB 集群會出現性能問題,速度太慢,項目週期太長,增加運維的成本與複雜度。否則可以選擇 Hadoop 作為中轉平臺的遷移。
  • DataX 源碼特定場景改造。如日期類型的轉換、索引主鍵 _id 的生成、索引主鍵 _id 映射,支持重複同步。
  • 多實例多線程並行。主數據同步部署多個實例,從數據同步也部署多個實例,單實例中配置多個 Channel。
為什麼要從MongoDB遷移到Elasticsearch?

DataX 同步數據示意圖

②遷移索引設置

臨時修改索引的一些設置,當數據同步完之後再修改回來,如下:

<code>"index.number_of_replicas": 0, 
 "index.refresh_interval": "30s", 
 "index.translog.flush_threshold_size": "1024M" 
 "index.translog.durability": "async", 
 "index.translog.sync_interval": "5s" /<code>

③應用遷移

操作日誌項目採用 Spring Boot 構建,增加了自定義配置項,如下:

<code>#應用寫入mongodb標識 
writeflag.mongodb: true 
#應用寫入elasticsearch標識 
writeflag.elasticsearch: true /<code>

項目改造說明:

  • 第一次上線的時候,先將 2 個寫入標識設置為 true,雙寫 MongoDB 和 ES。
  • 對於讀,提供 2 個不同接口,前端自由的切換。
  • 等數據遷移完,沒有差異的時候,重新更改 flag 的值。
為什麼要從MongoDB遷移到Elasticsearch?

應用平衡遷移

結語

①遷移效果

棄用 MongoDB 使用 ElasticSearch 作為存儲數據庫,服務器從原來的 15 臺 MongoDB,變成了 3 臺 ElasticSearch,每月為公司節約了一大筆費用。

同時查詢性能提高了 10 倍以上,而且更好的支持了各種查詢,得到了業務部門的使用者,運維團隊和領導的一致讚賞。

②經驗總結

整個項目前後歷經幾個月,多位同事參與,設計、研發,數據遷移、測試、數據驗證、壓測等各個環節。

技術方案不是一步到位,中間也踩了很多坑,最終上線了。ES 的技術優秀特點很多,靈活的使用,才能發揮最大的威力。

作者:李猛

簡介:Elastic-stack 產品深度用戶,ES 認證工程師,2012 年接觸 Elasticsearch,對 Elastic-Stack 開發、架構、運維等方面有深入體驗,實踐過多種 Elasticsearch 項目,最暴力的大數據分析應用,最複雜的業務系統應用;業餘為企業提供 Elastic-stack 諮詢培訓以及調優實施。

編輯:陶家龍

出處:轉載自微信公眾號 DBAplus 社群(ID:dbaplus)


分享到:


相關文章: