
作為互聯(lián)網(wǎng)通信云獨(dú)角獸的融云每天要存儲(chǔ)的消息量高達(dá)數(shù)十億條,多年來融云一直致力于消息存儲(chǔ)的優(yōu)化,從原型階段的MySQL到后來的Redis、LevelDB,融云不停的探索實(shí)踐。隨著業(yè)務(wù)的發(fā)展和數(shù)據(jù)的持續(xù)增長(zhǎng),融云需要一個(gè)既能滿足業(yè)務(wù)需求,又能滿足大業(yè)務(wù)量的消息數(shù)據(jù)存儲(chǔ),因此融云研究院在2017年決定研發(fā)可以滿足自身業(yè)務(wù)特點(diǎn)的高性能消息存儲(chǔ)服務(wù)(內(nèi)部代號(hào)RCTSDB),并使用全新設(shè)計(jì)的數(shù)據(jù)存儲(chǔ)引擎。
以下內(nèi)容摘自李淼演講實(shí)錄。
融云消息存儲(chǔ)歷程
首先是融云在開始時(shí)的原型產(chǎn)品驗(yàn)證階段,大概是在2013年初創(chuàng)階段,為了驗(yàn)證融云的即時(shí)通信業(yè)務(wù)模式,此時(shí)的消息都是存儲(chǔ)在MySQL中,其特點(diǎn)是開發(fā)簡(jiǎn)單,可以滿足各種產(chǎn)品需求。
在原型驗(yàn)證通過后,正式上線前融云將離線消息遷移到了Redis中以滿足性能需求,而歷史消息則繼續(xù)保存在MySQL中。
融云經(jīng)過一年多業(yè)務(wù)飛速的發(fā)展,要存儲(chǔ)的消息越來越多,而Redis集群也幾乎每1-2個(gè)月就要進(jìn)行擴(kuò)容。當(dāng)時(shí)處于對(duì)成本的考量,融云決定采用相對(duì)低廉的磁盤存儲(chǔ)方案。此時(shí)融云做了很多選型,最終決定采用基于levelDB作為存儲(chǔ)引擎并自研DB。但是當(dāng)時(shí)的由于levelDB數(shù)據(jù)歸并消耗高,數(shù)據(jù)淘汰困難等問題,運(yùn)行兩個(gè)月后替換了原來的Redis存儲(chǔ)方案。
目前融云的線上情況是Redis存儲(chǔ)離線消息,levelDB存儲(chǔ)歷史消息,而融云的業(yè)務(wù)也相對(duì)進(jìn)入了平穩(wěn)期,Redis最近一次擴(kuò)容是在2018年的5、6月份,根據(jù)業(yè)務(wù)增速情況可以支持到2018年底。
存儲(chǔ)架構(gòu)相對(duì)穩(wěn)定,為什么融云還要啟動(dòng)自研存儲(chǔ)項(xiàng)目呢?
滿足一些復(fù)雜的業(yè)務(wù)場(chǎng)景需求
基于目前的存儲(chǔ)方案,一些需求實(shí)現(xiàn)起來非常困難,而這些需求都是來自客戶,從而制約產(chǎn)品的演進(jìn),所以融云急需一個(gè)替代方案;
降低整體的成本投入
融云線上的Redis集群成本是所有設(shè)備投入的一半以上,對(duì)于存儲(chǔ)的優(yōu)化,顯然是可以持續(xù)降低公司運(yùn)營(yíng)成本;
簡(jiǎn)化部署模型
對(duì)于Redis的部署不是很復(fù)雜,但是融云除了公有云的業(yè)務(wù)以外還有私有云項(xiàng)目,繼續(xù)使用Redis對(duì)客戶側(cè)的運(yùn)維部署成本就會(huì)變的很高;
源碼可控
之前融云使用過很多的開源產(chǎn)品,當(dāng)這些產(chǎn)品不能滿足業(yè)務(wù)需求時(shí),融云又急需某些特性時(shí),這就需要和作者聯(lián)系,但是大部分時(shí)候作者都不能及時(shí)響應(yīng)或者根本不在其計(jì)劃內(nèi),而這時(shí)融云只能等或者自己改,自己改的又回饋不了開源產(chǎn)品的主干上,或者當(dāng)開源產(chǎn)品更新沒辦法合并,這樣就迫使融云必須啟動(dòng)自研存儲(chǔ)項(xiàng)目。
即時(shí)通信類產(chǎn)品,自研存儲(chǔ)需具備哪些特點(diǎn)?
快速的數(shù)據(jù)淘汰能力
數(shù)據(jù)淘汰的過程不能對(duì)系統(tǒng)產(chǎn)生任何的影響;
避免數(shù)據(jù)合并
相對(duì)于levelDB來講,當(dāng)寫入很多操作的時(shí)候levelDB的數(shù)據(jù)合并經(jīng)常會(huì)發(fā)生CPU報(bào)警,導(dǎo)致寫入查詢響應(yīng)速度慢等情況;
讀寫性能要求高
至少不能比融云現(xiàn)有使用的Redis速度慢;
開發(fā)使用靈活
在融云存儲(chǔ)引擎設(shè)計(jì)過程中,不僅只是存儲(chǔ)數(shù)據(jù),而是當(dāng)作開發(fā)框架來進(jìn)行設(shè)計(jì)的,在各操作點(diǎn)上都提供Hook,從而能夠滿足各種業(yè)務(wù)場(chǎng)景需求。
站在前人的肩膀上遠(yuǎn)眺
融云在存儲(chǔ)引擎設(shè)計(jì)過程中借鑒很多已有的成熟方案,并將這些方案進(jìn)行優(yōu)化整合,最終完成了自有的引擎設(shè)計(jì)。下面將羅列一些方案,并向前人致敬。
數(shù)據(jù)寫入采用WAL模式
數(shù)據(jù)在寫入內(nèi)存時(shí)同時(shí)記錄,當(dāng)服務(wù)宕機(jī)或重啟的時(shí)候可以根據(jù)這些恢復(fù)內(nèi)存數(shù)據(jù)。這些都是按照磁盤順序?qū)懭,可以變相的提高存?chǔ)引擎性能。一般主流的數(shù)據(jù)庫(kù)都會(huì)采用這種模式完成數(shù)據(jù)寫入。
借鑒InfluxDB中的LSM數(shù)據(jù)結(jié)構(gòu)
LSM數(shù)據(jù)結(jié)構(gòu)是目前一些新興數(shù)據(jù)庫(kù)采用的數(shù)據(jù)結(jié)構(gòu),像LevelDB、RocksDB、HBase、Cassandra等。即時(shí)通訊消息具備時(shí)序數(shù)據(jù)的特點(diǎn),而InfluxDB更是時(shí)序數(shù)據(jù)庫(kù)中的佼佼者,融云對(duì)InfulxDB做了一些改造,使其更適合存儲(chǔ)一些時(shí)序數(shù)據(jù)
借鑒whiskey 的 K / V 分離存儲(chǔ)設(shè)計(jì)
whiskey 是2016年發(fā)表的一篇論文,主要解決了LSM中大數(shù)量寫入后頻繁數(shù)據(jù)歸并的問題,在LSM這種數(shù)據(jù)結(jié)構(gòu)中,數(shù)據(jù)的Key和Value值都是要寫入內(nèi)存的,當(dāng)數(shù)據(jù)到達(dá)內(nèi)存設(shè)定的閾值時(shí)進(jìn)行歸檔處理。對(duì)于value值較大的數(shù)據(jù)來說,這個(gè)歸檔就會(huì)變得特變頻繁,而whiskey的理念是將value單獨(dú)保存至另外的文件位置,LSM結(jié)構(gòu)內(nèi)保存的是Key以及這個(gè)Value所在文件的偏移量和長(zhǎng)度,以此來降低歸檔頻。按照論文上的介紹,歸檔頻率可以降低一個(gè)數(shù)量級(jí)。
借鑒MyISAM的存儲(chǔ)文件設(shè)計(jì)
在文件設(shè)計(jì)這塊融云一共經(jīng)歷四版改動(dòng),最終殊途同歸。融云發(fā)現(xiàn)Mysql中MyISAM引擎的文件設(shè)計(jì)很有類似之處。
融云消息存儲(chǔ)引擎設(shè)計(jì)
1.存儲(chǔ)邏輯劃分

