国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

TiDB 源碼閱讀系列文章(十七)DDL 源碼解析

OpenDigg / 895人閱讀

摘要:需要把的元信息從中解析出來,做一些檢查,然后把的元信息持久化保存到中。主要做件事修改的元信息,把加入到的元信息中去。從隊列中取出,根據(jù)的類型調(diào)用函數(shù)。的狀態(tài)變?yōu)橹螅瑫{(diào)用將的元信息從上刪除。

DDL 是數(shù)據(jù)庫非常核心的組件,其正確性和穩(wěn)定性是整個 SQL 引擎的基石,在分布式數(shù)據(jù)庫中,如何在保證數(shù)據(jù)一致性的前提下實現(xiàn)無鎖的 DDL 操作是一件有挑戰(zhàn)的事情。本文首先會介紹 TiDB DDL 組件的總體設(shè)計,介紹如何在分布式場景下支持無鎖 shema 變更,描述這套算法的大致流程,然后詳細(xì)介紹一些常見的 DDL 語句的源碼實現(xiàn),包括 create tableadd indexdrop columndrop table 這四種。

DDL in TiDB

TiDB 的 DDL 通過實現(xiàn) Google F1 的在線異步 schema 變更算法,來完成在分布式場景下的無鎖,在線 schema 變更。為了簡化設(shè)計,TiDB 在同一時刻,只允許一個節(jié)點執(zhí)行 DDL 操作。用戶可以把多個 DDL 請求發(fā)給任何 TiDB 節(jié)點,但是所有的 DDL 請求在 TiDB 內(nèi)部是由 owner 節(jié)點的 worker 串行執(zhí)行的。

worker:每個節(jié)點都有一個 worker 用來處理 DDL 操作。

owner:整個集群中只有一個節(jié)點能當(dāng)選 owner,每個節(jié)點都可能當(dāng)選這個角色。當(dāng)選 owner 后的節(jié)點 worker 才有處理 DDL 操作的權(quán)利。owner 節(jié)點的產(chǎn)生是用 Etcd 的選舉功能從多個 TiDB 節(jié)點選舉出 owner 節(jié)點。owner 是有任期的,owner 會主動維護(hù)自己的任期,即續(xù)約。當(dāng) owner 節(jié)點宕機后,其他節(jié)點可以通過 Etcd 感知到并且選舉出新的 owner。

這里只是簡單概述了 TiDB 的 DDL 設(shè)計,下兩篇文章詳細(xì)介紹了 TiDB DDL 的設(shè)計實現(xiàn)以及優(yōu)化,推薦閱讀:

TiDB 的異步 schema 變更實現(xiàn) ?

TiDB 的異步 schema 變更優(yōu)化

下圖描述了一個 DDL 請求在 TiDB 中的簡單處理流程:

圖 1:TiDB 中 DDL SQL 的處理流程

TiDB 的 DDL 組件相關(guān)代碼存放在源碼目錄的 ddl 目錄下。

ddl owner 相關(guān)的代碼多帶帶放在 owner 目錄下,實現(xiàn)了 owner 選舉等功能。

另外,ddl job queuehistory ddl job queue 這兩個隊列都是持久化到 TiKV 中的。structure 目錄下有 list,hash 等數(shù)據(jù)結(jié)構(gòu)在 TiKV 上的實現(xiàn)。

本文接下來按照 TiDB 源碼的 origin/source-code 分支講解,最新的 master 分支和 source-code 分支代碼會稍有一些差異。

Create table

create table 需要把 table 的元信息(TableInfo)從 SQL 中解析出來,做一些檢查,然后把 table 的元信息持久化保存到 TiKV 中。具體流程如下:

語法解析:ParseSQL 解析成抽象語法樹 CreateTableStmt。

編譯生成 Plan:Compile 生成 DDL plan , 并 check 權(quán)限等。

生成執(zhí)行器:buildExecutor 生成 ?DDLExec 執(zhí)行器。TiDB 的執(zhí)行器是火山模型。

執(zhí)行器調(diào)用 e.Next 開始執(zhí)行,即 DDLExec.Next 方法,判斷 DDL 類型后執(zhí)行 executeCreateTable , 其實質(zhì)是調(diào)用 ddl_api.go 的 CreateTable 函數(shù)。

CreateTable 方法是主要流程如下:

會先 check 一些限制,比如 table name 是否已經(jīng)存在,table 名是否太長,是否有重復(fù)定義的列等等限制。

buildTableInfo 獲取 global table ID,生成 tableInfo , 即 table 的元信息,然后封裝成一個 DDL job,這個 job 包含了 table IDtableInfo,并將這個 job 的 type 標(biāo)記為 ActionCreateTable

d.doDDLJob(ctx, job) 函數(shù)中的 d.addDDLJob(ctx, job) 會先給 job 獲取一個 global job ID 然后放到 job queue 中去。

DDL 組件啟動后,在 start 函數(shù)中會啟動一個 ddl_worker 協(xié)程運行 onDDLWorker 函數(shù)(最新 Master 分支函數(shù)名已重命名為 start),每隔一段時間調(diào)用 handleDDLJobQueu 函數(shù)去嘗試處理 DDL job 隊列里的 job,ddl_worker 會先 check 自己是不是 owner,如果不是 owner,就什么也不做,然后返回;如果是 owner,就調(diào)用 getFirstDDLJob 函數(shù)獲取 DDL 隊列中的第一個 job,然后調(diào) runDDLJob 函數(shù)執(zhí)行 job。

runDDLJob 函數(shù)里面會根據(jù) job 的類型,然后調(diào)用對應(yīng)的執(zhí)行函數(shù),對于 create table 類型的 job,會調(diào)用 onCreateTable 函數(shù),然后做一些 check 后,會調(diào)用 t.CreateTable 函數(shù),將 db_ID 和?table_ID 映射為 keytableInfo 作為 value 存到 TiKV 里面去,并更新 job 的狀態(tài)。

finishDDLJob 函數(shù)將 job 從 DDL job 隊列中移除,然后加入 history ddl job 隊列中去。

doDDLJob 函數(shù)中檢測到 history DDL job 隊列中有對應(yīng)的 job 后,返回。

Add index

add index 主要做 2 件事:

修改 table 的元信息,把 indexInfo 加入到 table 的元信息中去。

把 table 中已有了的數(shù)據(jù)行,把 index columns 的值全部回填到 index record 中去。

具體執(zhí)行流程的前部分的 SQL 解析、Compile 等流程,和 create table 一樣,可以直接從 DDLExec.Next 開始看,然后調(diào)用 alter 語句的 e.executeAlterTable(x) 函數(shù),其實質(zhì)調(diào) ddl 的 AlterTable 函數(shù),然后調(diào)用 CreateIndex 函數(shù),開始執(zhí)行 add index 的主要工作,具體流程如下:

Check 一些限制,比如 table 是否存在,索引是否已經(jīng)存在,索引名是否太長等。

封裝成一個 job,包含了索引名,索引列等,并將 job 的 type 標(biāo)記為 ActionAddIndex

給 job 獲取一個 global job ID 然后放到 DDL job 隊列中去。

owner ddl worker 從 DDL job 隊列中取出 job,根據(jù) job 的類型調(diào)用 onCreateIndex 函數(shù)。

buildIndexInfo 生成 indexInfo,然后更新 tableInfo 中的 Indices,持久化到 TiKV 中去。

這里引入了 online schema change 的幾個步驟,需要留意 indexInfo 的狀態(tài)變化:none -> delete only -> write only -> reorganization -> ?public。在 reorganization -> public 時,首先調(diào)用 getReorgInfo 獲取 reorgInfo,主要包含需要 reorganization 的 range,即從表的第一行一直到最后一行數(shù)據(jù)都需要回填到 index record 中。然后調(diào)用 runReorgJob , addTableIndex 函數(shù)開始填充數(shù)據(jù)到 index record中去。runReorgJob 函數(shù)會定期保存回填數(shù)據(jù)的進(jìn)度到 TiKV。addTableIndex 的流程如下:

啟動多個 worker 用于并發(fā)回填數(shù)據(jù)到 index record

reorgInfo 中需要 reorganization 分裂成多個 range。掃描的默認(rèn)范圍是 [startHandle , endHandle],然后默認(rèn)以 128 為間隔分裂成多個 range,之后并行掃描對應(yīng)數(shù)據(jù)行。在 master 分支中,range 范圍信息是從 PD 中獲取。

把 range 包裝成多個 task,發(fā)給 worker 并行回填 index record

等待所有 worker 完成后,更新 reorg 進(jìn)度,然后持續(xù)第 3 步直到所有的 task 都做完。

后續(xù)執(zhí)行 finishDDLJob,檢測 history ddl job?流程和 create table 類似。

Drop Column

drop Column 只要修改 table 的元信息,把 table 元信息中對應(yīng)的要刪除的 column 刪除。drop Column 不會刪除原有 table 數(shù)據(jù)行中的對應(yīng)的 Column 數(shù)據(jù),在 decode 一行數(shù)據(jù)時,會根據(jù) table 的元信息來 decode。

具體執(zhí)行流程的前部分都類似,直接跳到 DropColumn 函數(shù)開始,具體執(zhí)行流程如下:

Check table 是否存在,要 drop 的 column 是否存在等。

封裝成一個 job, 將 job 類型標(biāo)記為 ActionDropColumn,然后放到 DDL job 隊列中去

owner ddl worker 從 DDL job 隊列中取出 job,根據(jù) job 的類型調(diào)用 onDropColumn 函數(shù):

這里 column info 的狀態(tài)變化和 add index 時的變化幾乎相反:public -> write only -> delete only -> reorganization -> absent

updateVersionAndTableInfo 更新 table 元信息中的 Columns。

后續(xù)執(zhí)行 finishDDLJob,檢測 history ddl job 流程和 create table 類似。

Drop table

drop table 需要刪除 table 的元信息和 table 中的數(shù)據(jù)。

具體執(zhí)行流程的前部分都類似,owner ddl worker 從 DDL job 隊列中取出 job 后執(zhí)行 onDropTable 函數(shù):

tableInfo 的狀態(tài)變化是:public -> write only -> delete only -> none

tableInfo 的狀態(tài)變?yōu)?none 之后,會調(diào)用 ?DropTable 將 table 的元信息從 TiKV 上刪除。

