tidb是go語言麼

2022-12-02 22:01:44

是,TiDB採用go語言編寫。TiDB是一個分散式NewSQL資料庫;它支援水平彈性擴充套件、ACID事務、標準SQL、MySQL語法和MySQL協定,具有資料強一致的高可用特性。TiDB架構中的PD儲存了叢集的元資訊,如key在哪個TiKV節點;PD還負責叢集的負載均衡以及資料分片等。PD通過內嵌etcd來支援資料分佈和容錯;PD採用go語言編寫。

php入門到就業線上直播課:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

Go 語言不少重量級專案,而國內最牛逼的 Go 開源專案應該就是 TiDB 了吧。TiDB 是一個分散式資料庫,很多人可能對此一無所知。今天就跟大家聊聊這個話題。

TiDB設計簡單,官網和程式碼都非常易讀,是學習分散式資料庫的首選開源專案。

資料庫、作業系統和編譯器並稱為三大系統,可以說是整個計算機軟體的基石。

很多人用過資料庫,但是很少有人實現過一個資料庫,特別是實現一個分散式資料庫。瞭解資料庫的實現原理和細節,一方面可以提高個人技術,對構建其他系統有幫助,另一方面也有利於用好資料庫。

一、TiDB簡介

TiDB是一個分散式 NewSQL 資料庫。它支援水平彈性擴充套件、ACID 事務、標準 SQL、MySQL 語法和 MySQL 協定,具有資料強一致的高可用特性,是一個不僅適合 OLTP 場景還適合 OLAP 場景的混合資料庫

OLTP:On-Line Transaction Processing,聯機事務處理
OLAP:On-Line Analytical Processing,聯機分析處理

  • 高度相容 MySQL 5.7

TiDB 高度相容 MySQL 5.7 協定、MySQL 5.7 常用的功能及語法。雖然 TiDB 支援 MySQL 語法和協定,但是 TiDB 是由 PingCAP 團隊完全自主開發的產品,並非基於MySQL開發。

MySQL 5.7 生態中的系統工具 (PHPMyAdmin、Navicat、MySQL Workbench、mysqldump、Mydumper、Myloader)、使用者端等均適用於 TiDB。

TiDB 目前還不支援觸發器、儲存過程、自定義函數、外來鍵。

  • 易用性

TiDB 使用起來很簡單,可以將 TiDB 叢集當成 MySQL 來用,可以將 TiDB 用在任何以 MySQL 作為後臺儲存服務的應用中,並且基本上不需要修改應用程式碼,同時可以用大部分流行的 MySQL 管理工具來管理 TiDB。

只要支援 MySQL Client/Driver 的程式語言,都可以直接使用 TiDB

  • 支援分散式事務

無論是一個地方的幾個節點,還是跨多個資料中心的多個節點,TiDB 均支援 ACID 分散式事務

TiDB 事務模型靈感源自 Google Percolator 模型,主體是一個兩階段提交協定,並進行了一些實用的優化。該模型依賴於一個時間戳分配器,為每個事務分配單調遞增的時間戳,這樣就檢測到事務衝突。在 TiDB 叢集中,PD 承擔時間戳分配器的角色

TiDB不需要像MySQL一樣通過支援XA來滿足跨資料庫事務,TiDO的本身的分散式事務模型無論是在效能上還是在穩定性上都要比 XA 要高出很多,所以不會也不需要支援 XA。

與傳統的單機資料庫相比,TiDB 具有以下優勢

  • 純分散式架構,擁有良好的擴充套件性,支援彈性的擴縮容
  • 支援 SQL,對外暴露 MySQL 的網路協定,並相容大多數 MySQL 的語法,在大多數場景下可以直接替換 MySQL
  • 預設支援高可用,在少數副本失效的情況下,資料庫本身能夠自動進行資料修復和故障轉移,對業務透明
  • 支援 ACID 事務,對於一些有強一致需求的場景友好,例如:銀行轉賬
  • 具有豐富的工具鏈生態,覆蓋資料遷移、同步、備份等多種場景