2.存儲(chǔ)文件規(guī)劃
關(guān)于Table文件分為三種文件進(jìn)行組織存儲(chǔ):
- xxx.data 數(shù)據(jù)存儲(chǔ)文件;
- xxx.index 數(shù)據(jù)索引文件;
- xxx.info table信息文件。
文件并沒有按照Table文件進(jìn)行劃分存儲(chǔ),是按照序號(hào)字段進(jìn)行排序,為的是在設(shè)計(jì)過程中解決主從復(fù)制,提高便捷性。
3.數(shù)據(jù)寫入邏輯

4.數(shù)據(jù)文件設(shè)計(jì)

5.日志文件設(shè)計(jì)

6.索引文件設(shè)計(jì)

7.信息文件設(shè)計(jì)

內(nèi)存優(yōu)化
- 在M_block中融云重度依賴跳表這種數(shù)據(jù)結(jié)構(gòu),融云的存儲(chǔ)引擎是用java寫的,主要考慮是后面可移植的問題。起初融云采用了java里面內(nèi)置的ConcurrentSkipList,但是其內(nèi)存消耗很高,這個(gè)主要是java的中對(duì)象內(nèi)存分配的規(guī)則導(dǎo)致的。所以融云重寫了SkipList,放棄了java中的對(duì)象模式。重新造的輪子其內(nèi)存消耗只有原始 1/4,同時(shí)也犧牲了一些東西,例如:刪除跳表內(nèi)的數(shù)據(jù)時(shí),其刪除的數(shù)據(jù)所占的內(nèi)存無法釋放,但是對(duì)于即時(shí)通信消息來講基本上不存在刪除的場(chǎng)景,同樣一些時(shí)序數(shù)據(jù)也極少存在刪除場(chǎng)景;
- 索引數(shù)據(jù)融云進(jìn)行了一系列緊湊處理。優(yōu)化后40億級(jí)的索引數(shù)據(jù),只消耗內(nèi)存400MB。放棄java對(duì)象模式,直接采用byte數(shù)值的方式進(jìn)行數(shù)據(jù)組織;
- 對(duì)很多的對(duì)象又做了一些細(xì)節(jié)處理,想辦法把Java本身的一些內(nèi)存模型給抹平掉,通過這種方式來降低內(nèi)存利用率;
- 最后融云做了LIRS的緩存機(jī)制。
存儲(chǔ)優(yōu)化
- 索引數(shù)據(jù)前綴壓縮,降低磁盤的寫入量;
- 數(shù)值數(shù)據(jù)采用VarInt編碼;
- 業(yè)務(wù)數(shù)據(jù)QuickLZ壓縮,平衡了存儲(chǔ)及CPU的使用率;
- 數(shù)據(jù)寫入采用雙循環(huán)可變長(zhǎng)度Buffer,使數(shù)據(jù)寫入過程中是沒有直接操作的,有效降低延遲的產(chǎn)生;
- 重復(fù)數(shù)據(jù)引用寫入,該優(yōu)化對(duì)于即時(shí)通信場(chǎng)景有顯著成效。
服務(wù)端架構(gòu)
該架構(gòu)主要包含Broker,以及一些數(shù)據(jù)的分組Master、Slaver,這些數(shù)據(jù)是根據(jù)ZooKeeper進(jìn)行管理,同時(shí)向Broker進(jìn)行匯報(bào)。在Broker上會(huì)開設(shè)不同的端口去設(shè)置各種不同的協(xié)議。最后是DB manger,主要是用于管理引擎的各種數(shù)據(jù)查詢的插件,就像前文提到的該引擎除了是用于數(shù)據(jù)存儲(chǔ)外還是開發(fā)框架,程序員在架構(gòu)上可以靈活按照熟悉的開發(fā)語(yǔ)言去直接操作這些數(shù)據(jù)。

