摘要
之前寫過一篇ElasticSearch初識之吐槽,不知覺竟然過去了兩年了。哎,時光催人老啊。最近又用到了ES,想找找過去的總結文檔,居然只有一篇,搞了半年的ES,遇到那么多的問題,產出只有這么點,真是說不過去啊。只好又重新撿起ES,發現ES槽點依然很多,不兼容的更新太多了,各個版本之間的差異不小,感覺ES就是偏理論算法的人設計出來的,而不是工程學家寫的。非常像公司里面,算法工程師吐槽后端應用開發算法能力弱,后端應用開發吐槽算法工程師工程能力太差。作為一個應用開發對ES差不多就是這種感覺。不過要用到搜索,不用他又不行。既然不能拒絕,只能去享受了。
寫入分析
為什么要分析寫入了,因為好奇唄。比如有如下問題一直困惑着我
- 為什么es會丟數據
- 什么樣的節點可以是coordinate node
- refresh index和flush index是什么操作
- memory buffer,filesystem cache都存在什么地方。
- 集群中的節點如何配合寫入的
- 數據怎么存放的
- 為什么寫入到filesystem cache中就可以索引了
寫入概覽
首先我們從分布式集群的角度分析下寫入,采用系統默認的參數來說明
集群有三個節點,都存儲數據,indexA 有5個分片,2個復制集。
數據如下分布
Node1: shard1
Node2: shard2,shard3,shard1-R1(shard1的復制集)
Node3: shard4,shard5,shard-R2(shard1的復制集)
為了簡化問題,shard2,shard5等shard的復制集忽略問題了。
現在以寫入shard1為例說明問題。

- 首先客戶端根據配置的連接節點,通過輪詢方式連接到一個coordinate節點。
coordinate節點不是很master/client/data節點一個維度的描述,它就是指處理客戶端請求的節點。這個描述和cassandra的coordinate節點是一個概念。集群中所有的節點都可以是coordinate節點。
- coodinate節點通過hash算法計算出數據在shard1上
shard = hash(document_id) % (num_of_primary_shards),然后根據節點上維護的shard信息,將請求發送到node1上。 - node1 對索引數據進行校驗,然后寫入到shard中。具體細節見下一節
寫入到shard。 - 主節點數據寫入成功后,將數據並行發送到副本集節點Node2,Node3。
- Node2,Node3寫入數據成功后,發送ack信號給shard1主節點Node1。
- Node1發送ack給coordinate node
- coordinate node發送ack給客戶端。
整個過程coordinate node部分類似cassandra,主shard節點和副本集受master-slave模式影響,必須有master決定寫入成功與否,和mysql類似的。
寫入shard
上面第三步驟,shard內寫入還需要詳細分析下

- 數據寫入到內存buffer
- 同時寫入到數據到translog buffer
- 每隔1s數據從buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能通過索引查詢到了
- refresh完,memory buffer就清空了。
- 每隔5s中,translog 從buffer flush到磁盤中
- 定期/定量從FileSystemCache中,結合translog內容
flush index到磁盤中。做增量flush的。
各種數據庫的單節點寫入過程大同小異,一般都是寫內存,記錄操作日志(防止節點宕機,內存中的數據丟失)然后flush到磁盤,有個線程不斷的merge 數據塊。不過是寫入的數據格式不同。
另外分布式或者主從式部署結構,又需要將寫入的數據復制到不同的節點,這個過程比較復雜,每個數據庫處理也有不同的邏輯。
elastic search 寫入的中間過程還多了一層buffer,我們知道buffer和cache雖然都是為了提高寫入效率,但是工作原理不同,
1、Buffer(緩沖區)是系統兩端處理速度平衡(從長時間尺度上看)時使用的。它的引入是為了減小短期內突發I/O的影響,起到流量整形的作用。比如生產者——消費者問題,他們產生和消耗資源的速度大體接近,加一個buffer可以抵消掉資源剛產生/消耗時的突然變化。
2、Cache(緩存)則是系統兩端處理速度不匹配時的一種折衷策略。因為CPU和memory之間的速度差異越來越大,所以人們充分利用數據的局部性(locality)特征,通過使用存儲系統分級(memory hierarchy)的策略來減小這種差異帶來的影響。
所以寫入到buffer中的數據,還是原始數據,還沒有索引,搜索不到的。只有到Cache中還可以。
和MySQL,Cassandra,Mongo的寫入對比
數據庫寫入過程都需要寫入操作日志,復制集日志,不同的數據庫不一樣的處理方法。
有些數據庫是共用的,有些數據庫則是分開的。
寫操作日志的過程一般是直接寫入磁盤的,因為它本身就是防止進程,機器宕機造成內存數據丟失,而用來恢復數據的。寫入buffer中又會可能會導致數據的丟失。所以像elastic search mysql innodb這種操作日志寫buffer的也會提供配置項,來保證當事務成功后,操作日志會被刷盤的。不過es 的操作日志最小刷盤不能低於100ms.
下面是各個數據庫的日志對比,相同的功能,但是每個創建者都有自己的逼格,需要有不同的命名。
| 數據庫 | 記錄日志,刷磁盤 | 復制日志 | 備注 |
|---|---|---|---|
| cassandra | commit log | commit log | commit log 直接寫磁盤的 |
| mongo | journal | oplog | journal log寫磁盤的 |
| mysql | redo logs | bin log | redo logs寫buffer的, |
| elastic search | translog | translog | 寫buffer的 |
有興趣的同學可以之前寫過的mongo,cassandra寫入分析
關注公眾號【方丈的寺院】,第一時間收到文章的更新,與方丈一起開始技術修行之路

參考
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-translog.html
https://www.elastic.co/pdf/architecture-best-practices.pdf
https://lalitvc.files.wordpress.com/2018/05/mysql_architecture_guide.pdf
https://www.infoq.cn/article/analysis-of-elasticsearch-cluster-part01
https://blog.insightdatascience.com/anatomy-of-an-elasticsearch-cluster-part-i-7ac9a13b05db