簡單來說,TiDB 適合具備下面這些特點的場景

  • 資料量大,單機儲存不下
  • 不希望做 Sharding 或者懶得做 Sharding
  • 存取模式上沒有明顯的熱點
  • 需要事務、需要強一致、需要災備
  • 希望 Real-Time HTAP,減少儲存鏈路

五大核心特性

  • 一鍵水平擴容或者縮容

    得益於 TiDB 儲存計算分離的架構的設計,可按需對計算、儲存分別進行線上擴容或者縮容,擴容或者縮容過程中對應用運維人員透明。

  • 金融級高可用

    資料採用多副本儲存,資料副本通過 Multi-Raft 協定同步事務紀錄檔,多數派寫入成功事務才能提交,確保資料強一致性且少數副本發生故障時不影響資料的可用性。可按需設定副本地理位置、副本數量等策略滿足不同容災級別的要求。

  • 實時 HTAP

    提供行儲存引擎 TiKV、列儲存引擎 TiFlash 兩款儲存引擎,TiFlash 通過 Multi-Raft Learner 協定實時從 TiKV 複製資料,確保行儲存引擎 TiKV 和列儲存引擎 TiFlash 之間的資料強一致。TiKV、TiFlash 可按需部署在不同的機器,解決 HTAP 資源隔離的問題。

  • 雲原生的分散式資料庫

    專為雲而設計的分散式資料庫,通過 TiDB Operator 可在公有云、私有云、混合雲中實現部署工具化、自動化。

  • 相容 MySQL 5.7 協定和 MySQL 生態

    相容 MySQL 5.7 協定、MySQL 常用的功能、MySQL 生態,應用無需或者修改少量程式碼即可從 MySQL 遷移到 TiDB。提供豐富的資料遷移工具幫助應用便捷完成資料遷移。

四大核心應用場景

  • 對資料一致性及高可靠、系統高可用、可延伸性、容災要求較高的金融行業屬性的場景

    眾所周知,金融行業對資料一致性及高可靠、系統高可用、可延伸性、容災要求較高。傳統的解決方案是同城兩個機房提供服務、異地一個機房提供資料容災能力但不提供服務,此解決方案存在以下缺點:資源利用率低、維護成本高、RTO (Recovery Time Objective)RPO (Recovery Point Objective) 無法真實達到企業所期望的值。TiDB 採用多副本 + Multi-Raft 協定的方式將資料排程到不同的機房、機架、機器,當部分機器出現故障時系統可自動進行切換,確保系統的 RTO <= 30s 及 RPO = 0。

  • 對儲存容量、可延伸性、並行要求較高的海量資料及高並行的 OLTP 場景

    隨著業務的高速發展,資料呈現爆炸性的增長,傳統的單機資料庫無法滿足因資料爆炸性的增長對資料庫的容量要求,可行方案是採用分庫分表的中介軟體產品或者 NewSQL 資料庫替代、採用高階的儲存裝置等,其中價效比最大的是 NewSQL 資料庫,例如:TiDB。TiDB 採用計算、儲存分離的架構,可對計算、儲存分別進行擴容和縮容,計算最大支援 512 節點,每個節點最大支援 1000 並行,叢集容量最大支援 PB 級別。

  • Real-time HTAP 場景

    隨著 5G、物聯網、人工智慧的高速發展,企業所生產的資料會越來越多,其規模可能達到數百 TB 甚至 PB 級別,傳統的解決方案是通過 OLTP 型資料庫處理線上聯機交易業務,通過 ETL 工具將資料同步到 OLAP 型資料庫進行資料分析,這種處理方案存在儲存成本高、實時性差等多方面的問題。TiDB 在 4.0 版本中引入列儲存引擎 TiFlash 結合行儲存引擎 TiKV 構建真正的 HTAP 資料庫,在增加少量儲存成本的情況下,可以在同一個系統中做聯機交易處理、實時資料分析,極大地節省企業的成本。

  • 資料匯聚、二次加工處理的場景

    當前絕大部分企業的業務資料都分散在不同的系統中,沒有一個統一的彙總,隨著業務的發展,企業的決策層需要了解整個公司的業務狀況以便及時做出決策,故需要將分散在各個系統的資料匯聚在同一個系統並進行二次加工處理生成 T+0 或 T+1 的報表。傳統常見的解決方案是採用 ETL + Hadoop 來完成,但 Hadoop 體系太複雜,運維、儲存成本太高無法滿足使用者的需求。與 Hadoop 相比,TiDB 就簡單得多,業務通過 ETL 工具或者 TiDB 的同步工具將資料同步到 TiDB,在 TiDB 中可通過 SQL 直接生成報表。

