李 博,謝小龍,蔡仁鋒,李 亮,方魯杰
(1.中電(海南)聯(lián)合創(chuàng)新研究院,海南 澄邁 571924;2.中軟信息系統(tǒng)工程有限公司,北京 102209)
隨著互聯(lián)網(wǎng)經(jīng)濟(jì)的飛速發(fā)展,傳統(tǒng)的集中式數(shù)據(jù)庫(kù)逐漸成為金融核心業(yè)務(wù)發(fā)展的瓶頸,迫使金融核心業(yè)務(wù)系統(tǒng)向分布式架構(gòu)轉(zhuǎn)型,利用分布式數(shù)據(jù)庫(kù)替換集中式數(shù)據(jù)庫(kù),從而獲得高性能、高擴(kuò)展、高可用等關(guān)鍵優(yōu)勢(shì)。金融產(chǎn)業(yè)是一個(gè)國(guó)家的經(jīng)濟(jì)命脈,安全不容忽視,中國(guó)電子PKS 體系為助力金融國(guó)產(chǎn)化提供安全底座,從芯片到整機(jī)外設(shè)、操作系統(tǒng)等為金融國(guó)產(chǎn)化提供安全支持。通過前期調(diào)研數(shù)款分布式數(shù)據(jù)庫(kù)產(chǎn)品,選取可擴(kuò)展、強(qiáng)一致性、高可靠和支持HATP 混合工作負(fù)載的分布式數(shù)據(jù)庫(kù) CockroachDB[1]為研究對(duì)象,在PKS 體系下進(jìn)行性能優(yōu)化工作,其性能的提升對(duì)金融產(chǎn)業(yè)的發(fā)展有重要意義。
在對(duì)數(shù)據(jù)庫(kù)系統(tǒng)調(diào)優(yōu)時(shí),基本手段是在配置參數(shù)維度進(jìn)行,主要通過改變配置參數(shù)以達(dá)到優(yōu)化性能的目的,配置參數(shù)包括數(shù)據(jù)庫(kù)配置參數(shù),如用于緩存的內(nèi)存量、緩沖區(qū)大小等[2]。比如 BestConfig[3]方法,該工作基于遞歸限定查找算法搜索最佳配置參數(shù)。Thummala[2]等人對(duì)部分關(guān)系型數(shù)據(jù)庫(kù)參數(shù)進(jìn)行調(diào)優(yōu),尋找對(duì)其調(diào)優(yōu)效果最大的配置。與數(shù)據(jù)庫(kù)物理設(shè)計(jì)工具不同,配置工具不能使用關(guān)系型數(shù)據(jù)庫(kù)查詢優(yōu)化器中的內(nèi)置成本模型,此類模型根據(jù)系統(tǒng)預(yù)期為特定查詢執(zhí)行所需要的工作量進(jìn)行估計(jì)并生成預(yù)估值[4]。這些預(yù)估值針對(duì)單個(gè)關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)的備選查詢執(zhí)行策略與固定的執(zhí)行環(huán)境進(jìn)行比較。IBM 發(fā)布了DB2 Performance Wizard[4]根據(jù)具體工作負(fù)載來設(shè)置參數(shù),但由于模型是手動(dòng)創(chuàng)建,因此無法準(zhǔn)確反映實(shí)際工作負(fù)載或操作環(huán)境。Oracle[5]開發(fā)了以識(shí)別由于數(shù)據(jù)庫(kù)系統(tǒng)內(nèi)部組件中的錯(cuò)誤配置而導(dǎo)致的瓶頸的一個(gè)內(nèi)部監(jiān)控系統(tǒng),雖然可以為工程師提供建議,但因?yàn)?Oracle 系統(tǒng)采用基于性能測(cè)量的啟發(fā)式方法來管理內(nèi)存分配,無法對(duì)所有參數(shù)進(jìn)行調(diào)優(yōu)。SQL Server[6]也采用類似的方法。
隨著數(shù)據(jù)庫(kù)和應(yīng)用程序在規(guī)模和復(fù)雜性上的增長(zhǎng),優(yōu)化數(shù)據(jù)庫(kù)以滿足應(yīng)用程序的需求已經(jīng)超出了人類的能力,因?yàn)閿?shù)據(jù)庫(kù)的正確配置高度依賴于許多超出人類推理范圍的因素。上述的自動(dòng)數(shù)據(jù)庫(kù)配置工具存在某些不足之處,使其不適合于通用數(shù)據(jù)庫(kù)應(yīng)用程序。同時(shí)許多調(diào)優(yōu)工具都是由供應(yīng)商創(chuàng)建的,它們只支持特定的數(shù)據(jù)庫(kù)。鑒于此,Aken[7]等人提出了基于深度學(xué)習(xí)的OtterTune 調(diào)優(yōu)框架,該框架主要分為兩塊:客戶端和服務(wù)端??蛻舳撕蛿?shù)據(jù)庫(kù)進(jìn)行交互,比如采集數(shù)據(jù),執(zhí)行參數(shù)設(shè)置。服務(wù)端作為OtterTune 的大腦,分析收集到數(shù)據(jù),形成深度模型,并在產(chǎn)出參數(shù)的優(yōu)化策略,文獻(xiàn)[8-9]在OtterTune 的基礎(chǔ)上繼續(xù)發(fā)展應(yīng)用。類似利用深度學(xué)習(xí)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)庫(kù)優(yōu)化的工作還有CDBtune[10]等。PingCAP[11]團(tuán)隊(duì)使用TiDB 數(shù)據(jù)庫(kù)針對(duì)金融場(chǎng)景進(jìn)行調(diào)優(yōu),采用了包括索引優(yōu)化、拓展集群和負(fù)載均衡調(diào)整等手段,提升效果比較可觀。另外除了調(diào)整數(shù)據(jù)庫(kù)參數(shù),還有結(jié)合分布式數(shù)據(jù)庫(kù)自身特性進(jìn)行軟硬件調(diào)優(yōu),如操作系統(tǒng)內(nèi)核調(diào)優(yōu)、網(wǎng)絡(luò)調(diào)優(yōu)、線程調(diào)度調(diào)優(yōu)、I/O 讀寫性能調(diào)優(yōu)、PCIE 速率調(diào)優(yōu)、軟硬中斷調(diào)優(yōu)、熱點(diǎn)代碼分析,這些方法在實(shí)際性能調(diào)優(yōu)過程中發(fā)揮了重要作用,文獻(xiàn)[11]有實(shí)際應(yīng)用。
本文所研究的調(diào)優(yōu)方法則是在上述調(diào)優(yōu)方法的基礎(chǔ)上,重點(diǎn)研究數(shù)據(jù)庫(kù)與操作系統(tǒng)和CPU 等軟硬件協(xié)同工作,尤其在非一致性內(nèi)存訪問和操作系統(tǒng)內(nèi)核中頁緩存管理機(jī)制進(jìn)行深入研究,并提出拆分二進(jìn)制實(shí)例的調(diào)優(yōu)方法。
本節(jié)將對(duì)拆分二進(jìn)制實(shí)例的調(diào)優(yōu)方法進(jìn)行詳細(xì)介紹,在開始介紹之前,將對(duì)Numa 架構(gòu)和CPU 綁核原理進(jìn)行介紹,有利于更好地理解拆分二進(jìn)制實(shí)例的調(diào)優(yōu)方法。
2.1.1 NUMA 架構(gòu)
非一致性內(nèi)存訪問(Non-Uniform Memory Access,NUMA)是處理器地址空間中不同Node 的內(nèi)存具有不同性能特征,與之對(duì)應(yīng)的是早期使用的統(tǒng)一內(nèi)存訪問,即每個(gè)處理器核心享有相同的內(nèi)存地址空間。隨著CPU 架構(gòu)朝著多核心方向發(fā)展,多核心訪問內(nèi)存的瓶頸越來越明顯。NUMA 的基本思想是將各個(gè)CPU 劃分為不同的NUMA Node,每個(gè)Node 擁有自己的內(nèi)存,從處理器到內(nèi)存的信號(hào)路徑長(zhǎng)度起著重要作用,只有當(dāng)CPU訪問與自身直接相連的內(nèi)存對(duì)應(yīng)的物理地址時(shí),才會(huì)有較短的響應(yīng)時(shí)間。訪問其他CPU 的內(nèi)存時(shí),增加的信號(hào)路徑長(zhǎng)度不僅會(huì)增加內(nèi)存延遲,而且如果信號(hào)路徑由多個(gè)處理器共享,也會(huì)很快成為吞吐量瓶頸。
以飛騰S2500 高性能CPU 為例說明NUMA,圖1 為該CPU 的架構(gòu)圖,該CPU 以8 個(gè)核心(圖中使用 C 表示)為一組直接連接一個(gè) L3 內(nèi)存,這個(gè)組合被稱為一個(gè) Node,可以看到 S2500 有8 個(gè) Node,若跨 Node 訪問內(nèi)存則需要通過黑色雙向箭頭表示的系統(tǒng)總線。當(dāng)Node 訪問非本地內(nèi)存時(shí),就涉及訪問距離,在 S2500 中Nodei與 Nodej間的訪問距離dij可以表示為式(1)中的代價(jià)矩陣D,其中矩陣的對(duì)角線表示 Node 訪問本地內(nèi)存的距離,即最短訪問距離。
圖1 飛騰 S2500 處理器架構(gòu)圖
2.1.2 CPU 綁核
在Linux 操作系統(tǒng)中,線程調(diào)度默認(rèn)由內(nèi)核自由調(diào)度,在多核 CPU 上,進(jìn)程可能在不同的 CPU 核心上來回切換執(zhí)行,這對(duì) CPU 的緩存讀取是不利的,因?yàn)镃PU 存在上下文切換(Context Switch)。每個(gè)物理核有獨(dú)立的 L1 和 L2 級(jí)緩存,程序執(zhí)行最頻繁的指令和數(shù)據(jù)會(huì)被緩存到 L1 和 L2 級(jí)緩存中,一旦程序被切換到另一個(gè)物理核時(shí),對(duì)應(yīng)的指令和數(shù)據(jù)需要被重新刷到相應(yīng)的 L1、L2 緩存中,造成頻繁地進(jìn)行上下文切換,程序不能很好地利用 L1 和 L2 級(jí)緩存,增加程序的延時(shí)性。針對(duì)這種頻繁切換 CPU 核進(jìn)行操作,可以采用綁核操作,將程序綁核到指定 CPU 核上,程序只在對(duì)應(yīng)的CPU 核上執(zhí)行,不會(huì)切換到其他 CPU 核上。以飛騰S2500 處理器為例,可以參考式(1)中距離矩陣選擇距離較近的Node 進(jìn)行綁定,至于綁定方法及其試驗(yàn)結(jié)果將在第3 節(jié)進(jìn)行討論。
本次研究采用單機(jī)四實(shí)例的部署方式,即一臺(tái)服務(wù)器上開啟四個(gè) CockroachDB 的二進(jìn)制實(shí)例,四個(gè)二進(jìn)制實(shí)例綁核在不同的 Node 上,通常做法是將一個(gè) CockroachDB 的二進(jìn)制實(shí)例運(yùn)行四次。用 numastat 命令查看二進(jìn)制實(shí)例在 Node 內(nèi)存的分布情況,發(fā)現(xiàn)少部分內(nèi)存在非綁定 Node 內(nèi)存中。表1 展示了第四個(gè)CockroachDB 二進(jìn)制實(shí)例的 Node 內(nèi)存使用情況,該二進(jìn)制實(shí)例綁定在 Node 12 和 Node 13 上,卻發(fā)現(xiàn)少部分內(nèi)存被 Node 1 和 Node 2 使用(表格中加粗顯示部分),類似的情況也出現(xiàn)在其他二進(jìn)制實(shí)例。
表1 優(yōu)化前 CockroachDB 第四個(gè)二進(jìn)制實(shí)例的內(nèi)存使用詳情
為了深入調(diào)查這部分內(nèi)存的信息,調(diào)取該二進(jìn)制實(shí)例的 numa_maps 信息。numa_maps 是一個(gè)只讀文件,當(dāng)讀取時(shí),內(nèi)核會(huì)掃描對(duì)應(yīng)進(jìn)程的虛擬地址空間并報(bào)告內(nèi)存的使用情況,二進(jìn)制實(shí)例的每個(gè)唯一內(nèi)存范圍顯示一行。如表2 所示,展示的是 CockroachDB 第四個(gè)二進(jìn)制實(shí)例 numa_maps 的關(guān)鍵信息,兩個(gè)地址的代碼段存在位于 Node 2 的內(nèi)存。
表2 優(yōu)化前 CockroachDB 第四個(gè)二進(jìn)制實(shí)例 numa_maps 的關(guān)鍵信息
通過對(duì)操作系統(tǒng)內(nèi)核中頁緩存管理機(jī)制的研究,發(fā)現(xiàn)在該四個(gè)二進(jìn)制實(shí)例場(chǎng)景中,第一個(gè)綁定Node 2 和Node 3 的 CockroachDB 二進(jìn)制實(shí)例運(yùn)行后,CockroachDB 的代碼段進(jìn)入頁緩存(位于NUMA Node 2),從而在 Node 2 對(duì)應(yīng)的內(nèi)存命中,當(dāng)接下來第二至第四個(gè)二進(jìn)制實(shí)例在其他 NUMA Node 啟動(dòng)的時(shí)候,也需要CockroachDB 的代碼段,這時(shí)命中的依然是 Node 2 的代碼段。如圖2 所示,以一個(gè)搭載雙路處理器的服務(wù)器為例,CockroachDB 的代碼段位于 Node 0,其他三個(gè)進(jìn)程都各自有跨 Node 的代碼段內(nèi)存訪問,從而造成效率低下。造成這種現(xiàn)象的原因在于,Kylin 操作系統(tǒng)內(nèi)核中內(nèi)存上的頁緩存的管理機(jī)制是以索引節(jié)點(diǎn)(inode,index node)為單位的,索引節(jié)點(diǎn)是 UNIX 風(fēng)格文件系統(tǒng)中的一種數(shù)據(jù)結(jié)構(gòu),用于描述文件系統(tǒng)對(duì)象,每個(gè) inode存儲(chǔ)對(duì)象數(shù)據(jù)的屬性和磁盤塊位置,且 inode 以二進(jìn)制名稱作為唯一標(biāo)識(shí),在圖2 的情況下,以一個(gè)二進(jìn)制文件名稱啟動(dòng)四個(gè)進(jìn)程,則操作系統(tǒng)判定為同一個(gè) inode。一個(gè) inode(比如 CockroachDB 對(duì)應(yīng)的 inode)的頁緩存在內(nèi)存命中的情況下,內(nèi)核不會(huì)為每個(gè) Node 直接復(fù)制一份,導(dǎo)致在不同 Node 上啟動(dòng)的 CockroachDB 的頁緩存均在一個(gè) Node 上,造成其他 Node 訪問二進(jìn)制文件系統(tǒng)的頁緩存出現(xiàn)跨路,出現(xiàn)時(shí)延增加和降低數(shù)據(jù)庫(kù)運(yùn)行效率的現(xiàn)象。
圖2 跨路訪問示意圖
所提出的優(yōu)化方法具體是將默認(rèn)的一份CockroachDB 的二進(jìn)制文件拷貝成四份不同名稱的文件,這樣讓每個(gè)Node 申請(qǐng)連續(xù)內(nèi)存的時(shí)候,可以申請(qǐng)到本Node 的近地址內(nèi)存,不用到遠(yuǎn)端為代碼段申請(qǐng)內(nèi)存,從而提高I/O 的性能,示意圖如圖3 所示。
圖3 優(yōu)化后的代碼段訪問示意圖
通過查看優(yōu)化后同一個(gè)進(jìn)程的 numastat 和numa_maps 的關(guān)鍵信息,初步確認(rèn)了所提出方法的有效性。如表3 和表4 所示,內(nèi)存和代碼段均位于綁定的響應(yīng) Node 上。對(duì)于具體的試驗(yàn)結(jié)果,將在下一部分進(jìn)行討論。
表3 優(yōu)化后 CockroachDB 第四個(gè)進(jìn)程的內(nèi)存使用詳情
表4 優(yōu)化后 CockroachDB 第四個(gè)進(jìn)程numa_maps 的關(guān)鍵信息
為了驗(yàn)證所提出方法的有效性,本節(jié)主要介紹拆分二進(jìn)制實(shí)例的調(diào)優(yōu)方法在 PKS 體系下進(jìn)行評(píng)估。
本實(shí)驗(yàn)采用兩臺(tái)PKS 雙路服務(wù)器,整機(jī)共128 個(gè)CPU 核心,運(yùn)行內(nèi)存 512 GB,通過萬兆光纖直連的方式進(jìn)行通信。
實(shí)驗(yàn)采用一個(gè)基于 LuaJIT 的可編寫腳本的多線程基準(zhǔn)測(cè)試工具 sysbench。它最常用于數(shù)據(jù)庫(kù)基準(zhǔn)測(cè)試,sysbench 可以設(shè)置測(cè)試的線程、腳本等參數(shù)。在輸出結(jié)果方面,主要考察 sysbench 輸出的每秒事務(wù)數(shù)(Transactions Per Second,TPS),TPS 的大小反映數(shù)據(jù)庫(kù)的性能高低。測(cè)試場(chǎng)景選擇讀寫測(cè)試,這樣更貼合分布式數(shù)據(jù)庫(kù)實(shí)際應(yīng)用中的讀寫模擬。負(fù)載均衡選擇haproxy,這是一種流行的開源軟件 TCP/HTTP 負(fù)載均衡器和代理解決方案,可以在多系統(tǒng)上運(yùn)行。它最常見的用途是通過將工作負(fù)載分布到多個(gè)服務(wù)器(例如 Web、應(yīng)用程序、數(shù)據(jù)庫(kù))來提高服務(wù)器環(huán)境的性能和可靠性。實(shí)驗(yàn)采用的軟件詳細(xì)信息如表5 所示。
表5 實(shí)驗(yàn)采用的軟件一覽表
實(shí)驗(yàn)環(huán)境的拓?fù)浣Y(jié)構(gòu)如圖4 所示,測(cè)試需要兩臺(tái)服務(wù)器,其中一臺(tái)裝有 sysbench 和 haproxy,作為壓力機(jī),另一臺(tái)裝有四個(gè)實(shí)例的 CockroachDB 集群并創(chuàng)建一個(gè)名為 sysbench 的數(shù)據(jù)庫(kù),包含30 個(gè)表,每個(gè)表有5 000 000條數(shù)據(jù),每個(gè)實(shí)例的數(shù)據(jù)均位于一個(gè)單獨(dú)的 SSD 硬盤。測(cè)試前,確定好綁核策略,測(cè)試時(shí),裝有sysbench 的服務(wù)器通過萬兆光纖直連的方式向 CockroachDB 發(fā)送壓測(cè)命令,壓力機(jī)壓測(cè)5 次,每次90 s 的讀寫壓力測(cè)試。
圖4 實(shí)驗(yàn)環(huán)境拓?fù)鋱D
為了實(shí)驗(yàn)公平性,首先對(duì)照組 4 個(gè)實(shí)例使用同一個(gè)二進(jìn)制文件命名為 cockroach-21.1.9,每個(gè)用例綁定 16個(gè)CPU 核心,即兩個(gè) Node,且同時(shí)綁定內(nèi)存。綁定的詳細(xì)信息可查看表6 和表7。使用 sysbench 對(duì) CockroachDB 進(jìn)行4 組測(cè)試,每組分別并發(fā)32、64 和128 線程,觀察CPU 占用率和 numa_maps 信息、記錄 TPS 與平均時(shí)延,并且每輪測(cè)試前清除緩存。
表6 優(yōu)化前實(shí)例綁核詳情
表7 優(yōu)化后實(shí)例綁核詳情
圖5 和圖6 分別展示了優(yōu)化前后的 TPS 和 Lat 實(shí)驗(yàn)結(jié)果圖,實(shí)驗(yàn)先后進(jìn)行五輪,記錄第二輪至第五輪的數(shù)據(jù)每秒事務(wù)數(shù)和延遲(后文均分別用 TPS 和 Lat 表示),并取這四組數(shù)據(jù)的平均值,這樣的預(yù)熱操作是必要的,因?yàn)?CockroachDB 的最佳性能是在其各種緩存中填充了最相關(guān)的數(shù)據(jù)時(shí)實(shí)現(xiàn),同時(shí)從內(nèi)存讀取通常比磁盤讀取要快得多,所以經(jīng)過預(yù)熱后記錄的數(shù)據(jù)更加準(zhǔn)確。
圖6 優(yōu)化前后 Lat 對(duì)比圖
實(shí)驗(yàn)結(jié)果表明,在相同的綁核綁內(nèi)存策略下,拆分實(shí)例相較于不拆分實(shí)例,TPS 有顯著提升,提高范圍在1.7 至 1.8 倍。通過觀察監(jiān)控面板,拆分實(shí)例后數(shù)據(jù)庫(kù)的 CPU 使用率更為均衡,每個(gè)實(shí)例 CPU 使用率保持在1 000% 至 1 400%(每個(gè)實(shí)例綁定的 16 核)之間,相互間差值小于 200。而不拆分實(shí)例測(cè)得的 CPU 使用率較不均衡,每個(gè)實(shí)例 CPU 使用率在 800% 到 1 500% 之間,實(shí)例相互間差值較大且不穩(wěn)定。
通過查看 numa_maps 信息分析造成這種現(xiàn)象的原因,在數(shù)據(jù)庫(kù)進(jìn)行優(yōu)化前,四個(gè)實(shí)例同名且 inode 相同,實(shí)例代碼段先會(huì)被讀入最先執(zhí)行綁定 Node 對(duì)應(yīng)的內(nèi)存,其余的三個(gè)實(shí)例執(zhí)行需要跨 Node 跨路獲取代碼段信息,存在頻繁跨 Node 進(jìn)行數(shù)據(jù)交互的場(chǎng)景,從而CPU 使用率不均衡,性能較低。在進(jìn)行優(yōu)化后,將CockroachDB 二進(jìn)制文件復(fù)制成命名不同的四份,雖然內(nèi)容相同,但名稱不同且 inode 不同,實(shí)例代碼段分別被讀入綁定 Node 的對(duì)應(yīng)內(nèi)存中,從而CPU 使用率相對(duì)均衡,使得性能提升。
本文提出了基于 PKS 體系拆分 CockroachDB 二進(jìn)制實(shí)例的調(diào)優(yōu)方法,使得每個(gè)二進(jìn)制實(shí)例的代碼段能夠分布在被綁定相應(yīng)的 Node 上,從而降低跨 Node 訪問的性能損失。通過大量對(duì)比實(shí)驗(yàn)表明該方法能降低時(shí)延的同時(shí),顯著提升 CockroachDB 的性能。