TiKV 集羣版本的安全遷移

問題描述

在 TiDB 的產品迭代中,不免會碰到一些兼容性問題出現。通常協議上的兼容性 protobuf 已經能幫我們處理的很好,在進行功能開發,性能優化時,通常會保證版本是向後兼容的,但並不保證向前兼容性,因此,當集羣中同時有新舊版本節點存在時,舊版本不能兼容新版本的特性,就有可能造成該節點崩潰,影響集羣可用性,甚至丟失數據。目前在有不兼容的版本升級時,會要求進行離線升級,但這會影響到服務,我們需要一個適合的機制來進行不停服務的升級。因此我們需要在進行滾動升級時,讓這些不能保證整個集羣的向後兼容性的功能不被啓用。只有在保證集羣中所有節點都已經升級完成後,我們才安全的啓用這些功能。

常見的當我們對引入新的 RaftCommand 的時候,舊版本的 TiKV 並不能識別新的添加的 RaftCommand,對於不能認知的 RaftCommand TiKV 有不同的處理,可能會報錯退出或忽略。比如爲了支持 Raft Learner, 在 raftpb 裏對添加新的 ConfChange 類型。 當 PD 在進行 Region 調度時,會先發送 AddLearner 到 TiKV 上,接受到這個命令的肯定是這個 Region 的 Leader,在進行一系列檢查後,會將該命令 Proposal, 而 Follwer 如果是舊版本的話,在 Apply 這條 Command 就會出錯。而在滾動升級時,很有可能存在 Leader 是新版本,Follwer 是老版本的情況。

引入版本檢查機制

TiDB 的版本定義是遵循 Semver 的版本規則的。版本格式一般由主版本號(Major),次版本號(Minor),修訂號(Patch),版本號遞增規則如下:

  1. 主版本號:當進行了不兼容的 API 修改。
  2. 次版本號:當做了向下兼容的功能性新增。
  3. 修訂號:當做了向下兼容的問題修正。

先行版本號(PreRelase)及版本編譯信息可以加到“主版本號.次版本號.修訂號”的後面,作爲延伸。比如 TiDB 目前的版本是 2.1.0-beta,先行版號爲 beta 版。

在此之前,集羣並沒有版本的概念,雖然每個組件都有各自的版本信息,但各個節點的各自組件的版本都可以任意的。沒有一個管理機制可以管理或查看所有組件的版本信息。爲了解決滾動升級過程中存在多個版本的兼容性問題,這裏引入集羣版本的概念,並由 TiDB 集羣的中心節點 PD 來進行管理和檢查。

具體實現

1.升級集羣

在 PD 中,會設置一個 cluster_version 的鍵值對,對應當前運行集羣中 TiKV 節點中最舊的版本。也就是必須要兼容這個版本, 因此不能打開集羣中其他新版本的節點的一些不兼容的特性。

在集羣啓動的時候,每個 TiKV 都需要向 PD 註冊,註冊時會帶上版本信息。噹噹前 TiKV 的版本低於集羣版本的時候,該 TiKV 會註冊失敗。因爲此時集羣的版本已經是更高的版本了,而加入舊版本的節點需要對舊版本進行兼容,爲了防止已有的特性降級,直接拒絕不兼容的版本加入,目前默認主版本號和此版本號一樣則爲兼容的版本。

如果 TiKV 的版本高於或等於當前的 cluster_version 時, TiKV 能夠註冊成功併成功啓動。每次註冊都會觸發 PD 的一次檢查,會檢測當前集羣中正常運行的 TiKV 的最低版本,並與當前的 cluster_version 進行比對,如果最低版本比 cluster_version 更加新,則將 cluster_version 更新。因此每次滾動升級的時候,能夠自動更新集羣的版本。

2. 版本特性的開啓

TiKV 很多功能是需要 PD 的參與,目前這些新功能的開啓也是通過 PD 進行控制的。在 PD 中,會將每個版本新特性記錄下來,在 TiKV 2.0 中,對應有 Raft Leaner, Region Merge。 TiKV 2.1 中有 Batch Split,Joint Consensus 等。這些特性都需要 PD 的參與與控制。比如說 Add Leaner,Region Merge,Joint Consensus 需要 PD 下發調度給 TiKV,Batch Split 則是 TiKV 主動發起並請求 PD 分配新的 Region ID。因此這些功能都是能通過 PD 進行控制的。PD 會通過比對當前的集羣版本,選擇開啓當前集羣版本所支持的新特性。從而保證版本的兼容性。

3. 集羣回滾

當升級完成後,如果遇到問題需要進行集羣進行回滾時, 需要手動修改集羣版本後。PD 提供了 pdctl 可以通過命令手動修改集羣的 cluster_version,這時舊版本的 TiKV 就能註冊並啓動,從而進行回滾。

PD 對 cluster_version 是通過 etcd 進行了持久化,在每次 PD 啓動的時候,leader 都會從 etcd kv 中加載出 clustrer_version,然後提供服務。從而保證在 PD leader 切換後 cluster_version 的一致性。另外 PD 本身的版本可能會小於當前 cluster_version。因此在滾動升級的時候,需要先升級 PD,如果只升級了 TiKV,雖然 cluster_version 已經更新到新的版本的,但 PD 並不能開啓新的功能,因爲對它來說是不支持的。如果出現這種情況,PD 的日誌中會有報警。在升級的時候,最好按 PD,TiKV,TiDB 的順序逐一對各個組件。

後續計劃

上面提到的新功能特性一般都是需要 PD 參與的。而有些特性不需要PD的參與,因此需要保證這種特性在 TiKV 之間是可以兼容的,實現的時候可以採用類是 http2 <-> http 的方式,對請求進行降級裝發,保留兩套接口等。另爲 TiDB 目前是自身保證可以無縫兼容,但與 TiKV 可能存在兼容性問題,往後同樣考慮讓TiDB 也在 PD上進行註冊。

作者:陳書寧
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章