二、快速上手

TiDB 是一個分散式系統。最基礎的 TiDB 測試叢集通常由 2 個 TiDB 範例、3 個 TiKV 範例、3 個 PD 範例和可選的 TiFlash 範例構成。通過 TiUP Playground,可以快速搭建出上述的一套基礎測試叢集,步驟如下:

  • step1、下載並安裝 TiUP。

    curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
    登入後複製

安裝完成後顯示:

Successfully set mirror to https://tiup-mirrors.pingcap.com
Detected shell: bash
Shell profile:  /home/user/.bashrc
/home/user/.bashrc has been modified to add tiup to PATH
open a new terminal or source /home/user/.bashrc to use it
Installed path: /home/user/.tiup/bin/tiup
===============================================
Have a try:     tiup playground
===============================================
登入後複製
  • step2、宣告全域性環境變數。 source ${your_shell_profile}

    source /home/user/.bashrc
    登入後複製
  • step3、在當前 session 執行以下命令啟動叢集。

    tiup playground
    登入後複製
  • step4、驗證。【現在可以像使用MySQL一樣使用TiDB啦

    #新開啟一個 session 以存取 TiDB 資料庫。
    #使用 TiUP client 連線 TiDB:
    tiup client
    #也可使用 MySQL 使用者端連線 TiDB
    mysql --host 127.0.0.1 --port 4000 -u root
    #通過 http://127.0.0.1:9090 存取 TiDB 的 Prometheus 管理介面。
    #通過 http://127.0.0.1:2379/dashboard 存取 TiDB Dashboard 頁面,預設使用者名稱為 root,密碼為空。
    #通過 http://127.0.0.1:3000 存取 TiDB 的 Grafana 介面,預設使用者名稱和密碼都為 admin。
    登入後複製

三、TiDB架構原理

在核心設計上,TiDB 分散式資料庫將整體架構拆分成了多個模組,各模組之間互相通訊,組成完整的 TiDB 系統。對應的架構圖如下:

1.png

  • TiDB Server 負責處理SQL相關的邏輯,將SQL語句轉成key,通過PD來查詢資料具體在哪個TiKV。TiDB本身是無狀態的,不儲存資料,只負責計算。TiDB採用go語言編寫。【相關推薦:Go視訊教學

  • PD

    PD儲存了叢集的元資訊,如key在哪個 TiKV 節點;PD還負責叢集的負載均衡以及資料分片等。PD通過內嵌etcd來支援資料分佈和容錯。PD採用go語言編寫。

  • TiKV Server

    TiKV 是一個分散式的提供事務的 Key-Value 儲存引擎,基於Google Spanner, HBase 設計,但脫離了底層較為複雜的HDFS。通過RocksDB將key-value值存在本地地盤,使用 Raft 協定做複製,保持資料的一致性和容災。TiKV採用Rust語言編寫。

2.png

1、TiDB資料庫的儲存——TiKV Server

TiDB儲存模型,一個分散式帶事務的 KV 引擎一個全域性有序的分散式 Key-Value 引擎的分層結構以及如何實現多副本容錯。

儲存節點TiKV Server:負責儲存資料,從外部看 TiKV 是一個分散式的提供事務的 Key-Value 儲存引擎。儲存資料的基本單位是 Region,每個 Region 負責儲存一個 Key Range(從 StartKey 到 EndKey 的左閉右開區間)的資料,每個 TiKV 節點會負責多個 Region。TiKV 的 API 在 KV 鍵值對層面提供對分散式事務的原生支援,預設提供了 SI (Snapshot Isolation) 的隔離級別,這也是 TiDB 在 SQL 層面支援分散式事務的核心。TiDB 的 SQL 層做完 SQL 解析後,會將 SQL 的執行計劃轉換為對 TiKV API 的實際呼叫。所以,資料都儲存在 TiKV 中。另外,TiKV 中的資料都會自動維護多副本(預設為三副本),天然支援高可用和自動故障轉移。

