<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          輪子這么多,為什么我們選擇自己造一個(gè)NewSQL?

          共 6177字,需瀏覽 13分鐘

           ·

          2020-07-27 19:34

          點(diǎn)擊“開發(fā)者技術(shù)前線”,選擇“星標(biāo)?”

          在看|星標(biāo)|留言,? 真愛

          作者丨李鑫
          來源丨滴滴技術(shù)(ID:didi_tech)



          一、背景


          Fusion-NewSQL是由滴滴自研的在分布式KV存儲(chǔ)基礎(chǔ)上構(gòu)建的NewSQL存儲(chǔ)系統(tǒng)。Fusion-NewSQ兼容了MySQL協(xié)議,支持二級(jí)索引功能,提供超大規(guī)模數(shù)據(jù)持久化存儲(chǔ)和高性能讀寫。


          我們的問題


          滴滴的業(yè)務(wù)快速持續(xù)發(fā)展,數(shù)據(jù)量和請(qǐng)求量急劇增長,對(duì)存儲(chǔ)系統(tǒng)等壓力與日俱增。雖然分庫分表在一定程度上可以解決數(shù)據(jù)量和請(qǐng)求增加的需求,但是由于滴滴多條業(yè)務(wù)線(快車、專車、兩輪車等)的業(yè)務(wù)快速變化,數(shù)據(jù)庫加字段加索引的需求非常頻繁,分庫分表方案對(duì)于頻繁的Schema變更操作并不友好,會(huì)導(dǎo)致DBA任務(wù)繁重,變更周期長,并且對(duì)巨大的表操作還會(huì)對(duì)線上有一定影響。同時(shí),分庫分表方案對(duì)二級(jí)索引支持不友好或者根本不支持。鑒于上述情況,NewSQL數(shù)據(jù)庫方案就成為我們解決業(yè)務(wù)問題的一個(gè)方向。


          開源產(chǎn)品調(diào)研


          最開始,我們調(diào)研了開源的分布式NewSQL方案TiDB。雖然TiDB是非常優(yōu)秀的NewSQL產(chǎn)品,但是對(duì)于我們的業(yè)務(wù)場(chǎng)景來說,TiDB并不是非常適合,原因如下:


          • 我們需要一款高吞吐,低延遲的數(shù)據(jù)庫解決方案,但是TiDB由于要滿足事務(wù),2pc方案天然無法滿足低延遲(100ms以內(nèi)的99rt,甚至50ms內(nèi)的99rt)。

          • 我們的多數(shù)業(yè)務(wù),并不真正需要分布式事務(wù),或者說可以通過其他補(bǔ)償機(jī)制,繞過分布式事務(wù)。這是由于業(yè)務(wù)場(chǎng)景決定的。

          • TiDB三副本的存儲(chǔ)空間成本相對(duì)比較高。

          • 我們內(nèi)部一些離線數(shù)據(jù)導(dǎo)入在線系統(tǒng)的場(chǎng)景,不能直接和TiDB打通。


          基于以上原因,我們開啟了自研符合自己業(yè)務(wù)需求的NewSQL之路。


          我們的基礎(chǔ)


          我們并沒有打算從0開發(fā)一個(gè)完備的NewSQL系統(tǒng),而是在自研的分布式KV存儲(chǔ)Fusion的基礎(chǔ)上構(gòu)建一個(gè)能滿足我們業(yè)務(wù)場(chǎng)景的NewSQL。Fusion是采用了Codis架構(gòu),兼容Redis協(xié)議和數(shù)據(jù)結(jié)構(gòu),使用RocksDB作為存儲(chǔ)引擎的NoSQL數(shù)據(jù)庫。Fusion在滴滴內(nèi)部已經(jīng)有幾百個(gè)業(yè)務(wù)在使用,是滴滴主要的在線存儲(chǔ)之一。


          Fusion的架構(gòu)圖如下:



          我們采用hash分片的方式來做數(shù)據(jù)sharding。從上往下看,用戶通過Redis協(xié)議的客戶端就可以訪問Fusion,用戶的訪問請(qǐng)求發(fā)到proxy,再由proxy轉(zhuǎn)發(fā)數(shù)據(jù)到后端Fusion的數(shù)據(jù)節(jié)點(diǎn)。proxy到后端數(shù)據(jù)節(jié)點(diǎn)的轉(zhuǎn)發(fā),是根據(jù)請(qǐng)求的key計(jì)算hash值,然后對(duì)slot分片數(shù)取余,得到一個(gè)固定的slotid,每個(gè)slotid會(huì)固定的映射到一個(gè)存儲(chǔ)節(jié)點(diǎn),以此解決數(shù)據(jù)路由問題。


          有了一個(gè)高并發(fā),低延遲,大容量的存儲(chǔ)層后,我們要做的就是在之上構(gòu)建MySQL協(xié)議以及二級(jí)索引。那么如何將MySQL的數(shù)據(jù)格式轉(zhuǎn)成Redis的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)就是我們必須面臨的問題,后面會(huì)詳細(xì)說。


          二、需求



          綜合考慮大多數(shù)用戶對(duì)需求,我們整理了我們的NewSQL需要提供的幾個(gè)核心能力:


          • 高吞吐,低延遲,大容量。

          • 兼容MySQL協(xié)議及下游生態(tài)。

          • 支持主鍵查詢和二級(jí)索引查詢。

          • Schema變更靈活,不影響線上服務(wù)穩(wěn)定性。


          三、架構(gòu)設(shè)計(jì)


          Fusion-NewSQL由下面幾個(gè)部分組成:


          • 解析MySQL協(xié)議的DiseServer;

          • 存儲(chǔ)數(shù)據(jù)的Fusion集群-Data集群;

          • 存儲(chǔ)索引信息的Fusion集群-Index集群;

          • 負(fù)責(zé)Schema的管理配置中心-ConfigServer;

          • 異步構(gòu)建索引程序-Consumer負(fù)責(zé)消費(fèi)Data集群寫到MQ中的MySQL-Binlog格式數(shù)據(jù),根據(jù)schema信息,生成索引數(shù)據(jù)寫入Index集群;

          • 外部依賴,MQ,Zookeeper。


          架構(gòu)圖如下:



          四、詳細(xì)設(shè)計(jì)


          存儲(chǔ)結(jié)構(gòu)


          MySQL的表結(jié)構(gòu)數(shù)據(jù)如何轉(zhuǎn)成Redis的數(shù)據(jù)結(jié)構(gòu)是我們面臨的第一個(gè)問題。


          如下圖:



          我們將MySQL表的一行記錄轉(zhuǎn)成Redis的一個(gè)Hashmap結(jié)構(gòu)。Hashmap的key由表名+主鍵值組成,滿足了全局唯一的特性。下圖展示了MySQL通過主鍵查詢轉(zhuǎn)換為Redis協(xié)議的方式:



          除了數(shù)據(jù),索引也需要存儲(chǔ)在Fusion-NewSQL中,和數(shù)據(jù)存成hashmap不同,索引存儲(chǔ)成key-value結(jié)構(gòu)。根據(jù)索引類型不同,組成key-value的格式還有一點(diǎn)細(xì)微的差別(下面的格式為了看起來直觀,實(shí)際上分隔符,indexname都是做過編碼的):


          唯一索引:

          Key:?

          table_indexname_indexColumnsValue?

          Value: Rowkey


          非唯一索引:

          Key:?

          table_indexname_indexColumnsValue_Rowkey?

          Value:null


          造成這種差異的原因就是非唯一索引在加入Rowkey之前的部分是有可能重復(fù)的,無法全局唯一。另外,唯一索引不將Rowkey編碼在key中,是因?yàn)樵诓樵冋Z句是單純的“=”查詢的時(shí)候直接get操作就可以找到對(duì)應(yīng)的Rowkey內(nèi)容,而不需要通過scan,這樣的效率更高。



          后面會(huì)在查詢流程中重點(diǎn)講述如何通過二級(jí)索引查詢到數(shù)據(jù)。


          數(shù)據(jù)讀寫流程


          1)數(shù)據(jù)寫入


          • 用戶通過MySQL-sdk將協(xié)議發(fā)給dise-server;

          • dise-server根據(jù)schema對(duì)用戶寫入的SQL做校驗(yàn);

          • dise-server將校驗(yàn)通過的SQL轉(zhuǎn)成Redis的Hashmap結(jié)構(gòu),通過Redis協(xié)議發(fā)給Data集群;

          • Data集群將數(shù)據(jù)寫入wal文件,并將數(shù)據(jù)存儲(chǔ)rocksdb;

          • Data集群后臺(tái)線程將wal文件消費(fèi),轉(zhuǎn)成MySQL-Binlog格式。將數(shù)據(jù)發(fā)到MQ;

          • 異步索引模塊消費(fèi)MQ,將MySQL-Binlog根據(jù)操作類型(insert,update,delete)配合schema信息,構(gòu)建索引信息,并將索引數(shù)據(jù)寫入index集群。


          通過上面的鏈路,用戶的一條MySQL寫操作就完成了數(shù)據(jù)存儲(chǔ)和索引構(gòu)建。由于通過數(shù)據(jù)構(gòu)建索引這一步是通過MQ異步完成,所以會(huì)存在數(shù)據(jù)和索引有一定的時(shí)間差的情況。


          2)查詢


          下面是一個(gè)使用二級(jí)索引查詢數(shù)據(jù)的案例:


          • dise-server接收到SQL查詢,根據(jù)條件,選擇索引,如果沒有命中任何索引,給用戶返回錯(cuò)誤(Fusion-NewSQL不能以非索引字段作為查詢條件)。

          • 根據(jù)選中的索引,構(gòu)建查詢范圍,通過scan命令遍歷Index集群,獲取符合條件的主鍵集合。下圖以一個(gè)SQL查詢,展示使用scan遍歷二級(jí)索引的例子:



          • 根據(jù)主鍵,通過hgetall命令向Data集群查詢符合條件的結(jié)果集。

          • 將結(jié)果集構(gòu)建成MySQL的結(jié)果返回給用戶。


          根據(jù)上面索引數(shù)據(jù)的格式可以看到,scan范圍的時(shí)候,前綴必須固定,映射到SQL語句到時(shí)候,意味著where到條件中,范圍查詢只能有一個(gè)字段,而不能多個(gè)字段。比如:



          索引是age和name兩個(gè)字段的聯(lián)合索引。如果查詢語句如下:



          select * from student where age > 20 and name >‘W’;


          scan就沒有辦法確定前綴,也就無法通過index_age_name這個(gè)索引查詢到滿足條件的數(shù)據(jù),所以使用KV形式存儲(chǔ)到索引只能滿足where條件中有一個(gè)字段是范圍查詢。當(dāng)然可以通過將聯(lián)合索引分開存放,多次交互搜索取交集的方式解決,但是這就和我們降低RPC次數(shù),降低延遲的設(shè)計(jì)初衷相違背了。為了解決這個(gè)問題,我們引入了Elastic Search搜索引擎,這部分后面會(huì)詳細(xì)說明。


          Schema變更


          用戶涉及Schema變更時(shí),會(huì)以工單形式發(fā)給管控系統(tǒng)。管控系統(tǒng)審批過后,會(huì)將變更請(qǐng)求推給配置中心,配置中心進(jìn)行安全性檢查后,將新的Schema寫入到存儲(chǔ)中,并給各個(gè)節(jié)點(diǎn)推送變更。


          字段變更:


          節(jié)點(diǎn)接收到推送,更新本地的Schema。對(duì)于歷史數(shù)據(jù),并不真正去修改數(shù)據(jù),而是在查詢的時(shí)候,根據(jù)Schema信息匹配字段,如果數(shù)據(jù)比Schema缺失某些字段,就使用默認(rèn)值代替;如果數(shù)據(jù)比Schema多了字段,就隱藏掉多余字段不展示。


          新增索引分為兩步處理:


          • 新增索引,歷史數(shù)據(jù)不處理,增量數(shù)據(jù)立刻走索引構(gòu)建流程。

          • 通過歷史索引構(gòu)建工具,掃描歷史數(shù)據(jù),構(gòu)建新索引的KV,將歷史數(shù)據(jù)完成索引構(gòu)建。這里有個(gè)優(yōu)化點(diǎn),掃描slave而不是master,避免對(duì)線上產(chǎn)生影響。


          五、生態(tài)構(gòu)建


          一個(gè)單獨(dú)的存儲(chǔ)產(chǎn)品解決所有問題的時(shí)代早已經(jīng)過去,數(shù)據(jù)孤島是沒有辦法很好服務(wù)業(yè)務(wù)的,F(xiàn)usion-NewSQL從設(shè)計(jì)的那天起就考慮了和其他存儲(chǔ)系統(tǒng)的打通。


          Fusion-NewSQL到其他存儲(chǔ)系統(tǒng)


          Fusion-NewSQL通過兼容MySQL的Binlog格式,將數(shù)據(jù)發(fā)到MQ中。下游各個(gè)系統(tǒng)凡是能接入MySQL數(shù)據(jù)的,都可以通過消費(fèi)MQ中相同格式的Fusion-NewSQL數(shù)據(jù),將數(shù)據(jù)存到其他系統(tǒng)中。這樣的方式用最小的工作量最大程度做到了兼容。


          Hive到Fusion-NewSQL


          Fusion-NewSQL還支持將離線的Hive表中的數(shù)據(jù)通過Fusion-NewSQL提供的FastLoad(DTS)工具,將Hive表數(shù)據(jù)轉(zhuǎn)入到Fusion-NewSQL,滿足離線數(shù)據(jù)到在線的數(shù)據(jù)流動(dòng)。


          如果用戶自己完成數(shù)據(jù)流轉(zhuǎn),一般會(huì)掃描Hive表,然后構(gòu)建MySQL的寫入語句,一條條將數(shù)據(jù)寫入到Fusion-NewSQL,流程如下面這樣:



          • MySQL-client將寫請(qǐng)求發(fā)給DiseServer。

          • DiseServer將MySQL寫做解析,轉(zhuǎn)成hashmap將轉(zhuǎn)換后的數(shù)據(jù)以Redis協(xié)議發(fā)給Data集群。

          • Data集群的存儲(chǔ)節(jié)點(diǎn)收到數(shù)據(jù),將數(shù)據(jù)寫到wal文件。

          • Data集群的存儲(chǔ)節(jié)點(diǎn)走RocksDB的寫流程,這里包括了寫memtable,還有可能memtable寫滿,發(fā)生flush以及觸發(fā)后臺(tái)的compact。

          • 異步線程消費(fèi)wal,將數(shù)據(jù)構(gòu)建MySQL-Binlog格式發(fā)到MQ。

          • 異步索引程序消費(fèi)MySQL-Binlog,構(gòu)建Index集群需要的數(shù)據(jù),向Index集群發(fā)送寫入請(qǐng)求。

          • Index集群的存儲(chǔ)節(jié)點(diǎn)寫wal。

          • Index集群的存儲(chǔ)節(jié)點(diǎn)進(jìn)入RocksDB的寫流程。


          從上面的流程可以看出這種遷移方式有幾個(gè)痛點(diǎn):


          • 有這種Hive到Fusion-NewSQL數(shù)據(jù)導(dǎo)入需求的用戶都需要開發(fā)一套相同邏輯的代碼,維護(hù)成本高。

          • 每條Hive數(shù)據(jù)都要經(jīng)過較長鏈路,數(shù)據(jù)導(dǎo)入耗時(shí)較長。

          • 離線平臺(tái)的數(shù)據(jù)量大,吞吐高,直接大幅提升在線系統(tǒng)的QPS,對(duì)在線系統(tǒng)的穩(wěn)定性有較大影響。


          基于上述的痛點(diǎn),我們?cè)O(shè)計(jì)了Fastload數(shù)據(jù)導(dǎo)入平臺(tái),通過約定Hive到Fusion-NewSQL的表格式,使用Hadoop并發(fā)處理數(shù)據(jù),并構(gòu)建RocksDB能識(shí)別的sst存儲(chǔ)文件,繞過復(fù)雜的DISE寫鏈路,直接將數(shù)據(jù)導(dǎo)入到Fusion-NewSQL中,流程如下:



          • 用戶填寫工單,選中將指定Hive表的某些字段映射為Fusion-NewSQL表的字段(這里可以Hive中多個(gè)字段組成一個(gè)Fusion-NewSQL字段)。

          • Hadoop遍歷Hive表,并且通過Zookeeper獲取數(shù)據(jù)應(yīng)該存放在Data集群和Index集群的路由信息。

          • 通過上面的遍歷,計(jì)算,之后,將數(shù)據(jù)直接構(gòu)建成、Rocksdb能識(shí)別的sst,并且其中存的數(shù)據(jù)已經(jīng)是按DISE的表結(jié)構(gòu)信息組成的KV數(shù)據(jù)。

          • 將sst文件直接發(fā)送到指定的存儲(chǔ)節(jié)點(diǎn),存儲(chǔ)節(jié)點(diǎn)或通過Rocksdb提供的ingest功能,直接將sst文件加載到Fusion-NewSQL中,用戶可以讀到。


          這個(gè)方案避免了冗長復(fù)雜的寫鏈路,同時(shí)不會(huì)增加系統(tǒng)的QPS,在磁盤和網(wǎng)絡(luò)IO沒有達(dá)到瓶頸的情況下對(duì)線上訪問幾乎是沒有任何影響;同時(shí),用戶只需要填寫Hive到Fusion-NewSQL的Schema映射關(guān)系即可,不必再關(guān)心實(shí)現(xiàn)。


          通過ElasticSearch實(shí)現(xiàn)復(fù)雜查詢


          在業(yè)務(wù)使用MySQL或Fusion-NewSQL的過程中,我們發(fā)現(xiàn)有這樣一種場(chǎng)景:業(yè)務(wù)的查詢條件很復(fù)雜,涉及的字段數(shù),條件,聚合都比較多,這種場(chǎng)景下,業(yè)務(wù)會(huì)選擇將ElasticSearch作為MySQL或Fusion-NewSQL的下游,將數(shù)據(jù)導(dǎo)入Elastic Search,然后通過ElasticSearch豐富的搜索能力,先從ElasticSearch中獲取數(shù)據(jù)在MySQL或Fusion-NewSQL的主鍵,然后再根據(jù)主鍵獲取全部數(shù)據(jù)。


          根據(jù)上面的場(chǎng)景,F(xiàn)usion-NewSQL提供一個(gè)特殊的索引類型:ES。用戶在創(chuàng)建索引的時(shí)候,可以將需要做復(fù)雜查詢的字段勾選出來,共同構(gòu)建成一個(gè)ES索引,這樣既滿足了業(yè)務(wù)需求,避免了每個(gè)業(yè)務(wù)都需要開發(fā)一套和ElasticSearch交互的復(fù)雜邏輯,又統(tǒng)一了數(shù)據(jù)庫使用接口都為MySQL。同時(shí),還彌補(bǔ)了前面提到的Fusion-NewSQL的KV二級(jí)索引不能支持多個(gè)字段范圍檢索的能力。


          架構(gòu)圖如下:



          ES索引只是在上圖紅4處,將ES索引中包含的字段信息和主鍵寫入到ElasticSearch中。在查詢時(shí)綠1如果選中了ES類型的索引,就根據(jù)where條件中涉及的字段,組裝成ElasticSearch的DSL語句,從ElasticSearch獲取主鍵,再從Data集群獲取。由于ElasticSearch查詢的延遲比較慢,F(xiàn)usion-NewSQL可以支持一張表的多個(gè)索引采用KV索引和ES索引并存,對(duì)于延遲要求高,查詢條件相對(duì)簡(jiǎn)單的使用KV索引;對(duì)于查詢條件復(fù)雜,延遲要求不高的使用ES索引。


          六、總結(jié)


          Fusion-NewSQL當(dāng)前已經(jīng)接入訂單、預(yù)估、賬單、用戶中心、交易引擎等70個(gè)核心業(yè)務(wù),總QPS超過200W,總數(shù)據(jù)超過600TB。



          當(dāng)然,F(xiàn)usion-New不是一個(gè)通用完備的NewSQL方案,而是在已有的NoSQL數(shù)據(jù)庫基礎(chǔ)上,通過對(duì)SQL協(xié)議的支持以及組合各種組件,構(gòu)建一個(gè)對(duì)外表達(dá)的數(shù)據(jù)庫,但是這種方式,可以以最小的開發(fā)代價(jià),滿足大多數(shù)的業(yè)務(wù)場(chǎng)景,具備較高的投入產(chǎn)出比。?


          七、后續(xù)工作


          • 有限制的事物支持,比如讓業(yè)務(wù)規(guī)劃落在一個(gè)節(jié)點(diǎn)的數(shù)據(jù)可以支持單機(jī)跨行事務(wù)。

          • 實(shí)時(shí)索引替代異步索引,滿足即寫即讀。目前已經(jīng)有一個(gè)寫穿+補(bǔ)償機(jī)制的方案,在沒有分布式事務(wù)的前提下滿足正常狀態(tài)的實(shí)時(shí)索引,異常情況下保證數(shù)據(jù)索引最終一致的方案。

          • 更多的SQL協(xié)議和功能支持。


          作者介紹

          李鑫,滴滴資深軟件開發(fā)工程師,多年分布式存儲(chǔ)領(lǐng)域設(shè)計(jì)及開發(fā)經(jīng)驗(yàn)。曾參與NoSQL/NewSQL數(shù)據(jù)庫Fusion、分布式時(shí)序數(shù)據(jù)庫sentry、NewSQL數(shù)據(jù)庫SDB等系統(tǒng)的設(shè)計(jì)開發(fā)工作。




          END



          前線推出學(xué)習(xí)交流一定要備注:研究/工作方向+地點(diǎn)+學(xué)校/公司+昵稱(如大數(shù)據(jù)+上海+上交+卡卡),根據(jù)格式備注,可更快被通過且邀請(qǐng)進(jìn)群

          掃碼加我微信和大佬們零距離

          好文點(diǎn)個(gè)在看吧!
          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黑人下面太大我高潮了 | 三级网站在线视频 | 91福利在线观看 | 人人综合网 | 玩熟女五十AV一二三区 |