19 日,我司 CTO 黃東旭同學在全球雲端計算開源大會上,發表了《Cloud-Native 的分散式資料庫架構與實踐》主題演講,以下為演講實錄~~
大家好,今天我的題目是 Cloud-Native 與分散式資料庫的實踐。先簡單的介紹一下自己,我是 PingCAP 的聯合創始人和 CTO,過去一直在做基礎軟體領域的工程師,基本上做的所有的東西都是開源。在分享之前我想說一下為什麼現在各行各業或者整個技術軟體社群一直在重複的再造資料庫,現在資料庫到底怎麼了,為什麼這麼百花齊放?
首先隨著業務的多種多樣,還有不管是傳統行業還是網際網路行業,業務的迭代速度越來越網際網路化,使得整個資料量其實是一直在往上走的;
第二就是隨著 IOT 的裝置還有包括像手機、移動網際網路蓬勃的發展,終端其實也不再僅僅是傳統的 PC 客戶端的資料的接入;
第三方面隨著現在 AI 或者大資料分析一些模型或者理論上的突破,使得在大資料上進行計算的手段越來越多樣,還有在物理上一些硬體的新的帶有保護的記憶體,各種各樣新的物理的裝置,越來越多的硬體或者物理上的儲存成本持續的降低,使得我們的資料庫需要要面對更多的挑戰。
關聯資料庫理論是上世紀七十年代做出來的東西,現在四十年過去不管是物理的環境還是計算模型都是完全不一樣的階段,還抱著過去這種觀念可能並不是一個面向未來的設計。而且今天我的題目是 Cloud-Native,有一個比較大膽的假設,大家在過去三十年的計算平臺基本都是在一臺 PC 或者一個伺服器或者一個手機這樣的獨立的計算平臺,但是未來我覺得一切的服務都應該是分散式的。因為我覺得摩爾定律已經失效了,所以未來的作業系統會是一個大規模分散式的作業系統,在上面跑的任何的程式,任何的服務都應該是分散式的,在這個假設下怎麼去做設計,雲其實是這個假設最好的載體。怎麼在這個假設上去設計面向雲的技術軟體,其實是最近我一直在思考的一個問題。其實在這個時代包括面向雲的軟體,對業務開發來說盡量還是不要太多的改變過去的開發習慣。你看最近大資料的發展趨勢,從最傳統的關聯式資料庫到過去十年相比,整個改變了使用者的程式設計模型,但是改變到底是好的還是不好的,我個人覺得其實並不是太好。最近這兩年大家會看到整個學術圈各種各樣的論文都在迴歸,包括 DB 新時代的軟體都會把擴充套件性和分散式放在第一個要素。
大家可能聽到主題會有點蒙,叫 Cloud-Native,Cloud-Native 是什麼?其實很早的過去也不是沒有人做過這種分散式系統的嘗試,最早是 IBM 提出面向服務的軟體架構設計,最近熱門的 SOA、Micro Service 把自己的服務拆分成小的服務,到現在谷歌一直對外輸出一個觀點就是 Cloud-Native,就是未來大家的業務看上去的分散式會變成一個更加透明的概念,就是你怎麼讓分散式的複雜性消失在雲的基礎設施後,這是 Cloud-Native 更加關心的事情。
這個圖是 CNCF 的一個基金會,也是谷歌支援的基金會上扒過來的圖。這裡面有一個簡單的定義,就是 SCALE 作為一等公民,面向 Cloud-Native 的業務必須是彈性伸縮的,不僅能伸也得能縮;第二就是在對於這種 Cloud-Native 業務來說是面向 Micro service 友好;第三就是部署更加的去人工化。
最近大家可能也看到很多各種各樣容器化的方案,背後代表的意義是什麼?就是整個運維和部署脫離人工,大家可以想象過去十幾二十年來,一直以來運維的手段是什麼樣的。我找了一個運維,去買伺服器,買伺服器裝系統,在上面部署業務。但是現在 Cloud-Native 出現變得非常的自動化,就相當於把人的功能變得更低,這是很有意義的,因為理想中的世界或者未來的世界應該怎麼樣,一個業務可能會有成百上千的物理節點,如果是人工的去做運維和部署是根本不可能做得到的,所以其實構建整個 Cloud-Native 的基礎設施的兩個條件:第一個就是儲存本身的雲化;第二就是運維要和部署的方式必須是雲化的。
我就從這兩個點說一下我們 TiDB 在上面的一些工作和一些我的思考。
儲存本身的雲化有幾個基本條件,大家過去認為是高可用,主要停留在雙活。其實仔細去思考的話,主備的方案是很難保證資料在完全不需要人工的介入情況下資料的一致性可用性的,所以大家會發現最近這幾年出來的分散式儲存系統的可用性的協議跟複製協議基本都會用類似 Raft/Paxos 基於選取的一致性演算法,不會像過去做這種老的複製的方案。
第二就是整個分片的策略,作為分散式系統資料一定是會分片的,資料分片是來做分散式儲存唯一的思路,自動分片一定會取代傳統的人工分片來去支撐業務。比如傳統分片,當你的資料量越來越大,你只能做分庫分表或者用中介軟體,不管你分庫分表還是中介軟體都必須制訂自己人工的分辨規則,但是其實在一個真正面向 Cloud 的資料庫設計裡,任何一種人的介入的東西都是不對的。
第三,接入層的去狀態化,因為你需要面對 Cloud-Native 做設計,你的接入層就不能帶有狀態,你可以相當於是前端的接入層是一層無狀態的或者連線到任何一個服務的接入的入口,對你來說應該都是一樣的,就是說你不能整個系統因為一個關鍵元件的損壞或者說磁碟壞掉或者機器的當機,整個系統就不能服務了,整個測試系統應該具有自我癒合和自我維護的能力。
其實我本身是架構師,所以整個我們資料庫的設計都是圍繞這些點來做思考的,就是一個資料庫怎麼能讓他自我的生長,自我的維護,哪怕出現任何的災難性的物理故障(有物理故障是非常正常的,每天在一個比較大的叢集的規模下,網路中斷、磁碟損壞甚至是很多很詭異的問題都是很正常的),所以怎麼設計這種資料庫。
我們的專案是 TiDB,我不知道在座的有沒有聽說過這個專案,它其實是一個開源實現。當你的業務已經用了資料庫,資料量一大就有可能遇到一些問題,一個是單點的可靠性的問題,還有一個資料容量怎麼去彈性伸縮的問題。TiDB 就能解決這個問題,它本身對外暴露了一個介面,你可以用客戶端去連線,你可以認為你下面面對的是一個彈性動態伸縮完全沒有容量限制,同時還可以在上面支援複雜的子查詢的東西。底層儲存的話,相當於這一層無狀態的會把這個請求發到底層的節點上,這個儲存裡面的資料都是通過協議做高可用和複製的,這個資料在底層會不停的分裂和移動,你可以認為這個資料庫是一個活的資料庫,你任何一個節點的當機都不會影響整個資料庫對業務層的使用,包括你可以跨資料中心部署,甚至你在跨資料中心的時候,整個資料中心網路被切斷,機房著火,業務層都幾乎完全是透明的,而且這個資料比如副本丟失會自己去修復,自己去管理或者移動資料。
上圖右邊是一個叢集的排程模組,你可以認為它是整個叢集的大腦,是一個 7×24 小時不眠的 DBA,你任何的業務可以接上來。NewSQL 這個詞大家聽的都爛了,但是我還是想提,首先它是一個面向擴充套件的資料庫,同時它還結合的傳統管理資料庫的強一致事務,必須得是 SSI 隔離級別的,並不是非常弱根本沒法用的隔離級別,而是需要提供最強一致性的隔離級別的資料庫。擴充套件性其實是通過在 TiKV 層面做完全自動分片,可用性是通過 Raft 為保證,我們整個資料庫沒有主從的概念,每一個節點既可以是主又可以是從,然後整個資料複製通過 Raft 為保證,對外的是一個強一致性的事務層,其實背後的演算法是用兩階段提交的演算法,比如一個最簡單的例子,我一百個併發過來很快,每個平均十毫秒訪問資料,一百個併發,一百萬個併發,你還能保證每一個請求都是十毫秒返回資料嗎?那我可以簡單的通過新增機器把系統的吞吐加上去,每一個吞吐的響應延遲會更大一些,在論文裡提到過,谷歌資料庫寫的每一個平均延遲是 150 到 100 毫秒,可以做到線性擴充套件。所以終於有一個資料庫可以 scable。剛才說的是儲存層面的雲化,剛才提到了 Cloud-Native 還有一個重要的點就是部署和運維方式的雲化,我們其實選的這個 Kubernetes 就是用來承載背後資料庫大規模叢集上的部署,其實大家都知道這個是什麼東西,這是最出名的開源專案之一,谷歌開源的,大家也知道 borg,就是他們用了這麼多年的叢集排程服務,主要做的事情就是服務的編排、部署、自動化的運維,一臺物理機掛掉了,他會很好的讓這個業務不中斷,像叢集排程器,它就是整個資料中心的作業系統,但是面臨最大的問題就是所有的業務一旦是有狀態的,那你這個就非常噁心。舉個案例,比如我在跑一個資料庫,如果你這臺物理機當機,按照 Kubernetes 會開一個伺服器在那邊展開,但是這一臺老的當機伺服器資料是存在上面的,你不能只是把程式在新的伺服器那啟起來而資料不帶過去,相當於這種業務是帶狀態的,這在 Kubernetes 過去是一個老大難的問題,其實整個應用層,因為它的特性被分成了四個大的陣營,如果想上可以看一下自己的業務到底屬於哪一個陣營。
第一個就是完全無狀態的業務,比如這是一個簡單的 CRUD 業務層的邏輯,其實是無狀態的應用層。第二種就是單點的帶狀態的 applications,還有任何單機的資料庫其實都有屬於 applications。第三個就是 Static distributed,比如高可用的分散式服務,大家也不會做擴容什麼的,這種是靜態的分散式應用。還有最難的一個問題,就是這種叢集型的 applications,clustered 是沒有辦法很好的排程服務的。這是剛才說的,其實對於 Single point,其實是很好解決的,對於靜態的其實也是用 Static distributed 來解決帶狀態的持續化的方案。
剛才我說最難的那個問題,我們整個架構中引入了 Operational,排程一套有狀態服務的方案,其實它思路也很簡單,就是把運維分佈人員系統的領域知識給嵌入到了系統中,Knowledge 釋出排程任務之前都會相當於被 CoreOS 提供的介面以後再排程業務,這套方案依賴了 HtirdPartyResources 排程,因為這個裡面我的狀態我自己才知道,這個時候你需要通過把你的系統領域知識放到 operator 裡。很簡單,就是 Create 用 TiDB Operator 來實現,還有 Rollingupdate 和 Scale Out 還有 Failover 等。使用 Kubemetes 很重要的原因就是它只用到了很毛的一層 API,內部大量的邏輯是在 Operator 內部,而且像 PV/Statefulset 中並不是一個很好的方案,比如 PV 實現你可以用分散式檔案系統或者快儲存作為你持久化的這一層,但是資料庫的業務,我對我底層的 IO 或者硬體有很強的掌控力的,我在我的業務層自己做了三副本和高可用,我其實就不需要在儲存層面上比如我在一個裸盤上跑的效能能比其他上快十倍,這個時候你告訴我不好意思下面只支援 statefulset 那這是不適合跑資料庫的,也就是資料庫叢集是跟它的普通的雲盤或者雲端儲存的業務是分開的。
分散式資料庫也不是百分之百所有的業務場景都適合,特別是大規模的分散式資料庫來說,比如自增 ID,雖然我們支援,但是自增 IT 高壓力寫入的時候它的壓力會集中在表的末尾,其實是我不管怎麼排程總會有一塊熱點,當然你可以先分表,最後我們聚合分析也沒有問題,像秒殺或者特別小的表,其實是完全不適合在這種分散式資料庫上做的,比較好的一些實踐業務的讀寫比較平均,資料量比較大,同時還有併發的事務的支援,需要有事務的支援,但並不是衝突特別大的場景,並不是秒殺的場景,同時你又可以需要在上面做比較複雜的分析,比如現在我們的一些線上的使用者特別好玩,過去它的業務全都是跑在 MySQL 上,一主多從,他發現我一個個 MySQL 成為了資訊的孤島,他並沒有辦法做聚合地分析,過去傳統的方案就是我把 MySQL 或者資料通過一個 ETL 流程導到資料倉儲裡,但是開發者不會用各種琳琅滿目大資料的東西,他只會用 MySQL,一般他做的資料分析都會把 MySQL 倒騰到一個庫上再做分析,資料量一大堆分析不出來,這個時候他把所有他自己的 MySQL 總庫連到了一個 TiDB上,過去是一主多從,先多主多從,把所有的從都打通,做 MySQL 的分析,所以我覺得 TiDB 打造了新的模型,可以讀寫高併發的事務,所以未來的資料庫會是一個什麼樣子的,我覺得可能是至少我們覺得沿著這條路走下去應該會有一條新的路,謝謝大家。