TiFlash:TiFlash 是一類特殊的儲存節點。和普通 TiKV 節點不一樣的是,在 TiFlash 內部,資料是以列式的形式進行儲存,主要的功能是為分析型的場景加速。

TiKV

儲存資料需要保證:資料不丟、資料不錯→Raft協定。除此之外,還需要考慮以下問題:

1、能否支援跨資料中心的容災?
2、寫入速度是否夠快?
3、資料儲存下來後,是否方便讀取?
4、儲存的資料如何修改?如何支援並行的修改?
5、如何原子地修改多條記錄?

TiKV專案很好的解決了以上問題。那麼如何實現 TiKV 這樣一個高效能高可靠性的巨大的(分散式的) Map?

  • TiKV是一個巨大的 Map,也就是儲存的是 Key-Value pair。
  • 這個 Map 中的 Key-Value pair 按照 Key 的二進位制順序有序,也就是我們可以 Seek 到某一個 Key 的位置,然後不斷的呼叫 Next 方法以遞增的順序獲取比這個 Key 大的 Key-Value。

Raft和RocksDB

TiKV 利用 Raft 來做資料複製,每個資料變更都會落地為一條 Raft 紀錄檔,通過 Raft 的紀錄檔複製功能,將資料安全可靠地同步到 Group 的多數節點中。

TiKV 沒有選擇直接向磁碟上寫資料,而是把資料儲存在 RocksDB 中,具體的資料落地由 RocksDB 負責。【RocksDB 是一個非常優秀的開源的單機儲存引擎。】

3.png

通過使用 Raft 一致性演演算法,資料在各 TiKV 節點間複製為多副本,以確保某個節點掛掉時資料的安全性。

實際上在底層,TiKV 使用複製紀錄檔 + 狀態機 (State Machine) 的模型來複制資料。對於寫入請求,資料被寫入 Leader,然後 Leader 以紀錄檔的形式將命令複製到它的 Follower 中。當叢集中的大多數節點收到此紀錄檔時,紀錄檔會被提交,狀態機會相應作出變更。

Region概念

對於一個 KV 系統,將資料分散在多臺機器上有兩種比較典型的方案:一種是按照 Key 做 Hash,根據 Hash 值選擇對應的儲存節點;另一種是分 Range,某一段連續的 Key 都儲存在一個儲存節點上。為了支援範圍查詢,TiKV 選擇了第二種方式,將整個 Key-Value 空間分成很多段,每一段是一系列連續的 Key,我們將每一段叫做一個 Region,並且我們會盡量保持每個 Region 中儲存的資料不超過一定的大小(這個大小可以設定,目前預設是 96Mb)。每一個 Region 都可以用 StartKey 到 EndKey 這樣一個左閉右開區間來描述。

4.png

將資料劃分成 Region 後,會做 兩件重要的事情

  • 以 Region 為單位,將資料分散在叢集中所有的節點上,並且儘量保證每個節點上服務的 Region 數量差不多。

    資料按照 Key 切分成很多 Region,每個 Region 的資料只會儲存在一個節點上面。我們的系統會有一個元件【PD】來負責將 Region 儘可能均勻的散佈在叢集中所有的節點上,這樣一方面實現了儲存容量的水平擴充套件(增加新的節點後,會自動將其他節點上的 Region 排程過來),另一方面也實現了負載均衡(不會出現某個節點有很多資料,其他節點上沒什麼資料的情況)。同時為了保證上層使用者端能夠存取所需要的資料,系統中也會由元件【PD】記錄 Region 在節點上面的分佈情況,也就是通過任意一個 Key 就能查詢到這個 Key 在哪個 Region 中,以及這個 Region 目前在哪個節點上。

  • 以 Region 為單位做 Raft 的複製和成員管理。

    TiKV 是以 Region 為單位做資料的複製,也就是一個 Region 的資料會儲存多個副本,將每一個副本叫做一個 Replica。Replica 之間是通過 Raft 來保持資料的一致(終於提到了 Raft),一個 Region 的多個 Replica 會儲存在不同的節點上,構成一個 Raft Group。其中一個 Replica 會作為這個 Group 的 Leader,其它的 Replica 作為 Follower。所有的讀和寫都是通過 Leader 進行,再由 Leader 複製給 Follower。

    理解了 Region 之後,應該可以理解下面這張圖:

