最近這段時間一直在研究消息隊列烤低、文件系統、數據庫等镶柱,慢慢的發(fā)現他們都有一個核心組件:日志.有時也叫write-ahead logs 摔癣、commit logs 或者事物 logs, 通常指在應用所有的修改之前先寫入日志,一般會將重放日志襟交、撤銷日志都寫進去迈倍。
我們經常聽到很多名詞,NoSQL數據庫、KV存儲捣域、Hadoop啼染、raft、paxos 以及版本控制等等焕梅,這些中間件或者協議本質上都或多或少依賴于日志迹鹅,可以發(fā)現日志一直都在分布式系統中扮演者非常重要的角色。
什么是日志?
日志就是按照時間順序追加的贞言、完全有序的記錄序列斜棚,其實就是一種特殊的文件格式,文件是一個字節(jié)數組该窗,而這里日志是一個記錄數據弟蚀,只是相對于文件來說,這里每條記錄都是按照時間的相對順序排列的酗失,可以說日志是最簡單的一種存儲模型义钉,讀取一般都是從左到右,例如消息隊列级零,一般是線性寫入log文件断医,消費者順序從offset開始讀取滞乙。
由于日志本身固有的特性,記錄從左向右開始順序插入鉴嗤,也就意味著左邊的記錄相較于右邊的記錄“更老”, 也就是說我們可以不用依賴于系統時鐘斩启,這個特性對于分布式系統來說相當重要。
如果你想學習Java工程化醉锅、高性能及分布式兔簇、高性能、深入淺出硬耍。性能調優(yōu)垄琐、Spring,MyBatis经柴,Netty源碼分析和大數據等知識點可以來找我狸窘。 而現在我就有一個平臺可以提供給你們學習,讓你在實踐中積累經驗掌握原理坯认。主要方向是JAVA架構師翻擒。如果你想拿高薪,想突破瓶頸牛哺,想跟別人競爭能取得優(yōu)勢的陋气,想進BAT但是有擔心面試不過的,可以加我的Java架構進階群:554355695?
注:加群要求 1引润、具有2-5工作經驗的巩趁,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加淳附。 2议慰、在公司待久了,過得很安逸燃观,但跳槽時面試碰壁褒脯。需要在短時間內進修、跳槽拿高薪的可以加缆毁。 3、如果沒有工作經驗到涂,但基礎非常扎實脊框,對java工作機制,常用設計思想践啄,常用java開發(fā)框架掌握熟練的浇雹,可以加。 4屿讽、覺得自己很牛B昭灵,一般需求都能搞定吠裆。但是所學的知識點沒有系統化,很難在技術領域繼續(xù)突破的可以加烂完。 5.阿里Java高級大牛直播講解知識點试疙,分享知識,多年工作經驗的梳理和總結抠蚣,帶著大家全面祝旷、科學地建立自己的技術體系和技術認知! 6.小號加群一律不給過嘶窄,謝謝
日志的應用
日志在數據庫中的應用
日志是什么時候出現已經無從得知怀跛,可能是概念上來講太簡單。在數據庫領域中日志更多的是用于在系統crash的時候同步數據以及索引等柄冲,例如MySQL中的redo log吻谋,redo log是一種基于磁盤的數據結構,用于在系統掛掉的時候保證數據的正確性现横、完整性漓拾,也叫預寫日志,例如在一個事物的執(zhí)行過程中长赞,首先會寫redo log晦攒,然后才會應用實際的更改,這樣當系統crash后恢復時就能夠根據redo log進行重放從而恢復數據(在初始化的過程中得哆,這個時候不會還沒有客戶端的連接)脯颜。日志也可以用于數據庫主從之間的同步,因為本質上贩据,數據庫所有的操作記錄都已經寫入到了日志中栋操,我們只要將日志同步到slave,并在slave重放就能夠實現主從同步饱亮,這里也可以實現很多其他需要的組件矾芙,我們可以通過訂閱redo log 從而拿到數據庫所有的變更,從而實現個性化的業(yè)務邏輯近上,例如審計剔宪、緩存同步等等。
日志在分布式系統中的應用
分布式系統服務本質上就是關于狀態(tài)的變更壹无,這里可以理解為狀態(tài)機葱绒,兩個獨立的進程(不依賴于外部環(huán)境,例如系統時鐘斗锭、外部接口等)給定一致的輸入將會產生一致的輸出并最終保持一致的狀態(tài)地淀,而日志由于其固有的順序性并不依賴系統時鐘,正好可以用來解決變更有序性的問題岖是。
我們利用這個特性實現解決分布式系統中遇到的很多問題帮毁。例如RocketMQ中的備節(jié)點实苞,主broker接收客戶端的請求,并記錄日志烈疚,然后實時同步到salve中黔牵,slave在本地重放,當master掛掉的時候胞得,slave可以繼續(xù)處理請求荧止,例如拒絕寫請求并繼續(xù)處理讀請求。日志中不僅僅可以記錄數據阶剑,也可以直接記錄操作跃巡,例如SQL語句。
日志是解決一致性問題的關鍵數據結構牧愁,日志就像是操作序列素邪,每一條記錄代表一條指令,例如應用廣泛的Paxos猪半、Raft協議兔朦,都是基于日志構建起來的一致性協議。
日志在Message Queue中的應用
日志可以很方便的用于處理數據之間的流入流出磨确,每一個數據源都可以產生自己的日志沽甥,這里數據源可以來自各個方面,例如某個事件流(頁面點擊乏奥、緩存刷新提醒摆舟、數據庫binlog變更),我們可以將日志集中存儲到一個集群中邓了,訂閱者可以根據offset來讀取日志的每條記錄恨诱,根據每條記錄中的數據、操作應用自己的變更骗炉。
這里的日志可以理解為消息隊列照宝,消息隊列可以起到異步解耦、限流的作用句葵。為什么說解耦呢厕鹃?因為對于消費者、生產者來說乍丈,兩個角色的職責都很清晰熊响,就負責生產消息、消費消息诗赌,而不用關心下游、上游是誰秸弛,不管是來數據庫的變更日志铭若、某個事件也好洪碳,對于某一方來說我根本不需要關心,我只需要關注自己感興趣的日志以及日志中的每條記錄叼屠。
我們知道數據庫的QPS是一定的瞳腌,而上層應用一般可以橫向擴容,這個時候如果到了雙11這種請求突然的場景镜雨,數據庫會吃不消嫂侍,那么我們就可以引入消息隊列,將每個隊數據庫的操作寫到日志中荚坞,由另外一個應用專門負責消費這些日志記錄并應用到數據庫中挑宠,而且就算數據庫掛了,當恢復的時候也可以從上次消息的位置繼續(xù)處理(RocketMQ和Kafka都支持Exactly Once語義)颓影,這里即使生產者的速度異于消費者的速度也不會有影響各淀,日志在這里起到了緩沖的作用,它可以將所有的記錄存儲到日志中诡挂,并定時同步到slave節(jié)點碎浇,這樣消息的積壓能力能夠得到很好的提升,因為寫日志都是有master節(jié)點處理璃俗,讀請求這里分為兩種奴璃,一種是tail-read,就是說消費速度能夠跟得上寫入速度的城豁,這種讀可以直接走緩存苟穆,而另一種也就是落后于寫入請求的消費者,這種可以從slave節(jié)點讀取钮蛛,這樣通過IO隔離以及操作系統自帶的一些文件策略鞭缭,例如pagecache、緩存預讀等魏颓,性能可以得到很大的提升岭辣。
分布式系統中可橫向擴展是一個相當重要的特性,加機器能解決的問題都不是問題甸饱。那么如何實現一個能夠實現橫向擴展的消息隊列呢? 加入我們有一個單機的消息隊列沦童,隨著topic數目的上升,IO叹话、CPU偷遗、帶寬等都會逐漸成為瓶頸,性能會慢慢下降驼壶,那么這里如何進行性能優(yōu)化呢?
1.topic/日志分片氏豌,本質上topic寫入的消息就是日志的記錄,那么隨著寫入的數量越多热凹,單機會慢慢的成為瓶頸泵喘,這個時候我們可以將單個topic分為多個子topic泪电,并將每個topic分配到不同的機器上,通過這種方式纪铺,對于那些消息量極大的topic就可以通過加機器解決相速,而對于一些消息量較少的可以分到到同一臺機器或不進行分區(qū)
2.group commit,例如Kafka的producer客戶端鲜锚,寫入消息的時候突诬,是先寫入一個本地內存隊列,然后將消息按照每個分區(qū)芜繁、節(jié)點匯總旺隙,進行批量提交,對于服務器端或者broker端浆洗,也可以利用這種方式催束,先寫入pagecache,再定時刷盤伏社,刷盤的方式可以根據業(yè)務決定抠刺,例如金融業(yè)務可能會采取同步刷盤的方式。
4.IO隔離
結語
日志在分布式系統中扮演了很重要的角色摘昌,是理解分布式系統各個組件的關鍵速妖,隨著理解的深入,我們發(fā)現很多分布式中間件都是基于日志進行構建的聪黎,例如Zookeeper罕容、HDFS、Kafka稿饰、RocketMQ锦秒、Google Spanner等等,甚至于數據庫喉镰,例如Redis旅择、MySQL等等,其master-slave都是基于日志同步的方式侣姆,依賴共享的日志系統生真,我們可以實現很多系統: 節(jié)點間數據同步、并發(fā)更新數據順序問題(一致性問題)捺宗、持久性(系統crash時能夠通過其他節(jié)點繼續(xù)提供服務)柱蟀、分布式鎖服務等等,相信慢慢的通過實踐蚜厉、以及大量的論文閱讀之后长已,一定會有更深層次的理解。