carloszhao
當(dāng)前內(nèi)存數(shù)據(jù)庫發(fā)展迅速,用戶對于存儲(chǔ)系統(tǒng)的要求也越來越高,為了滿足各類業(yè)務(wù)場景的需要,騰訊云設(shè)計(jì)了新一代的內(nèi)存數(shù)據(jù)庫,不但保留了原來系統(tǒng)的高性能、高可用等特性,同時(shí)還兼容了當(dāng)前流行的Redis原生協(xié)議及使用方式。我們試圖在解決原生方案短板的基礎(chǔ)上,不斷創(chuàng)新,使得新系統(tǒng)同時(shí)具備易懂、易用、易維護(hù)、高可靠、低成本等特點(diǎn)。主要體現(xiàn)在以下幾個(gè)方面:
1.沿用了上一代自研系統(tǒng)使用共享內(nèi)存的數(shù)據(jù)存儲(chǔ)方案,避免Redis采用AOF機(jī)制,恢復(fù)時(shí)間過久的問題,極大的降低了在升級、進(jìn)程異常等場景產(chǎn)生的影響。同時(shí),使用全新的快照與流水機(jī)制,解決了Fork機(jī)制造成的內(nèi)存預(yù)留問題。
2.在存儲(chǔ)引擎方面,對于自研及開源方案進(jìn)行重新分析整理,進(jìn)行了再次創(chuàng)新,不但使用多規(guī)格Block靈活組合的存儲(chǔ)方式,內(nèi)部數(shù)據(jù)結(jié)構(gòu)同樣采用動(dòng)態(tài)頁管理,對比原生引擎,極大的提高了內(nèi)存使用率的同時(shí),也降低了運(yùn)行過程中產(chǎn)生內(nèi)存碎片的機(jī)率。
3.單進(jìn)程多線程的模型讓運(yùn)維部署更加簡便,同時(shí)精簡模塊數(shù)量,讓請求路徑更短。
4.更加精細(xì)化的數(shù)據(jù)管理,實(shí)現(xiàn)快速的過期淘汰及精確的LRU特性。
5.實(shí)現(xiàn)了強(qiáng)一致特性,滿足了金融等業(yè)務(wù)對于數(shù)據(jù)一致性的強(qiáng)需求。
6.集群版模式中,支持了多數(shù)據(jù)庫的場景,降低用戶由主從版遷移至集群版的使用門檻。
7.存儲(chǔ)節(jié)點(diǎn)可直接轉(zhuǎn)發(fā)用戶請求,降低后臺(tái)數(shù)據(jù)變更對于客戶端的依賴,原生主從版客戶端可直接訪問集群版,無需修改代碼。
8.我們正在兼容更多的原生數(shù)據(jù)庫協(xié)議,讓更多的用戶可以無縫切換,體驗(yàn)更多的新特性。
技術(shù)架構(gòu)優(yōu)化歷程
在架構(gòu)方面我們將當(dāng)前比較流行的兩層(不包含客戶端)結(jié)構(gòu)簡化成了單層。
Cache則是實(shí)際的數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn)。架構(gòu)中不再顯式設(shè)置接入層,而是通過Cache轉(zhuǎn)發(fā)用戶請求,這樣做的好處:
·單純的存儲(chǔ)或接入模塊,由于對不同資源類型(CPU、網(wǎng)卡、內(nèi)存等)需求的傾斜,無法很好的提高當(dāng)前高配機(jī)型的設(shè)備利用率。也基于這個(gè)原因,理論上合并后的單層結(jié)構(gòu)能更好的利用硬件資源,節(jié)約成本;
·減少模塊數(shù)量可以減少大量運(yùn)維操作,便于運(yùn)維人員部署及規(guī)劃資源等;
·路由更接近數(shù)據(jù),因此在某臺(tái)Cache上進(jìn)行數(shù)據(jù)遷移動(dòng)作時(shí),可以更加實(shí)時(shí)的對用戶請求做出應(yīng)對(轉(zhuǎn)發(fā)至最新的目標(biāo)),減少變更對用戶請求的影響。
針對一些對于接入層有強(qiáng)需求的場景,比如,某業(yè)務(wù)的客戶端鏈接數(shù)極多,我們也有針對性的做了優(yōu)化。Cache可退化為純接入機(jī)使用,這樣可以方便的擴(kuò)展為兩層結(jié)構(gòu),統(tǒng)一使用一套代碼,無需單獨(dú)維護(hù)。
數(shù)據(jù)分布方面,采用了全部打散的方式,即在任意一臺(tái)Cache上既有主數(shù)據(jù)也有(其他業(yè)務(wù))備份數(shù)據(jù),完全以Shard為粒度(物理內(nèi)存單元)進(jìn)行管理。
每臺(tái)Cache的內(nèi)存被劃分為若干Shard,無論是主從版還是集群版,用戶的主或備數(shù)據(jù)可能落到任意Cache,分配策略支持跨機(jī)架、跨機(jī)房等。這樣做的目的有:
·不再有單純的熱備設(shè)備,減少低負(fù)載設(shè)備比例,充分利用整個(gè)集群的網(wǎng)卡、CPU等資源;
·當(dāng)一個(gè)或若干節(jié)點(diǎn)異常時(shí),利用整個(gè)集群的能力進(jìn)行容錯(cuò)(切換流量)與恢復(fù)(在不同節(jié)點(diǎn)重建備份),避免雪球效應(yīng);
·在分配時(shí),將考慮現(xiàn)有設(shè)備主備Shard比例及負(fù)載,優(yōu)化裝箱算法,可是集群資源更加均衡。
由于CKV+兼容Redis協(xié)議及各種使用場景,因此也區(qū)分了主從版與集群版。對于集群版來說,經(jīng)過對比,數(shù)據(jù)哈希仍然采用了Pre-sharding的方式。
對于單個(gè)Shard來說,最大可管理內(nèi)存為8 T,由于目前設(shè)備限制,實(shí)際最大可支持512 G,因此集群版支持的容量范圍為[1 G,512 G]×16 384 = [16 T,8 P]。當(dāng)然在實(shí)際應(yīng)用中,還需考慮系統(tǒng)內(nèi)部預(yù)留資源等因素,且Shard大小及Slot對應(yīng)關(guān)系的規(guī)劃也要視物理資源情況而定。
內(nèi)存引擎設(shè)計(jì),確定CKV+引擎
內(nèi)存管理是內(nèi)存數(shù)據(jù)庫系統(tǒng)中非常重要的一環(huán),在CKV+系統(tǒng)的設(shè)計(jì)階段,對于引擎也是進(jìn)行了大量的討論與調(diào)研,根據(jù)我們的經(jīng)驗(yàn),同時(shí)吸納了多種主流內(nèi)存管理體系的優(yōu)點(diǎn),確定了當(dāng)前CKV+的引擎方案。主要特點(diǎn)歸納如下:
·使用共享內(nèi)存,方便升級或進(jìn)程異常時(shí)快速恢復(fù);
·基于共享內(nèi)存實(shí)現(xiàn)了紅黑樹算法,在保證性能的前提下,兼容Redis中的Hash、Set、ZSet數(shù)據(jù)類型;
·使用多規(guī)格Block作為(最小的)數(shù)據(jù)存儲(chǔ)單位,更加靈活同時(shí)內(nèi)存空隙更??;
·使用經(jīng)典的Page管理模式,優(yōu)化了動(dòng)態(tài)分配策略,提高了Page回收幾率,降低內(nèi)存碎片率;
·用戶數(shù)據(jù)所依附的內(nèi)部數(shù)據(jù)結(jié)構(gòu)同樣基于Page進(jìn)行動(dòng)態(tài)分配,減少內(nèi)部預(yù)留空間的浪費(fèi)。
內(nèi)存引擎的一個(gè)重要指標(biāo)就是內(nèi)存使用率,我們與原生Redis存儲(chǔ)進(jìn)行了對比測試。
測試方法:使用同樣的隨機(jī)數(shù)據(jù),分別寫入Redis及CKV+的1 G實(shí)例,對比實(shí)際存儲(chǔ)數(shù)據(jù)量的多少。
樣本大?。簁ey [10,30],Value [20,100]
測試顯示,在簡單String類型的場景下,兩者存儲(chǔ)量近似,但在稍復(fù)雜的結(jié)構(gòu)中,CKV+則可以存儲(chǔ)更多的用戶數(shù)據(jù)。
大膽嘗試,采用單進(jìn)程多線程模型
對于內(nèi)存數(shù)據(jù)庫來說,高性能仍然是大前提,而開發(fā)過程中使用的線程模型及框架對于這個(gè)層面影響較大。因此在設(shè)計(jì)初始,我們對于這部分也做了大膽嘗試。
首先,我們使用了單進(jìn)程多線程的模式,而非大多開源系統(tǒng)的單進(jìn)程單線程的路數(shù),一方面可以更好的利用整機(jī)資源,另一方面也能降低運(yùn)維門檻。對于多線程來說,需要解決的主要問題有如下幾點(diǎn):
·若干線程共同管理內(nèi)存則勢必需要引入鎖,而高配機(jī)型核數(shù)多、線程多,加鎖可能帶來毛刺;
·單個(gè)進(jìn)程需要管理多個(gè)業(yè)務(wù)數(shù)據(jù),特別是主從版,每塊內(nèi)存Shard容量較大,難免有比較龐大的kv數(shù)據(jù),同時(shí)主從版支持部分耗時(shí)操作,需要盡量減少實(shí)例間的相互影響;
·線程間通信或共享數(shù)據(jù)的代價(jià)要小,如同步路由信息等;
·同時(shí)要考慮諸如線程上下文切換、CPU緩存命中率、IO等因素。
在進(jìn)行了一系列的調(diào)研工作后,最終確定線程模型為:每個(gè)物理核啟動(dòng)一個(gè)線程,管理若干內(nèi)存Shard。
使用這種模式的主要考慮:
·具體內(nèi)存的操作僅由某一個(gè)CPU處理,避免加鎖,某個(gè)Shard出現(xiàn)熱點(diǎn)時(shí),對其他線程管理的實(shí)例影響較?。?/p>
·在管理實(shí)例數(shù)量不多的情況下,空閑CPU可以處理網(wǎng)絡(luò)及磁盤IO,以及請求的編解碼等工作,提高整機(jī)資源利用率;
·線程間不存在依賴或競爭關(guān)系,避免不必要的損耗。
騰訊云新一代內(nèi)存數(shù)據(jù)庫不但全面兼容了Redis的數(shù)據(jù)結(jié)構(gòu)及使用方法,同時(shí)解決了原生方案在備份、容災(zāi)等方面的不足。在性能方面,我們并沒有滿足于現(xiàn)狀,后續(xù)還將更細(xì)致的優(yōu)化邏輯流程,并引入DPDK等特性,進(jìn)一步提升系統(tǒng)性能。成本也是我們關(guān)注的重點(diǎn),當(dāng)前的系統(tǒng)架構(gòu)與線程模型能更好的適應(yīng)不斷提升的硬件設(shè)備性能,提高硬件資源的利用率,同時(shí),我們也將引進(jìn)冷熱數(shù)據(jù)分離等技術(shù),在保證性能的前提下,更好的為用戶節(jié)省成本。