5.png

以 Region 為單位做資料的分散和複製,就有了一個分散式的具備一定容災能力的 KeyValue 系統,不用再擔心資料存不下,或者是磁碟故障丟失資料的問題。

MVCC

如果兩個 Client 同時去修改一個 Key 的 Value,如果沒有 MVCC,就需要對資料上鎖,在分散式場景下,可能會帶來效能以及死鎖問題。 TiKV 的 MVCC 實現是通過在 Key 後面新增 Version 來實現。

對於同一個 Key 的多個版本,把版本號較大的放在前面,版本號小的放在後面。這樣當使用者通過一個 Key + Version 來獲取 Value 的時候,可以將 Key 和 Version 構造出 MVCC 的 Key,也就是 Key-Version。然後可以直接 Seek(Key-Version),定位到第一個大於等於這個 Key-Version 的位置。

#簡單來說,沒有 MVCC 之前,可以把 TiKV 看做這樣的
Key1 -> Value
Key2 -> Value
……
KeyN -> Value
#有了 MVCC 之後,TiKV 的 Key 排列是這樣的:
Key1-Version3 -> Value
Key1-Version2 -> Value
Key1-Version1 -> Value
……
Key2-Version4 -> Value
Key2-Version3 -> Value
Key2-Version2 -> Value
Key2-Version1 -> Value
……
KeyN-Version2 -> Value
KeyN-Version1 -> Value
……
登入後複製

GC

TiDB 的事務的實現採用了 MVCC(多版本並行控制)機制,當新寫入的資料覆蓋舊的資料時,舊的資料不會被替換掉,而是與新寫入的資料同時保留,並以時間戳來區分版本。Garbage Collection (GC) 的任務便是清理不再需要的舊資料。

  • GC整體流程

一個 TiDB 叢集中會有一個 TiDB 範例被選舉為 GC leader,GC 的執行由 GC leader 來控制。

GC 會被定期觸發。每次 GC 時,首先,TiDB 會計算一個稱為 safe point 的時間戳,接下來 TiDB 會在保證 safe point 之後的快照全部擁有正確資料的前提下,刪除更早的過期資料。每一輪 GC 分為以下三個步驟

step1:「Resolve Locks」 【清理鎖】階段會對所有 Region 掃描 safe point 之前的鎖,並清理這些鎖。

step2:「Delete Ranges」 【刪除區間】階段快速地刪除由於 DROP TABLE/DROP INDEX 等操作產生的整區間的廢棄資料。

step3:「Do GC」【進行GC清理】階段每個 TiKV 節點將會各自掃描該節點上的資料,並對每一個 key 刪除其不再需要的舊版本。

預設設定下,GC 每 10 分鐘觸發一次,每次 GC 會保留最近 10 分鐘內的資料(即預設 GC life time 為 10 分鐘,safe point 的計算方式為當前時間減去 GC life time)。如果一輪 GC 執行時間太久,那麼在一輪 GC 完成之前,即使到了下一次觸發 GC 的時間也不會開始下一輪 GC。另外,為了使持續時間較長的事務能在超過 GC life time 之後仍然可以正常執行,safe point 不會超過正在執行中的事務的開始時間 (start_ts)。

2、TiDB資料庫的計算——TiDB Server

從 SQL 的角度瞭解了資料是如何儲存,以及如何用於計算。

TiDB 在 TiKV 提供的分散式儲存能力基礎上,構建了兼具優異的交易處理能力與良好的資料分析能力的計算引擎。