至于刪除 table 中的數(shù)據(jù),后面在調(diào)用 finishDDLJob 函數(shù)將 job 從 job queue 中移除,加入 history ddl job queue 前,會調(diào)用 delRangeManager.addDelRangeJob(job),將要刪除的 table 數(shù)據(jù)范圍插入到表 gc_delete_range 中,然后由 GC worker 根據(jù) gc_delete_range 中的信息在 GC 過程中做真正的刪除數(shù)據(jù)操作。

New Parallel DDL

目前 TiDB 最新的 Master 分支的 DDL 引入了并行 DDL,用來加速多個 DDL 語句的執(zhí)行速度。因為串行執(zhí)行 DDL 時,add index 操作需要把 table 中已有的數(shù)據(jù)回填到 index record 中,如果 table 中的數(shù)據(jù)較多,回填數(shù)據(jù)的耗時較長,就會阻塞后面 DDL 的操作。目前并行 DDL 的設(shè)計是將 add index job 放到新增的 add index job queue 中去,其它類型的 DDL job 還是放在原來的 job queue。相應(yīng)的,也增加一個 add index worker 來處理 add index job queue 中的 job。

圖 2:并行 DDL 處理流程

并行 DDL 同時也引入了 job 依賴的問題。job 依賴是指同一 table 的 DDL job,job ID 小的需要先執(zhí)行。因為對于同一個 table 的 DDL 操作必須是順序執(zhí)行的。比如說,add column a,然后 add index on column a, 如果 add index 先執(zhí)行,而 add column 的 DDL 假設(shè)還在排隊未執(zhí)行,這時 add index on column a 就會報錯說找不到 column a。所以當(dāng) add index job queue 中的 job2 執(zhí)行前,需要檢測 job queue 是否有同一 table 的 job1 還未執(zhí)行,通過對比 job 的 job ID 大小來判斷。執(zhí)行 job queue 中的 job 時也需要檢查 add index job queue 中是否有依賴的 job 還未執(zhí)行。

End

TiDB 目前一共支持 十多種 DDL,具體以及和 MySQL 兼容性對比可以看 這里。剩余其它類型的 DDL 源碼實現(xiàn)讀者可以自行閱讀,流程和上述幾種 DDL 類似。

作者:陳霜

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/17776.html

相關(guān)文章

  • DM 源碼閱讀系列文章(一)序

    摘要:內(nèi)容概要源碼閱讀系列將會從兩條線進(jìn)行展開,一條是圍繞的系統(tǒng)架構(gòu)和重要模塊進(jìn)行分析,另一條線圍繞內(nèi)部的同步機制展開分析。更多的代碼閱讀內(nèi)容會在后面的章節(jié)中逐步展開,敬請期待。 作者:楊非 前言 TiDB-DM 是由 PingCAP 開發(fā)的一體化數(shù)據(jù)同步任務(wù)管理平臺,支持從 MySQL 或 MariaDB 到 TiDB 的全量數(shù)據(jù)遷移和增量數(shù)據(jù)同步,在 TiDB DevCon 2019 正...

    Mr_houzi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<