吐血總結了各個中間件是如何實現持久化的
文轉載自微信公眾號「Java3y」,作者Java3y。轉載本文請聯系Java3y公眾號。
到目前為止,三歪也已經接觸到了不少的中間件了,比如說「Elasticsearch」「Redis」「HDFS」「Kafka」「HBase」等等。
可以發現的是,它們的持久化機制都差不得太多。今天想來總結一下,一方面想來回顧一下這些組件,一方面給還沒入門過這些中間件的同學總結一下持久化的”套路“,后面再去學習的時候就會輕松很多。
這些中間件我的GitHub目錄都是在的:
- https://github.com/ZhongFuCheng3y/3y
- https://gitee.com/zhongfucheng/Java3y
持久化
下面我們就直接來分別回顧一下各個中間件/組件的持久化機制,最后再總結就好了(三歪相信大家應該也能從回顧中看出些端倪)
為什么要持久化?原因也很簡單:數據需要存儲下來,不希望出了問題導致數據丟失
Elasticsearch
Elasticsearch是一個全文搜索引擎,對模糊搜索非常擅長。
Elasticsearch在寫數據的時候,會先寫到內存緩存區,然后寫到translog緩存區,每隔5s將translog緩沖區的數據刷到磁盤中
Kafka
眾所周知,Kafka是一個高吞吐量的消息隊列,那它是怎么持久化的呢?
Kafka relies heavily on the filesystem for storing and caching messages.
沒錯Kafka用的是文件系統來存儲的。
在Kafka官網上其實也說了,Kafka的持久化依賴操作系統的pagecache和順序寫來實現的。
HDFS
HDFS是分布式文件系統,能存儲海量的數據,那HDFS在寫入數據的時候是怎么樣的呢?
HDFS Client客戶端無論讀寫都需要走到NameNode去獲取/增刪改文件的元數據,而NameNode則是專門維護這些元數據的地方。
所以,在HDFS寫數據,需要先去NameNode上詢問這些切分好的block往哪幾個DataNode上寫數據。
為了提高NameNode的效率,在寫數據的時候,NameNode實際上是操作的是內存,然后涉及到增刪改的數據順序寫到editlog日志文件上
Redis
Redis是基于內存的,如果不想辦法將數據保存在硬盤上,一旦Redis重啟(退出/故障),內存的數據將會全部丟失。
我們肯定不想Redis里頭的數據由于某些故障全部丟失(導致所有請求都走MySQL),即便發生了故障也希望可以將Redis原有的數據恢復過來,所以Redis有RDB和AOF的持久化機制。
- RDB:基于快照,將某一時刻的所有數據保存到一個RDB文件中。
- AOF(append-only-file),當Redis服務器執行寫命令的時候,將執行的寫命令保存到AOF文件中。
AOF持久化功能的實現可以分為3個步驟:
- 命令追加:命令寫入aof_buf緩沖區
- 文件寫入:調用flushAppendOnlyFile函數,考慮是否要將aof_buf緩沖區寫入AOF文件中
- 文件同步:考慮是否將內存緩沖區的數據真正寫入到硬盤
HBase
HBase是一個能存儲海量數據的數據庫。
HBase在寫數據的時候,會先寫到Mem Store,當MemStore超過一定閾值,就會將內存中的數據刷寫到硬盤上,形成StoreFile,而StoreFile底層是以HFile的格式保存,HFile是HBase中KeyValue數據的存儲格式。
我們寫數據的時候是先寫到內存的,為了防止機器宕機,內存的數據沒刷到磁盤中就掛了。我們在寫Mem store的時候還會寫一份HLog
MySQL
MySQL我們用得最多的InnoDB引擎是怎么存儲的呢?它有redo log來支撐持久化的功能。
MySQL引入了redo log,內存寫完了,然后會寫一份redo log,這份redo log記載著這次在某個頁上做了什么修改。
總結看完上面常見的中間件/組件的持久化方式,應該就不用我多說了吧?思想幾乎都是一樣的,只是他們記錄“log”的名字不一樣而已。
先寫buffer,然后順序IO寫Log。防止buffer的數據還沒刷到磁盤,宕機導致數據丟失。
對于Log文件,中間件也不會放任它們一直膨脹,導致體積很大:
- 在Redis里邊,會對AOF文件進行重寫
- 在HDFS里邊,editlog會定時生成fsimage
- 在Elasticsearch里邊,translog會根據閾值觸發commit操作
- .....