TiDB Server:SQL 解析層,對外暴露 MySQL 協定的連線 endpoint,負責接受使用者端的連線,執行 SQL 解析和優化,最終生成分散式執行計劃。TiDB 層本身是無狀態的,實踐中可以啟動多個 TiDB 範例,通過負載均衡元件(如 LVS、HAProxy 或 F5)對外提供統一的接入地址,使用者端的連線可以均勻地分攤在多個 TiDB 範例上以達到負載均衡的效果。TiDB Server 本身並不儲存資料,只是解析 SQL,將實際的資料讀取請求轉發給底層的儲存節點 TiKV(或 TiFlash)。

SQL對映KV

可以將關係模型簡單理解為 Table 和 SQL 語句,那麼問題變為如何在 KV 結構上儲存 Table 以及如何在 KV 結構上執行 SQL 語句。 SQL 和 KV 結構之間存在巨大的區別,那麼如何能夠方便高效地進行對映,就成為一個很重要的問題。一個好的對映方案必須有利於對資料操作的需求。

6.png

分散式SQL運算

首先我們需要將計算儘量靠近儲存節點,以避免大量的 RPC 呼叫。其次,我們需要將 Filter 也下推到儲存節點進行計算,這樣只需要返回有效的行,避免無意義的網路傳輸。最後,我們可以將聚合函數、GroupBy 也下推【計算下推】到儲存節點,進行預聚合,每個節點只需要返回一個 Count 值即可,再由 tidb-server 將 Count 值 Sum 起來【並行運算元】。 這裡有一個資料逐層返回的示意圖:

7.png

實際上 TiDB 的 SQL 層要複雜的多,模組以及層次非常多,下面這個圖【SQL引擎架構】列出了重要的模組以及呼叫關係:

8.png

SQL查詢返回的簡要流程:使用者的 SQL 請求會直接或者通過 Load Balancer 傳送到 tidb-server,tidb-server 會解析 MySQL Protocol Packet,獲取請求內容,然後做語法解析、查詢計劃制定和優化、執行查詢計劃獲取和處理資料。資料全部儲存在 TiKV 叢集中,所以在這個過程中 tidb-server 需要和 tikv-server 互動,獲取資料。最後 tidb-server 需要將查詢結果返回給使用者。

SQL執行流程

在 TiDB 中,從輸入的查詢文字到最終的執行計劃執行結果的過程可以見下圖:

9.png

首先經過 parser 對原始查詢文字的解析以及一些簡單的合法性驗證後,TiDB 首先會對查詢做一些邏輯上的等價變化——查詢邏輯優化
通過這些等價變化,使得這個查詢在邏輯執行計劃上可以變得更易於處理。在等價變化結束之後,TiDB 會得到一個與原始查詢等價的查詢計劃結構,之後根據資料分佈、以及一個運算元具體的執行開銷,來獲得一個最終的執行計劃——查詢物理優化
同時,TiDB 在執行 PREPARE 語句時,可以選擇開啟快取來降低 TiDB 生成執行計劃的開銷——執行計劃快取

3、TiDB資料庫的排程——PD Server

PD (Placement Driver) 是 TiDB 叢集的管理模組,同時也負責叢集資料的實時排程。

排程場景

PD (Placement Driver) Server:整個 TiDB 叢集的元資訊管理模組,負責儲存每個 TiKV 節點實時的資料分佈情況和叢集的整體拓撲結構,提供 TiDB Dashboard 管控介面,併為分散式事務分配事務 ID。PD 不僅儲存元資訊,同時還會根據 TiKV 節點實時上報的資料分佈狀態,下發資料排程命令給具體的 TiKV 節點,可以說是整個叢集的「大腦」。此外,PD 本身也是由至少 3 個節點構成,從而提供高可用。建議部署奇數個 PD 節點。

排程需求

第一類:作為一個分散式高可用儲存系統,必須滿足的需求,包括幾種:【 容災功能 】

  • 副本數量不能多也不能少。
  • 副本需要根據拓撲結構分佈在不同屬性的機器上。
  • 節點宕機或異常能夠自動合理快速地進行容災。