數(shù)據(jù)存儲(chǔ)引擎項(xiàng)目將在年底開源
李淼在會(huì)上表示,為了促進(jìn)產(chǎn)業(yè)內(nèi)的技術(shù)交流,融云會(huì)在未來兩個(gè)月時(shí)間對(duì)數(shù)據(jù)存儲(chǔ)引擎項(xiàng)目進(jìn)行開源,開源前除了對(duì)引擎做一些優(yōu)化以外,還會(huì)補(bǔ)充一些相關(guān)的文檔,同時(shí)為了方便開發(fā)者集成參考還會(huì)對(duì)代碼增加一些注釋。項(xiàng)目開源后意味著融云是國(guó)內(nèi)首家將自研的消息存儲(chǔ)引擎開源的云通信廠商,也正在為中國(guó)的開源環(huán)境貢獻(xiàn)自己應(yīng)盡的力量。
關(guān)于融云:融云,安全、可靠的全球互聯(lián)網(wǎng)通信云服務(wù)商,向開發(fā)者和企業(yè)提供即時(shí)通訊和實(shí)時(shí)音視頻通信云服務(wù),據(jù)艾瑞等權(quán)威數(shù)據(jù)顯示,融云即時(shí)通訊云業(yè)務(wù)市場(chǎng)份額穩(wěn)居第一。目前,已有數(shù)十萬互聯(lián)網(wǎng)用戶及上千家企業(yè)級(jí)用戶通過融云實(shí)現(xiàn)了場(chǎng)景化溝通,并從中獲益,包括招商銀行、工商銀行、交通銀行、民生銀行、中國(guó)移動(dòng)、四川航空、CCTV微視、中聯(lián)重科、58 趕集、大河報(bào)業(yè)、新東方、陸金所、易車網(wǎng)、豬八戒、蔚來汽車、得到APP、荔枝 FM、汽車之家、優(yōu)酷來瘋、攜程愛玩、聚力視頻、百姓網(wǎng)等知名企業(yè)及應(yīng)用。