近日,國(guó)內(nèi)領(lǐng)先的中立云計(jì)算服務(wù)商UCloud與國(guó)內(nèi)開(kāi)源分布式NewSQL數(shù)據(jù)庫(kù)TiDB團(tuán)隊(duì)PingCAP正式達(dá)成合作,雙方聯(lián)手在UCloud全球數(shù)據(jù)中心推出了新一代TiDB的云端版本——Cloud TiDB。
作為一款定位于Cloud-native的數(shù)據(jù)庫(kù),截至目前TiDB在云整合上已取得了階段性進(jìn)展。Cloud TiDB產(chǎn)品在UCloud平臺(tái)正式開(kāi)啟公測(cè),TiDB彈性伸縮特性在Cloud 提供的基礎(chǔ)設(shè)施支持下得到了淋漓盡致的展現(xiàn)。
在感受云數(shù)據(jù)庫(kù)魅力的同時(shí),讓我們來(lái)探索一下TiDB與Cloud背后的技術(shù)秘密。
TiDB與傳統(tǒng)單機(jī)關(guān)系型數(shù)據(jù)庫(kù)的區(qū)別
首先,從TiDB的架構(gòu)說(shuō)起。TiDB作為一款開(kāi)源的分布式數(shù)據(jù)庫(kù)產(chǎn)品,具有多副本強(qiáng)一致性,能夠根據(jù)業(yè)務(wù)需求非常方便的進(jìn)行彈性伸縮,并且擴(kuò)縮容期間對(duì)上層業(yè)務(wù)無(wú)感知。
TiDB的主體架構(gòu)包含三個(gè)模塊,對(duì)應(yīng)Github上PingCAP組織下的三個(gè)開(kāi)源項(xiàng)目(TiDB / TiKV / PD):
◆ TiDB主要是負(fù)責(zé)SQL的解析器和優(yōu)化器,它相當(dāng)于計(jì)算執(zhí)行層,同時(shí)也負(fù)責(zé)客戶(hù)端接入和交互;
◆ TiKV是一套分布式的Key-Value存儲(chǔ)引擎,它承擔(dān)整個(gè)數(shù)據(jù)庫(kù)的存儲(chǔ)層,數(shù)據(jù)水平擴(kuò)展和多副本高可用特性都在這一層實(shí)現(xiàn);
◆ PD相當(dāng)于分布式數(shù)據(jù)庫(kù)的大腦,一方面負(fù)責(zé)收集和維護(hù)數(shù)據(jù)在各個(gè)TiKV節(jié)點(diǎn)的分布情況,另一方面PD承擔(dān)調(diào)度器的角色,根據(jù)數(shù)據(jù)分布狀況以及各個(gè)存儲(chǔ)節(jié)點(diǎn)的負(fù)載來(lái)采取合適的調(diào)度策略,維持整個(gè)系統(tǒng)的平衡與穩(wěn)定。
上述三個(gè)模塊中的每個(gè)角色都是一個(gè)多節(jié)點(diǎn)組成的集群,所以最終TiDB的架構(gòu)如下圖所示:
由此可見(jiàn),分布式系統(tǒng)本身的復(fù)雜性不僅導(dǎo)致手工部署和運(yùn)維成本較高,而且容易出錯(cuò)。傳統(tǒng)的自動(dòng)化部署運(yùn)維工具(如:Puppet/Chef/SaltStack/Ansible等),由于缺乏狀態(tài)管理,在節(jié)點(diǎn)出現(xiàn)問(wèn)題時(shí)不能及時(shí)自動(dòng)完成故障轉(zhuǎn)移,需要運(yùn)維人員人工干預(yù),有些則需要寫(xiě)大量DSL甚至與Shell腳本一起混合使用,可移植性較差,維護(hù)成本比較高。
在云時(shí)代,容器成為應(yīng)用分發(fā)部署的基本單位,谷歌基于內(nèi)部使用數(shù)十年的容器編排系統(tǒng)Borg經(jīng)驗(yàn),推出的開(kāi)源容器編排系統(tǒng)Kubernetes就成為當(dāng)前容器編排技術(shù)的主流。
TiDB 與Kubernetes的深度整合
作為Cloud Native Database,TiDB選擇擁抱容器技術(shù),并與Kubernetes進(jìn)行深度整合,使其可以非常方便地基于Kubernetes完成數(shù)據(jù)庫(kù)自動(dòng)化管理。甚至可以說(shuō)Kubernetes項(xiàng)目是為Cloud而生,利用云平臺(tái)IaaS層提供的API可以很方便地與云進(jìn)行整合。這樣只要讓TiDB與Kubernetes 結(jié)合得更好,進(jìn)而就能實(shí)現(xiàn)其與各個(gè)云平臺(tái)的整合,使TiDB在云上的快速部署和高效運(yùn)維成為現(xiàn)實(shí)。
◆ Kubernetes簡(jiǎn)介
Kubernetes最早是作為一個(gè)純粹的容器編排系統(tǒng)而誕生,用戶(hù)部署好Kubernetes集群之后,直接使用其內(nèi)置的各種功能部署應(yīng)用服務(wù)。由于這個(gè)PaaS平臺(tái)使用起來(lái)非常便利,吸引了很多用戶(hù),不同用戶(hù)也提出了各種不同需求,有些特性需求Kubernetes 可直接在其核心代碼里實(shí)現(xiàn),但有些特性并不適合合并到主干分支。
為了滿(mǎn)足這類(lèi)需求,Kubernetes開(kāi)放出一些API供用戶(hù)自己擴(kuò)展,實(shí)現(xiàn)自身需求。當(dāng)前Kubernetes已經(jīng)升級(jí)到v1.8版本,內(nèi)部API變得越來(lái)越開(kāi)放,使其更像是一個(gè)跑在云上的操作系統(tǒng)。用戶(hù)可以把它當(dāng)作一套云的SDK或Framework來(lái)使用,而且可以很方便地開(kāi)發(fā)組件來(lái)擴(kuò)展?jié)M足自身業(yè)務(wù)需求,對(duì)有狀態(tài)服務(wù)的支持就是一個(gè)代表性實(shí)例。
在最早期,Kubernetes 項(xiàng)目只支持無(wú)狀態(tài)服務(wù)(Stateless
Service) 來(lái)管理,無(wú)狀態(tài)服務(wù)通過(guò)ReplicationController定義多個(gè)副本,由Kubernetes調(diào)度器來(lái)決定在不同節(jié)點(diǎn)上啟動(dòng)多個(gè)Pod,實(shí)現(xiàn)負(fù)載均衡和故障轉(zhuǎn)移。對(duì)于無(wú)狀態(tài)服務(wù),多個(gè)副本對(duì)應(yīng)的 Pod是等價(jià)的,所以當(dāng)節(jié)點(diǎn)出現(xiàn)故障時(shí),在新節(jié)點(diǎn)上啟動(dòng)一個(gè)Pod與失效的Pod是等價(jià)的,不會(huì)涉及狀態(tài)遷移問(wèn)題,因而管理非常簡(jiǎn)單。
◆ 有狀態(tài)服務(wù)Stateful Service
不過(guò),對(duì)于有狀態(tài)服務(wù) (Stateful Service),由于需要將數(shù)據(jù)持久化到磁盤(pán),使得不同Pod之間不能再認(rèn)為成等價(jià),也就不能再像無(wú)狀態(tài)服務(wù)那樣隨意地進(jìn)行調(diào)度遷移。Kubernetes v1.3版本提出PetSet的概念,用來(lái)管理有狀態(tài)服務(wù)并在v1.5版本中將其更名為StatefulSet。
StatefulSet明確定義了一組Pod中的每個(gè)身份,啟動(dòng)和升級(jí)都按特定順序來(lái)操作。另外,使用持久化卷存儲(chǔ)(PersistentVolume)來(lái)作為存儲(chǔ)數(shù)據(jù)的載體,當(dāng)節(jié)點(diǎn)失效 Pod需要遷移時(shí),對(duì)應(yīng)的PV通過(guò)umount/mount方式跟著一起遷移到新節(jié)點(diǎn),或者直接使用分布式文件系統(tǒng)作PV底層存儲(chǔ),使Pod在遷移后仍然能訪問(wèn)到之前的數(shù)據(jù)。
同時(shí),Pod在發(fā)生遷移時(shí),其網(wǎng)絡(luò)身份(例如IP地址)是會(huì)發(fā)生變化的,很多分布式系統(tǒng)不能接受這種情況,所以StatefulSet在遷移Pod時(shí)可以通過(guò)綁定域名的方式來(lái)保證Pod在集群中網(wǎng)絡(luò)身份不發(fā)生變化。
然而,現(xiàn)實(shí)中一些分布式系統(tǒng)更為復(fù)雜,StatefulSet也顯得捉襟見(jiàn)肘。舉例來(lái)說(shuō),某些分布式系統(tǒng)的節(jié)點(diǎn)在加入集群或下線(xiàn)時(shí),還需要做些額外的注冊(cè)和清理操作,或者在滾動(dòng)升級(jí)時(shí),要考量版本兼容性等問(wèn)題。
基于上述原因,CoreOS公司提出了Operator概念,并實(shí)現(xiàn)了etcd-operator和prometheus-operator來(lái)管理Etcd和Prometheus這樣復(fù)雜的分布式系統(tǒng)。用戶(hù)可以開(kāi)發(fā)自己的Operator,在Kubernetes之上實(shí)現(xiàn)自定義的Controller,將有狀態(tài)服務(wù)領(lǐng)域中特定的運(yùn)維知識(shí)編碼進(jìn)去,從而實(shí)現(xiàn)對(duì)特定分布式系統(tǒng)的管理。同時(shí),Operator本身也是跑在Kubernetes中的一個(gè)Pod(deployment),對(duì)Kubernetes系統(tǒng)并無(wú)侵入性。
◆ TiDB多組件支持
針對(duì)TiDB這種復(fù)雜的分布式服務(wù),我們開(kāi)發(fā)了tidb-operator等一系列組件,來(lái)管理 TiDB集群實(shí)例在Kubernetes平臺(tái)上的創(chuàng)建、銷(xiāo)毀、擴(kuò)縮容、滾動(dòng)升級(jí)和故障轉(zhuǎn)移等運(yùn)維操作。同時(shí),在上層封裝了一個(gè)tidb-cloud-manager組件,提供RESTful接口,實(shí)現(xiàn)了與云平臺(tái)的控制臺(tái)打通功能。這就完成了一個(gè)DBaaS(數(shù)據(jù)庫(kù)即服務(wù))架構(gòu)的基本形態(tài)。
由于TiDB對(duì)磁盤(pán)I/O有比較高的要求,通過(guò)PV掛載網(wǎng)絡(luò)盤(pán),會(huì)有明顯的性能損耗。另外,TiKV本身維護(hù)了數(shù)據(jù)多副本,這點(diǎn)和分布式文件系統(tǒng)的多副本是有重復(fù)的,所以要給Pod上掛載本地磁盤(pán),并且在Kubernetes上把Local PV管理起來(lái),作為一種特定資源來(lái)維護(hù)。
Kubernetes官方長(zhǎng)期以來(lái)一直沒(méi)有提供Local PV支持,本地存儲(chǔ)只支持hostPath和 emptyDir兩種方式。其中,hostPath的生命周期是脫離Kubernetes管理的,使用 hostPath的Pod銷(xiāo)毀后,里面的數(shù)據(jù)是不會(huì)被自動(dòng)清理,下次再掛載Pod就會(huì)造成臟數(shù)據(jù)。而emptyDir更像是一個(gè)臨時(shí)磁盤(pán),在Pod重建時(shí)會(huì)被清理重置,不能成為持久化PV來(lái)使用。
為此,我們開(kāi)發(fā)了一個(gè)tidb-volume-manager組件,用于管理Kubernetes集群中每臺(tái)物理主機(jī)上的本地磁盤(pán),并且將其暴露成一種特殊的PV資源。結(jié)合Operator在部署TiDB節(jié)點(diǎn)時(shí)會(huì)參考Local PV資源的情況,來(lái)選擇特定節(jié)點(diǎn)進(jìn)行部署,分配一個(gè)空的Local PV和Pod綁定。而當(dāng)Pod銷(xiāo)毀時(shí),會(huì)根據(jù)具體情況決定是否結(jié)束Local PV的生命周期,釋放掉的Local PV在經(jīng)歷一個(gè)GC周期后,被tidb-volume-manager回收,清理其盤(pán)上數(shù)據(jù)等待再次被分配使用。
(圖:Cloud
TiDB 總體架構(gòu)圖)
將這些組件整合起來(lái),就形成了上圖描述了Cloud TiDB總體架構(gòu)。在Kubenetes管理的集群上,通過(guò)tidb-operator等組件針對(duì)性的調(diào)配和使用集群資源,從而實(shí)現(xiàn)TiDB集群實(shí)例的生命周期管理。通過(guò)這種方式實(shí)現(xiàn)TiDB分布式數(shù)據(jù)庫(kù)和云平臺(tái)的整合。
我們將在下一篇中詳細(xì)介紹針對(duì)Cloud TiDB的關(guān)鍵特性和實(shí)現(xiàn)細(xì)節(jié)。