第二類:作為一個良好的分散式系統,需要考慮的地方包括:【資源利用率更高且合理,具備良好的擴充套件性】

  • 維持整個叢集的 Leader 分佈均勻。
  • 維持每個節點的儲存容量均勻。
  • 維持存取熱點分佈均勻。
  • 控制負載均衡的速度,避免影響線上服務。
  • 管理節點狀態,包括手動上線/下線節點。

為了滿足這些需求,需要收集足夠的資訊,比如每個節點的狀態、每個 Raft Group 的資訊、業務存取操作的統計等;其次需要設定一些策略,PD 根據這些資訊以及排程的策略,制定出儘量滿足前面所述需求的排程計劃。

排程操作

排程的基本操作指的是為了滿足排程的策略。上述排程需求可整理為以下三個操作:

  • 增加一個副本
  • 刪除一個副本
  • 將 Leader 角色在一個 Raft Group 的不同副本之間 transfer(遷移)

剛好 Raft 協定通過 AddReplicaRemoveReplicaTransferLeader 這三個命令,可以支撐上述三種基本操作。

TiKV Store 的狀態具體分為 Up,Disconnect,Offline,Down,Tombstone。各狀態的關係如下:

10.png

排程策略

  • 一個 Region 的副本數量正確。
  • 一個 Raft Group 中的多個副本不在同一個位置。
  • 副本在 Store 之間的分佈均勻分配。
  • Leader 數量在 Store 之間均勻分配。
  • 存取熱點數量在 Store 之間均勻分配。
  • 各個 Store 的儲存空間佔用大致相等。
  • 控制排程速度,避免影響線上服務。

排程實現

PD 不斷的通過 Store 【即TiKV節點】或者 Leader 的心跳包收集資訊,獲得整個叢集的詳細資料,並且根據這些資訊以及排程策略生成排程操作序列,每次收到 Region Leader 發來的心跳包時,PD 都會檢查是否有對這個 Region 待進行的操作,通過心跳包的回覆訊息,將需要進行的操作返回給 Region Leader,並在後面的心跳包中監測執行結果。注意這裡的操作只是給 Region Leader 的建議,並不保證一定能得到執行,具體是否會執行以及什麼時候執行,由 Region Leader 自己根據當前自身狀態來定。

五、TiDB最佳實踐

TiDB 的最佳實踐與其實現原理密切相關,建議先了解一些基本的實現機制,包括 Raft、分散式事務、資料分片、負載均衡、SQL 到 KV 的對映方案、二級索引的實現方法、分散式執行引擎。

Raft

Raft 是一種一致性協定,能提供強一致的資料複製保證,TiDB 最底層用 Raft 來同步資料。每次寫入都要寫入多數副本,才能對外返回成功,這樣即使丟掉少數副本,也能保證系統中還有最新的資料。比如最大 3 副本的話,每次寫入 2 副本才算成功,任何時候,只丟失一個副本的情況下,存活的兩個副本中至少有一個具有最新的資料。

相比 Master-Slave 方式的同步,同樣是儲存三副本,Raft 的方式更為高效,因為寫入的延遲取決於最快的兩個副本,而不是最慢的那個副本。所以使用 Raft 同步的情況下,異地多活成為可能。在典型的兩地三中心場景下,每次寫入只需要本資料中心以及離得近的一個資料中心寫入成功就能保證資料的一致性,而並不需要三個資料中心都寫成功。

分散式事務

