在架構(gòu)上,TDSQL 的核心思想有兩個(gè):數(shù)據(jù)的復(fù)制(replica)和分片(sharding),其它都是由此衍生出來的。其中,
在金融行業(yè),銀行、風(fēng)控、渠道等第三方通常通過讀寫分離方式來查詢數(shù)據(jù),而在互聯(lián)網(wǎng)行業(yè),由于 x86 相對(duì)較高的故障率,導(dǎo)致數(shù)據(jù)可能經(jīng)常性的出現(xiàn)錯(cuò)亂、丟失場(chǎng)景。為了解決這個(gè)問題,就必須要求主從數(shù)據(jù)保持強(qiáng)一致和良好的讀寫分離策略。而其中的關(guān)鍵在于如何實(shí)現(xiàn)強(qiáng)同步復(fù)制技術(shù)。
由于 MySQL 的半同步和 Galera 模式不僅對(duì)性能的損耗是非常大的,而且數(shù)據(jù)同步有大量毛刺,這給金融業(yè)務(wù)同城雙中心或兩地三中心架構(gòu)容災(zāi)架構(gòu)帶來了極大的挑戰(zhàn)。為什么會(huì)這樣呢?
從 1996 年的 MySQL3.1.1.1 版本開始,業(yè)務(wù)數(shù)據(jù)庫通常跑在內(nèi)網(wǎng),網(wǎng)絡(luò)環(huán)境基本較好,因此 MySQL 采用的是每個(gè)連接一個(gè)線程的模型,這套模型最大的好處就是開發(fā)特別簡(jiǎn)單,線程內(nèi)部都是同步調(diào)用,只要不訪問外部接口,支撐每秒幾百上千的請(qǐng)求量也基本夠用,因?yàn)榇蟛糠智闆r下 IO 是瓶頸。
但隨著當(dāng)前硬件的發(fā)展,尤其是 ssd 等硬件出現(xiàn),IO 基本上不再是瓶頸,如再采用這套模型,并采用阻塞的方式調(diào)用延遲較大的外部接口,則 CPU 都會(huì)阻塞在網(wǎng)絡(luò)應(yīng)答上了,性能自然上不去。
為了解決這些問題,TDSQL 引入了線程池,將數(shù)據(jù)庫線程池模型 (執(zhí)行 SQL 的邏輯) 針對(duì)不同網(wǎng)絡(luò)環(huán)境進(jìn)行優(yōu)化,并支持組提交方案。例如,在 binlog 復(fù)制方案上將復(fù)制線程分解:
改造后, TDSQL 基本可以應(yīng)對(duì)復(fù)雜的網(wǎng)絡(luò)模型。
但上述方案還有小缺陷:當(dāng)主機(jī)故障,binlog 沒有來得及發(fā)送到遠(yuǎn)端,雖然此時(shí)不會(huì)返回給業(yè)務(wù)成功,備機(jī)上不存在這筆數(shù)據(jù),然而在主機(jī)故障自愈后,主機(jī)會(huì)多出來這筆事務(wù)的數(shù)據(jù)。解決方法是對(duì)新增的事務(wù)根據(jù) row 格式的 binlog 做閃回,這樣就有效解決了數(shù)據(jù)強(qiáng)一致的問題。
當(dāng)前大多數(shù)分布式數(shù)據(jù)庫都設(shè)計(jì)的是基于規(guī)則的查詢引擎 (RBO),這意味著,它有著一套嚴(yán)格的使用規(guī)則,只要你按照它去寫 SQL 語句,無論數(shù)據(jù)表中的內(nèi)容怎樣,也不會(huì)影響到你的“執(zhí)行計(jì)劃”,但這意味著該規(guī)則復(fù)雜的數(shù)據(jù)計(jì)算需求不“敏感”。雖然金融業(yè)務(wù)都有自己的數(shù)據(jù)倉(cāng)庫,然而也會(huì)經(jīng)常需要在 OLTP 類業(yè)務(wù)中執(zhí)行事務(wù)、Join 甚至批處理。
TDSQL 在 SQLENGINE 實(shí)現(xiàn)了基于代價(jià)的查詢引擎 (CBO),SQL 經(jīng)過 SQLENGINE 的詞法、語法解析、語義分析和 SQL 優(yōu)化之后,會(huì)生成分布式的查詢計(jì)劃,并根據(jù)數(shù)據(jù)路由策略(基于代價(jià)的查詢引擎)進(jìn)行下推計(jì)算,最后對(duì)匯總的數(shù)據(jù)返回給前端。
而作為分布式的計(jì)算引擎,在存儲(chǔ)與計(jì)算引擎相分離的情況下,非常重要的一環(huán)就是如何將計(jì)算盡量下推的下面的數(shù)據(jù)存儲(chǔ)層。因此 TDSQL 的 SQLENGINE 在經(jīng)過大量業(yè)務(wù)打磨后,實(shí)現(xiàn)了基于 shard key 下推、索引條件下推、驅(qū)動(dòng)表結(jié)果下推、null 下推、子查詢下推、left join 轉(zhuǎn)化成 inner join 等多達(dá) 18 種下推優(yōu)化手段,盡量降低數(shù)據(jù)在多個(gè)節(jié)點(diǎn)傳輸帶來的壓力,以提供更好的分布式查詢的能力,支撐金融交易的關(guān)聯(lián)操作。
如果說騰訊云數(shù)據(jù)庫歷史是一部從蟄伏到發(fā)展再到突破的歷史,那么可以說接下來 CynosDB 的推出,讓騰訊云數(shù)據(jù)庫迎來了新一輪云應(yīng)用場(chǎng)景下的突破與變遷。
2017 年,在騰訊云服務(wù)了百萬客戶之后,騰訊云數(shù)據(jù)庫迎來了突破。由開源數(shù)據(jù)庫適配業(yè)務(wù)和具體場(chǎng)景,騰訊云自主研發(fā)了一款真正的云原生數(shù)據(jù)庫CynosDB。作為騰訊云在數(shù)據(jù)庫領(lǐng)域的重要布局,CynosDB 單節(jié)點(diǎn)讀性能可以達(dá)到 130 萬 QPS,全面超越業(yè)內(nèi)目前最高的 100 萬 QPS 水平。它將傳統(tǒng)數(shù)據(jù)庫與云計(jì)算的優(yōu)勢(shì)相結(jié)合,解決了傳統(tǒng)數(shù)據(jù)庫云上的難題,其設(shè)計(jì)思路可以概括為以下幾點(diǎn):
這里需要重點(diǎn)說下計(jì)算和存儲(chǔ)分離。傳統(tǒng)數(shù)據(jù)庫的優(yōu)化演進(jìn)歷史,基本上是和IO 做斗爭(zhēng)的歷史,因?yàn)閿?shù)據(jù)庫是有狀態(tài)、重 IO 的服務(wù),傳統(tǒng) MySQL 架構(gòu)有多個(gè) IO 類型,存儲(chǔ)相同的文件,所以主機(jī)和備機(jī)的磁盤會(huì)有很多相同的 IO 和冗余的文件。即便數(shù)據(jù)庫被搬上云,為了在云上做彈性的擴(kuò)容,開發(fā)者依然面臨傳統(tǒng)數(shù)據(jù)庫所面臨的問題。
基于以上痛點(diǎn),CynosDB 引入計(jì)算存儲(chǔ)分離的架構(gòu),存儲(chǔ)層使用共享的分布式塊存儲(chǔ)云服務(wù),計(jì)算層則將不必要的 IO 全部卸載,實(shí)現(xiàn)計(jì)算與存儲(chǔ)基于日志傳輸?shù)男录軜?gòu)。
在新架構(gòu)中,日志處理無可厚非具有非常重要的作用。其中連續(xù)的日志在存儲(chǔ)層被打散成了很多的小的分片,分別存儲(chǔ)在不同的 cell 里。而日志處理的邏輯是將存儲(chǔ)引擎將日志發(fā)給存儲(chǔ)節(jié)點(diǎn),存儲(chǔ)節(jié)點(diǎn)將日志放到一個(gè)日志隊(duì)列里面,并將其持久化,之后立即返回給存儲(chǔ)引擎,當(dāng)存儲(chǔ)引擎獲得日志的反饋后就可以將一部分事務(wù)提交。其中,存儲(chǔ)節(jié)點(diǎn)會(huì)異步的進(jìn)行一些操作,這些操作和事務(wù)的提交過程無關(guān),不影響事務(wù)的提交響應(yīng)速度。
而在數(shù)據(jù)庫里面,如果 buffer 足夠的話,數(shù)據(jù)庫的寫性能是和日志的落盤時(shí)間相關(guān)的,傳統(tǒng)數(shù)據(jù)庫組提交機(jī)制可能存在幾個(gè)問題,一是如果有大量的連接進(jìn)來,MySQL 將會(huì)為每一個(gè)連接創(chuàng)建一個(gè)線程,如果用戶的業(yè)務(wù)沒有連接管理,那么將會(huì)存在頻繁的線程創(chuàng)建與銷毀,浪費(fèi)很多資源,同時(shí),大量并發(fā)線程的鎖沖突以及切換代價(jià)也會(huì)非常大。
針對(duì)以上問題,CynosDB 引入了線程池,直接解決了資源管理和線程切換的問題,但線程池只適合處理短任務(wù)。為此,CynosDB 同時(shí)引入了異步組提交的機(jī)制,基于線程池實(shí)現(xiàn),再增加獨(dú)立的日志寫線程 log writer,每一個(gè)工作線程提交事務(wù)的時(shí)候,并不是去做寫和刷的操作,而是將自己的請(qǐng)求提交到一個(gè)提交隊(duì)列里去,然后立即返回給 Server 層,以便釋放自己的線程資源。如果某一段日志持久化成功之后,log writer 會(huì)喚醒提交隊(duì)列里面等待的請(qǐng)求,將其重新調(diào)度到線程池的高優(yōu)先級(jí)隊(duì)列,重新獲得工作線程執(zhí)行事務(wù)提交后的工作。如此一來就能高效的利用線程池的資源,同時(shí)做到資源的控制,避免上下文頻繁切換帶來的性能問題。
日志下沉是什么意思?比如開發(fā)者在一個(gè)頁面做插入操作,生成的日志會(huì)放到日志管理子系統(tǒng)的日志 buffer 里,日志 buffer 的重用、刷新、并發(fā)管理等都是由數(shù)據(jù)庫來做。CynosDB 會(huì)把日志管理做成獨(dú)立模塊,并在 CynosStore Client 中實(shí)現(xiàn)。任何數(shù)據(jù)庫如果想接入這個(gè)系統(tǒng)的話,都不用去關(guān)心日志管理,直接調(diào)相關(guān)接口完成日志記錄即可。這里的日志和普通日志存在區(qū)別,比如 PG 的日志更偏向邏輯的概念,而 CynosDB 的日志,記錄的是物理修改(對(duì)某頁面的什么位置做了什么內(nèi)容的修改)。另外,日志向日志 buffer 的插入過程是并行的,若有 5 個(gè)用戶同時(shí)生成日志,往日志 buffer copy 都是并行進(jìn)行的而非串行。
總結(jié)來說,日志下沉是指 DB 層產(chǎn)生的日志都會(huì)放到 CynosStore Client 的 buffer 中,然后異步發(fā)送到分布式存儲(chǔ)中,而不是存到本地。而在分布式存儲(chǔ)中有一塊固定的存儲(chǔ)空間來專門存儲(chǔ)日志,由于空間大小固定,因此在 CynosStore 中會(huì)有特定的線程,定時(shí)地把日志異步地合并到數(shù)據(jù)頁面上,通過這種日志回收機(jī)制可以有效的利用日志空間,保證寫的連續(xù)性。
近日,騰訊云數(shù)據(jù)庫 CynosDB 正式亮相 MariaDB 用戶者大會(huì),并受到了 MariaDB 基金會(huì)以及眾多參會(huì)者的認(rèn)可。
與此同時(shí),騰訊云數(shù)據(jù)庫產(chǎn)品總監(jiān)王義成還向記者透露,今年 Q3,CynosDB 將會(huì)徹底完成商業(yè)化。CynosDB 的技術(shù)能力以及存儲(chǔ)層早已具備按使用量計(jì)費(fèi)的能力,計(jì)算層也正在進(jìn)行相應(yīng)的適配,待 CynosDB 商業(yè)化后將逐步推上日程。
由于 CynosDB 對(duì)主流開源數(shù)據(jù)庫的兼容,以及快速?gòu)椥陨?jí)、海量數(shù)據(jù)存儲(chǔ)等優(yōu)勢(shì),王義成稱,CynosDB 未來將持續(xù)落地應(yīng)用于包括互聯(lián)網(wǎng)及游戲等廣闊的行業(yè),幫助用戶更好地應(yīng)對(duì)業(yè)務(wù)高峰,加速業(yè)務(wù)創(chuàng)新。
從 2012 年到 2019 年,這七年,騰訊云數(shù)據(jù)庫無不見證、參與數(shù)據(jù)庫技術(shù)發(fā)展史上的一次次突破與迭代?;赝@段從開源到適配,從適配到自研的歷程,騰訊云可以說將每一次經(jīng)由業(yè)務(wù)適配考驗(yàn)后的思考、經(jīng)驗(yàn)都化作數(shù)據(jù)庫服務(wù)的“活水”,灌溉自身業(yè)務(wù)的同時(shí)也灌溉了開發(fā)者社區(qū)。
但值得注意的是,在長(zhǎng)達(dá)幾十年的時(shí)間里,由于國(guó)內(nèi)數(shù)據(jù)庫市場(chǎng)啟動(dòng)較晚,國(guó)外巨頭始終占據(jù)數(shù)據(jù)庫絕對(duì)領(lǐng)先優(yōu)勢(shì),使得國(guó)產(chǎn)數(shù)據(jù)庫的發(fā)展十分艱難。未來,由云原生技術(shù)帶來的一系列新技術(shù)與市場(chǎng)機(jī)遇,不僅僅是對(duì)數(shù)據(jù)庫管理員的挑戰(zhàn),也是對(duì)數(shù)據(jù)庫產(chǎn)品內(nèi)核與工具的考驗(yàn),接下來騰訊云數(shù)據(jù)庫“風(fēng)”往何處吹?且看“行云”。