TiDB 提供完整的分散式事務,事務模型是在 Google Percolator 的基礎上做了一些優化。

  • 樂觀鎖

    TiDB 的樂觀事務模型,只有在真正提交的時候,才會做衝突檢測。如果有衝突,則需要重試。這種模型在衝突嚴重的場景下,會比較低效,因為重試之前的操作都是無效的,需要重複做。舉一個比較極端的例子,就是把資料庫當做計數器用,如果存取的並行度比較高,那麼一定會有嚴重的衝突,導致大量的重試甚至是超時。但是如果存取衝突並不十分嚴重,那麼樂觀鎖模型具備較高的效率。在衝突嚴重的場景下,推薦使用悲觀鎖,或在系統架構層面解決問題,比如將計數器放在 Redis 中。

  • 悲觀鎖

    TiDB 的悲觀事務模式,悲觀事務的行為和 MySQL 基本一致,在執行階段就會上鎖,先到先得,避免衝突情況下的重試,可以保證有較多衝突的事務的成功率。悲觀鎖同時解決了希望通過 select for update 對資料提前鎖定的場景。但如果業務場景本身衝突較少,樂觀鎖的效能會更有優勢。

  • 事務大小限制

    由於分散式事務要做兩階段提交,並且底層還需要做 Raft 複製,如果一個事務非常大,會使得提交過程非常慢,並且會卡住下面的 Raft 複製流程。為了避免系統出現被卡住的情況,我們對事務的大小做了限制【單個事務包含的 SQL 語句不超過 5000 條(預設)】。

資料分片

TiKV 自動將底層資料按照 Key 的 Range 進行分片。每個 Region 是一個 Key 的範圍,從 StartKeyEndKey 的左閉右開區間。Region 中的 Key-Value 總量超過一定值,就會自動分裂。這部分對使用者透明。

負載均衡

PD 會根據整個 TiKV 叢集的狀態,對叢集的負載進行排程。排程是以 Region 為單位,以 PD 設定的策略為排程邏輯,自動完成。

SQL on KV

TiDB 自動將 SQL 結構對映為 KV 結構。簡單來說,TiDB 執行了以下操作:

  • 一行資料對映為一個 KV,Key 以 TableID 構造字首,以行 ID 為字尾
  • 一條索引對映為一個 KV,Key 以 TableID+IndexID 構造字首,以索引值構造字尾

可以看到,對於一個表中的資料或者索引,會具有相同的字首,這樣在 TiKV 的 Key 空間內,這些 Key-Value 會在相鄰的位置。那麼當寫入量很大,並且集中在一個表上面時,就會造成寫入的熱點,特別是連續寫入的資料中某些索引值也是連續的(比如 update time 這種按時間遞增的欄位),會在很少的幾個 Region 上形成寫入熱點,成為整個系統的瓶頸。同樣,如果所有的資料讀取操作也都集中在很小的一個範圍內(比如在連續的幾萬或者十幾萬行資料上),那麼可能造成資料的存取熱點。

二級索引

TiDB 支援完整的二級索引,並且是全域性索引,很多查詢可以通過索引來優化。如果利用好二級索引,對業務非常重要,很多 MySQL 上的經驗在 TiDB 這裡依然適用,不過 TiDB 還有一些自己的特點,需要注意,這一節主要討論在 TiDB 上使用二級索引的一些注意事項。

  • 二級索引不是越多越好。

  • 對區分度【基數】比較大的列建立索引比較合適。有多個查詢條件時,可以選擇組合索引,注意最左字首原則。

  • 通過索引查詢和直接掃描 Table 的區別。

  • 查詢並行度。

    資料分散在很多 Region 上,所以 TiDB 在做查詢的時候會並行進行,預設的並行度比較保守,因為過高的並行度會消耗大量的系統資源。

    對於 OLTP 型別的查詢,往往不會涉及到大量的資料,較低的並行度已經可以滿足需求。
    對於 OLAP 型別的 Query,往往需要較高的並行度。

    所以 TiDB 支援通過 System Variable 來調整查詢並行度。【tidb_distsql_scan_concurrency、tidb_index_lookup_size、tidb_index_lookup_concurrency、tidb_index_serial_scan_concurrency等等】

  • 通過索引保證結果順序。【索引除了可以用來過濾資料之外,還能用來對資料排序,首先按照索引的順序獲取行 ID,然後再按照行 ID 的返回順序返回行的內容,這樣可以保證返回結果按照索引列有序。】

  • 也支援逆序索引。【目前速度比順序 Scan 慢一些,通常情況下慢 20%,在資料頻繁修改造成版本較多的情況下,會慢的更多。如果可能,建議避免對索引的逆序 Scan】

更多程式設計相關知識,請存取:!!

以上就是tidb是go語言麼的詳細內容,更多請關注TW511.COM其它相關文章!