摘要:我們通常會說我們要做一個分布式數(shù)據(jù)庫,自動彈性伸縮,能解決分庫分表的問題,你會用嗎用戶說那肯定啊,現(xiàn)在的分庫分表太痛苦了。在軟件開發(fā)領(lǐng)域有一條非常經(jīng)典的哲學(xué)。作為一個分布式數(shù)據(jù)庫,每一層的穩(wěn)定性都非常重要。
本文根據(jù)我司 CEO 劉奇在第 100 期 Infra Meetup 上的演講整理,預(yù)計閱讀時間為 30 分鐘。
大家可能知道我是 PingCAP CEO,但是不知道的是,我也是 PingCAP 的產(chǎn)品經(jīng)理,應(yīng)該也是最大的產(chǎn)品經(jīng)理,是對于產(chǎn)品重大特性具有一票否決權(quán)的人。中國有一類產(chǎn)品經(jīng)理是這樣的,別人有的功能我們統(tǒng)統(tǒng)都要有,別人沒有的功能,我們也統(tǒng)統(tǒng)都要有,所以大家看到傳統(tǒng)的國內(nèi)好多產(chǎn)品就是一個超級巨無霸,功能巨多、巨難用。所以我在 PingCAP 的一個重要職責(zé)是排除掉“看起來應(yīng)該需要但實際上不需要”的那些功能,保證我們的產(chǎn)品足夠的專注、足夠聚焦,同時又具有足夠的彈性。一、最初的三個基本信念
本次分享題目是《TiDB 的架構(gòu)演進(jìn)哲學(xué)》,既然講哲學(xué)那肯定有故事和教訓(xùn),否則哲學(xué)從哪兒來呢?但從另外的角度來說,一般大家來講哲學(xué)就先得有信念。有一個內(nèi)容特別扯的美劇叫做《美國眾神》,里面核心的一條思路是“你相信什么你就是什么”。其實人類這么多年來,基本上也是朝這條線路在走的,人類對于未知的東西很難做一個很精確的推導(dǎo),這時信念就變得非常重要了。
實際上,我們開始做 TiDB 這個產(chǎn)品的時候,第一個信念就是相信云是未來。當(dāng)年 K8s 還沒火,我們就堅定的擁抱了 K8s。第二是不依賴特定硬件、特定的云廠商,也就是說 TiDB 的設(shè)計方向是希望可以 Run 在所有環(huán)境上面,包括公有云私有云等等。第三是能支持多種硬件,大家都知道我們支持 X86、AMD64、ARM 等等,可能大家不清楚的是 MIPS,MIPS 典型代表是龍芯,除此之外,TiDB 未來還可以在 GPU 上跑(TiFlash 的后續(xù)工作會支持 GPU)。
二、早期用戶故事 2.1 Make it work有一句話大概是“眼睛里面寫滿了故事,臉上沒有一點滄桑”,其實現(xiàn)實是殘酷的,歲月一定會給你滄桑的。我們早期的時候,也有相對比較難的時候,這時候就有一些故事關(guān)于我們怎么去經(jīng)歷、怎么渡過的。 ?
首先大家做產(chǎn)品之前肯定先做用戶調(diào)研,這是通用的流程,我們當(dāng)初也做過這個事,跟用戶聊。我們通常會說:“我們要做一個分布式數(shù)據(jù)庫,自動彈性伸縮,能解決分庫分表的問題,你會用嗎?”用戶說“那肯定啊,現(xiàn)在的分庫分表太痛苦了?!边@是最初我們獲取需求最普通的方式,也是我們最容易掉入陷阱的方式,就好像“我有一百萬,你要不要?肯定要?!薄拔矣幸黄克?,喝了之后就健康無比,延年益壽你要不要?肯定要?!焙苋菀拙偷玫筋愃频慕Y(jié)論。
所以這個一句話結(jié)論的代價是我們進(jìn)行了長達(dá)兩年的開發(fā)。在這兩年的時間里,我們確定了很多的技術(shù)方向,比如最初 TiDB 就決定是分層的。很顯然一個復(fù)雜的系統(tǒng)如果沒有分層,基本上沒有辦法很好的控制規(guī)模和復(fù)雜度。TiDB 分兩層,一層是 SQL 層,一層是 key-value 層,那么到底先從哪一個層開始寫呢?其實從哪層開始都可以,但是總要有一個先后,如何選擇?
這里就涉及到 TiDB 的第一條哲學(xué)。我們做一個產(chǎn)品的時候會不斷面臨選擇,那每次選擇的時候核心指導(dǎo)思想是什么?核心思想是能一直指導(dǎo)我們持續(xù)往前去迭代,所以我們第一條哲學(xué)就是:永遠(yuǎn)站在離用戶更近的地方去考慮問題。
為什么我們會定義這樣一條哲學(xué)?因為離用戶越近越能更快的得到用戶的反饋,更快的驗證你的想法是不是可行的。顯然 SQL 層離用戶更近,所以我們選擇從 SQL 層寫起。其實一直到現(xiàn)在,絕大多數(shù)用戶用 TiDB 的時候根本感受不到 KV 層的存在,用戶寫的都是 SQL,至于底層存儲引擎換成了別的,或者底層的 RocksDB 做了很多優(yōu)化和改進(jìn),這些變化對于用戶關(guān)注的接口來說是不可見的。
選擇從 SQL 層開始寫之后,接下來面臨的問題就是怎么做測試,怎么去更好的做驗證,怎么讓整個架構(gòu),先能夠完整跑起來。
在軟件開發(fā)領(lǐng)域有一條非常經(jīng)典的哲學(xué):「Make it work, make it right, make it fast」。我想大家每一個學(xué)軟件開發(fā)的人,或者每一個學(xué)計算機(jī)的人可能都聽過這樣一句話。所以當(dāng)時我們就做另外一個決定,先在已有的 KV 上面構(gòu)建出一個原形,用最短的時間讓整個系統(tǒng)能夠先能 work。
我們在 2015 年的 9 月份開源了第一個版本,當(dāng)時是沒有存儲層的,需要接在 HBase 上。當(dāng)這個系統(tǒng)能跑起來之后,我們的第一想法是趕緊找到當(dāng)初調(diào)研時說要用的那些用戶,看看他們是什么想法,盡快的去驗證我們的想法是不是可行的。因為很多人做產(chǎn)品思維屬于自嗨型,“我做的東西最厲害,只要一推出去肯定一群人蜂擁而至?!北в羞@種想法的人太多了,實際上,只有盡快去驗證才是唯一的解決之道,避免產(chǎn)品走入誤區(qū)。
然而當(dāng)我跟用戶講,你需要先裝一個 Hadoop,可能還要裝一組 Zookeeper,但用戶說:“我只想要一個更強大的 MySQL,但是讓我裝這一堆東西,你是解決問題還是引入問題?”
這個問題有什么解決辦法呢?一個辦法是你去解決用戶,可以通過銷售或者通過某些關(guān)系跟用戶聊,顯然這是一個不靠譜的思路。作為一個產(chǎn)品型的公司,我們很快就否了這個想法。用戶的本質(zhì)要求是:你不要給我裝一堆的東西,要真正解決我的問題。所以我們馬上開始啟動分布式 KV 的開發(fā)工作,徹底解決掉這個問題,滿足用戶的要求。
開始開發(fā) KV 層時候又會面臨很多技術(shù)選擇,我們有很多考量(如圖 3)。
第一點,我們認(rèn)為作為數(shù)據(jù)庫最重要的是正確性。 假設(shè)這個數(shù)據(jù)庫要用在金融行業(yè),用在銀行、保險、證券,和其他一些非常關(guān)鍵的場合的時候,正確性就是無比重要的東西。沒有人會用一個不正確的數(shù)據(jù)庫。
第二點是實現(xiàn)簡潔、易用。 用戶對于一個不簡潔、不易用的東西是無法接受的,所以我們當(dāng)時的一個想法是一定要做得比 HBase 更加易用,代碼量也要比 HBase 小,所以時至今天 TiDB 代碼量仍然是比 HBase 小得多,大約還不到 HBase 的十分之一。
第三點考慮是擴(kuò)展性。?TiDB 不僅在整體上是分層的,在存儲層 TiKV 內(nèi)部也是分層的,所以有非常好的擴(kuò)展性,也支持 Raw KV API、Transaction API,這個設(shè)計后來也收獲了很多用戶的支持,比如一點資訊的同學(xué)就是用的 Raw KV API。
第四點就是要求高性能低延遲。 大家對于數(shù)據(jù)庫的性能和延遲的追求是沒有止境的,但是我們當(dāng)時并沒有把太多精力花在高性能低延遲上。剛才說到我們有一條哲學(xué)是「Make it work, make it right, make it fast」,大家可以看到這句話里面 「Fast」是放最后的,這一點也是 TiDB 和其他產(chǎn)品有非常大的差異的地方。作為一個技術(shù)人員,通常大家看一個產(chǎn)品好不好,就會想:“來,不服跑個分,產(chǎn)品架構(gòu)、易用性、技術(shù)文檔、Community 這些指標(biāo)都不看,先跑個分讓大家看看行不行”。這個思路真正往市場上去推時是不對的。很多事情的選擇是一個綜合的過程。你可以讓你的汽車跑的巨快無比,上面東西全拆了就留一個發(fā)動機(jī)和四個輪子,那肯定也是跑得巨快,重量輕,而且還是敞篷車,但沒有一個人會在路上用的。同樣的,選擇 Rust 也是綜合考量的結(jié)果。我們看中了 Rust 這個非常具有潛力的語言。當(dāng)時 Rust 沒有發(fā)布 1.0,還不是一個 stable 版本,但我們相信它會有 1.0。大概過了幾個月,Rust 就發(fā)布了 1.0 版本,證明我們的選擇還是非常正確的。
最后一點就是穩(wěn)定性。 作為一個分布式數(shù)據(jù)庫,每一層的穩(wěn)定性都非常重要。最底下的一個存儲引擎,我們選擇了非常穩(wěn)定的 RocksDB。不過后來我們也查到幾個 RocksDB 掉數(shù)據(jù)的 Bug。這也是做數(shù)據(jù)庫或者說做基礎(chǔ)產(chǎn)品的殘酷性,我們在做產(chǎn)品的過程中找到了 Rust 編譯器的 Bug,XFS 掉數(shù)據(jù)的 Bug,RocksDB 掉數(shù)據(jù)的 Bug,好像幾大基礎(chǔ)組件的 Bug 都聚在這里開會。
接著我們辛辛苦苦干了三個月,然后就開源了 TiKV,所以這時候看起來沒有那么多的組件了。我們也不忘初心,又去找了我們當(dāng)初那個用戶,說我們做了一些改進(jìn),你要不要試一試。
但是用戶這時候給了一個讓我們非常傷心非常難受的回答:沒有,我們不敢上線,雖然你們的產(chǎn)品聽起來挺好的,但是數(shù)據(jù)庫后面有很大的責(zé)任,心理上的擔(dān)心確實是過不去。于是我們回去開始加班加點寫 TiDB Binlog,讓用戶可以把 binlog 同步給 MySQL。畢竟用戶需要一個 Backup:萬一 TiDB 掛了怎么辦,我需要切回 MySQL,這樣才放心,因為數(shù)據(jù)是核心資產(chǎn)。
所以最終我們第一個用戶上線的時候,整個 TiDB 的架構(gòu)是這樣的(如圖 5)。用戶通過 Client 連上 TiDB,然后 TiDB 后面就通過 Binlog 同步到 MySQL。后來過了一段時間,用戶就把后面的 MySQL 撤了。我們當(dāng)時挺好奇為什么撤了,用戶說,第一個原因是后面 MySQL 撐不起一個集群給它回吐 Binlog,第二就是用了一段時間覺得 TiDB 挺穩(wěn)定的,然后就不需要 Binlog 備份了。
其實第一個用戶上線的時候,數(shù)據(jù)量并不算大,大概 800G 的數(shù)據(jù),使用場景是 OLTP 為主,有少量的復(fù)雜分析和運算,但這少量的復(fù)雜分析運算是當(dāng)時他們選擇 TiDB 最重要的原因。因為當(dāng)時他們需要每隔幾分鐘算一個圖出來,如果是在 MySQL 上面跑,大約需要十幾分鐘,但他們需要每隔幾分鐘打一個點,后來突然發(fā)現(xiàn)第二天才能把前一天的點都打出來,這對于一個實時的系統(tǒng)來說就很不現(xiàn)實了。雖然這個應(yīng)用實踐只有少部分運算,但也是偏 OLAP,我記得 TiDB 也不算特別快,大概是十幾秒鐘,因為支持了一個并行的 Hash Join。
不管怎樣,這個時候終于有第一個用戶能證明我們做到了「Make it work」。
2.2 Make it right接下來就是「Make it right」。大家可能想象不到做一個保證正確性的數(shù)據(jù)庫這件事情有多么難,這是一個巨大的挑戰(zhàn),也有巨大的工作量,是從理論到實踐的距離。
大家可能會想寫程序跟理論有什么關(guān)系?其實在分布式數(shù)據(jù)庫領(lǐng)域是有一套方法論的。這個方法論要求先實現(xiàn)正確性,而實現(xiàn)正確的前提是有一個形式化的證明。為了保證整個系統(tǒng)的理論正確,我們把所有的核心算法都用 TLA+ 寫了一遍證明,并且把這個證明開源出去了,如果大家感興趣可以翻看一下(https://github.com/pingcap/tla-plus)。以前寫程序的時候,大家很少想到先證明一下算法是對的,然后再把算法變成一個程序,其實今天還有很多數(shù)據(jù)庫廠商沒有做這件事。
2.2.2 千萬級別測試用例在理論上保證正確性之后,下一步是在現(xiàn)實中測試驗證。這時只有一個辦法就是用非常龐大的測試用例做測試。大家通常自己做測試的時候,測試用例應(yīng)該很少能達(dá)到十萬級的規(guī)模,而我們現(xiàn)在測試用例的規(guī)模是以千萬為單位的。當(dāng)然如果以千萬為單位的測試用例靠純手寫不太現(xiàn)實,好在我們兼容了 MySQL 協(xié)議,可以直接從 MySQL 的測試用例里收集一些。這樣就能很快驗證整個系統(tǒng)是否具備正確性。
這些測試用例包括應(yīng)用、框架、管理工具等等。比如有很多應(yīng)用程序是依賴 MySQL,那直接拿這個應(yīng)用程序在 TiDB 上跑一下,就知道 TiDB 跟 MySQL 的兼容沒問題,如 Wordpress、無數(shù)的 ORM 等等。還有一些 MySQL 的管理工具可以拿來測試,比如 Navicat、PHP admin 等。另外我們把公司內(nèi)部在用的 Confluence、Jira 后面接的 MySQL 都換成了 TiDB,雖然說規(guī)模不大,但是我們是希望在應(yīng)用這塊有足夠的測試,同時自己「Eat dog food」。
2.2.3 7*24 的錯誤注入測試用例這些工作看起來已經(jīng)挺多的了,但實際上還有一塊工作比較消耗精力,叫 7*24 的錯誤注入測試。最早我們也不知道這個測試這么花錢,我們現(xiàn)在測試的集群已經(jīng)是幾百臺服務(wù)器了。如果創(chuàng)業(yè)的時候就知道需要這么多服務(wù)器測試,我們可能就不創(chuàng)業(yè)了,好像天使輪的融資都不夠買服務(wù)器的。不過好在這個事是一步一步買起來,剛開始我們也沒有買這么多測試服務(wù)器,后來隨著規(guī)模的擴(kuò)大,不斷的在增加這塊的投入。
大家可能到這兒的時候還是沒有一個直觀的感受,說這么多測試用例,到底是一個什么樣的感受。我們可以對比看一下行業(yè)巨頭 Oracle 是怎么干的。
這是一篇在 HackNews上面的討論,討論的問題是:你覺得這個最壞的、規(guī)模最大的代碼是什么樣子的?下面就有一個 Oracle 的前員工就介紹了 Oracle Database 12.2 這個版本的情況。他說這個整體的源代碼接近 2500 萬行 C 代碼,可能大家維護(hù) 25 萬行 C 代碼的時候就會痛不欲生了,可以想想維護(hù)這么多代碼的是一種什么樣的感受。到現(xiàn)在為止,TiDB 的代碼應(yīng)該還不到 25 萬行。當(dāng)然 TiDB 的功能遠(yuǎn)遠(yuǎn)沒有 Oracle 那么多,Oracle 的功能其實是很多的,歷史積累一直往上加,加的很兇。
這位 Oracle 前員工介紹了自己在 Oracle 的開發(fā)工作的流程,如下圖:
比如用戶報了一個 Bug,然后他開始 fix。第一件事是花兩周左右的時間去理解 20 個不同的 flag,看看有沒有可能因為內(nèi)部亂七八糟的原因來造成這個 Bug。大家可能不知道 MySQL 有多少變量,我剛做 TiDB 的時候也不知道,當(dāng)時我覺得自己是懂?dāng)?shù)據(jù)庫的,后來去看了一下 MySQL 的 flag 的變量數(shù)就驚呆了,但看到 Oracle 的 flag 變量數(shù),那不是驚呆了,是絕望了。大家可能知道開啟 1 個 flag 的時候會對什么東西有影響,但是要去理解 20 個 flag 開啟時和另外幾個 flag 組合的時候都有什么影響,可能會崩潰。所以其實精通 Oracle 這件事情,實際上可能比精通 C++ 這件事情更困難的。一個 Oracle 開發(fā)者在內(nèi)部處理這件事情都這么復(fù)雜,更何況是外面的用戶。但 Oracle 確實是功能很強大。
說回這位前 Oracle 員工的描述,他接著添加了更多的 flag 處理一個新的用戶場景的問題,然后加強代碼,最后改完以后會提交一個測試。先在 100 到 200 臺機(jī)器上面把這個 Oracle 給 build 出來,然后再對這個 Oracle 去做新的測試。他應(yīng)該對 Oracle 的測試用例的實際數(shù)量了解不深刻,我猜他可能不知道 Oracle 有多少個測試,所以寫的是 “millions of tests”,這顯然太低估了 Oracle 的測試數(shù)量。通常情況下,只會看到掛了的測試,看不到全部的測試數(shù)量。
下面的步驟更有意思了:Go home,因為整個測試需要 20-30 個小時,跑完之后測試系統(tǒng)反饋了一個報告:掛了 200 多個 test,更茫然的是這 200 tests 他以前都沒見過,這也是 Oracle 非常強大的一個地方,如果一個開發(fā)者的代碼提交過去掛掉一兩百個測試,是很正常的事情,因為 Oracle 的測試能 Cover 東西非常多,是這么多年來非常強大的積累,不停的堆功能的同時就不停的堆測試,當(dāng)然也不停的堆 flag。所以從另一個角度來看,限制一個系統(tǒng)的功能數(shù)量,對于維護(hù)來說是非常重要的。
總之,看完這個回復(fù)之后,我對行業(yè)前輩們充滿了敬畏之情。
2.3 Make it fast 2.3.1 新問題隨著 TiDB 有用戶開始上線,用戶的數(shù)量和規(guī)模越來越大,這時候就出現(xiàn)了一個很有意思的事情,一部分用戶把 TiDB 當(dāng)成了可以支持事務(wù)、擁有良好實時性的數(shù)據(jù)倉庫在用,和我們說:我們把公司 Hadoop 換了,數(shù)據(jù)量十幾 T。
我們就一下開始陷入了深深的思考,因為 TiDB 本來設(shè)計的目的不是這個方向,我們想做一個分布式 OLTP 數(shù)據(jù)庫,并沒有想說我們要做一個 Data Warehouse。但是用戶的理由讓我們覺得也很有道理,無法反駁——TiDB 兼容 MySQL,會 MySQL 的人很多,更好招人,最重要的是 Hadoop 跑得還不夠快。
雖然我們自己也很吃驚,但這體現(xiàn)了 TiDB 另一方面的價值,所以我們繼續(xù)問用戶還有什么痛點。用戶表示還有一部分查詢不夠快,數(shù)據(jù)沒辦法做到 shuffle,而且以前用 Spark,TiDB 好像沒有 Spark 的支持。
我們想了想,TiDB 直接連 Spark 也是可以的,但這樣 Spark 對底下沒有感知,事務(wù)跑得巨慢,就跟 Spark 接 MySQL 沒什么差別。我們研究了一下,做出了一個新的東西——TiSpark。TiSpark 就開始能夠同時在 TiDB 上去跑 OLAP 和 OLTP。
就在我們準(zhǔn)備改進(jìn) TiDB 的數(shù)據(jù)分析能力的時候,突然又有一大批 TP 用戶上線了,給我們報了一堆問題,比如執(zhí)行計劃不準(zhǔn)確,選不到最優(yōu)執(zhí)行計劃,數(shù)據(jù)熱點分布不均勻,Raft store 單線程寫入瓶頸,報表跑的慢等等……于是我們制定了 1.0 到 2.X 的計劃,先把用戶提的這些問題一一解決。
這里有另外一條哲學(xué):將用戶遇到的問題放在第一優(yōu)先級。我們從產(chǎn)品最初設(shè)計和之后 Roadmap 計劃永遠(yuǎn)是按照這個原則去做的。
首先,執(zhí)行計劃不準(zhǔn)確的問題。 最簡單有效的解決辦法是加一個 Index Hint,就像是“你告訴我怎么執(zhí)行,我就怎么執(zhí)行,我自己不會自作聰明的選擇”。但這不是長久之計,因為用戶可能是在一個界面上選擇各種條件、參數(shù)等等,最后拼成一個 SQL,他們自己沒辦法在里面加 Index Hint。我們不能決定用戶的使用習(xí)慣,所以從這時開始,我們決定從 RBO(Rule Based Optimizer)演進(jìn)到 CBO(Cost Based Optimizer),這條路也走了非常久,而且還在持續(xù)進(jìn)行。
第二個是熱點數(shù)據(jù)處理問題。 我們推出了一個熱點調(diào)度器,這個可能大家在分布式數(shù)據(jù)庫領(lǐng)域第一次聽說,數(shù)據(jù)庫領(lǐng)域應(yīng)該是 PingCAP 首創(chuàng)。 熱點調(diào)度器會統(tǒng)計、監(jiān)控整個系統(tǒng)熱點情況,再把這些熱點做一個快速遷移和平衡,比如整個系統(tǒng)有 10 個熱點,某一個機(jī)器上有 6 個熱點,這臺機(jī)器就會很卡,這時熱點調(diào)度器會開始將熱點打散,快速分散到集群的其他機(jī)器上去,從而讓整個集群的機(jī)器都處于比較正常的負(fù)載狀態(tài)。
第三個就是解決 Raft store 單線程瓶頸的問題。為了改變 Raft store 單線程,我們大概花了一年多的時間,目前已經(jīng)在 TiDB 3.0 里實現(xiàn)了。我們將 Raft store 線程更多耗時的計算變成異步操作,offload 到其它線程。不知道有沒有人會好奇為什么這個改進(jìn)會花這么長時間?我們一直認(rèn)為數(shù)據(jù)庫的穩(wěn)定性第一位的。分布式系統(tǒng)里面一致性協(xié)議本身也復(fù)雜,雖然說 Raft 是比 Paxos 要簡單,但它實際做起來也很復(fù)雜,要在一個復(fù)雜系統(tǒng)里支持多線程,并且還要做優(yōu)化,盡可能讓這個 I/O 能 group 到一起,其實非常耗精力。
第四個就是解決報表跑得慢的問題,這個骨頭特別硬,我們也是啃到今天還在繼續(xù)。首先要大幅提升 TiDB 在分析場景下的能力。大家都可以看到我們在發(fā)布每一個版本的時候,都會給出與上一個版本的 TPC-H 性能對比(TPC-H 是一個有非常多的復(fù)雜查詢、大量運算的場景)。其次就是高度并行化,充分利用多核,并提供參數(shù)控制,這個特性可能很多用戶不知道,我們可以配一下參數(shù),就讓 TiDB 有多個并發(fā)在底層做 Scan(https://github.com/pingcap/docs-cn/blob/master/v2.1/sql/tidb-specific.md)。
解決完這些問題,我們終于覺得可以喘口氣了,但喘氣的時間就不到一個星期,很快又有很多用戶的反饋開始把我們淹沒了。因為隨著用戶規(guī)模的擴(kuò)大,用戶反饋問題的速度也變得越來越快,我們處理的速度不一定跟的上用戶的增速。
2.3.4 新呼聲這時候我們也聽到了用戶的一些「新呼聲」。
有用戶說他們在跑復(fù)雜查詢時 OLTP 的查詢延遲變高了,跑一個報表的時候發(fā)現(xiàn) ?OLTP 開始卡了。這個問題的原因是在跑復(fù)雜查詢的時候,SQL 資源被搶占。我們又想有沒有可能將 OLAP 和 OLTP 的 Workload 分開?于是我們搞了第一個實驗版本,在 TiKV 里把請求分優(yōu)先級,放到不同隊列里面去,復(fù)雜 Query 放在第一優(yōu)先級的隊列, OLTP 放在高優(yōu)先級。然后我們發(fā)現(xiàn)自己是對報表理解不夠深刻,這個方案只能解決一部分用戶的問題,因為有的報表跑起來需要幾個小時,導(dǎo)致隊列永遠(yuǎn)是滿的,永遠(yuǎn)搶占著系統(tǒng)的資源。還有一部分用戶的報表沒有那么復(fù)雜,只是希望報表跑得更快、更加實時,比如一個做餐飲 SaaS 的用戶,每天晚上需要看一下餐館營收情況,統(tǒng)計一家餐館時速度還行,如果統(tǒng)計所有餐館的情況,那就另說了。
另外,報表有一些必需品,比如 View 和 Window Function,沒有這些的話 SQL 寫起來很痛苦,缺乏靈活度。
與此同時,用戶關(guān)于兼容性和新特性的要求也開始變多,比如希望支持 MySQL 類似的 table partition,還有銀行用戶習(xí)慣用悲觀鎖,而 TiDB 是樂觀鎖,遷移過來會造成額外的改造成本(TiDB 3.0 已經(jīng)支持了悲觀鎖)。
還有用戶有 400T 的數(shù)據(jù),沒有一個快速導(dǎo)入的工具非常耗時(當(dāng)然現(xiàn)在我們有快速導(dǎo)入工具TiDB Lightning),這個問題有一部分原因在于用戶的硬件條件限制,比如說千兆網(wǎng)導(dǎo)入數(shù)據(jù)。
還有些用戶的數(shù)據(jù)規(guī)模越來越大,到 100T 以上就開始發(fā)現(xiàn)十分鐘已經(jīng)跑不完 GC 了(TiDB 的 GC 是每十分鐘一次),一個月下來 GC 已經(jīng)整體落后了非常多。
我們當(dāng)時非常頭痛,收到了一堆意見和需求,壓力特別大,然后趕緊匯總了一下,如圖 10 所示。
面對這么多的需求,我們考慮了兩個點:
哪些是共性需求?
什么是徹底解決之道?
把共性的需求都列在一塊,提供一個在產(chǎn)品層面和技術(shù)層面真正的徹底的解決辦法。
比如圖 10 列舉的那么多問題,其實真正要解決三個方面:性能、隔離和功能。性能和隔離兼得好像很困難,但是這個架構(gòu)有非常獨特的優(yōu)勢,也是可以做得到的。那可以進(jìn)一步「三者兼得」,同時解決功能的問題嗎?我們思考了一下,也是有辦法的。TiDB 使用的 Raft 協(xié)議里有一個 Raft Learner 的角色,可以不斷的從 Leader 那邊復(fù)制數(shù)據(jù),我們把數(shù)據(jù)同步存成了一個列存,剛才這三方面的問題都可以用一個方案去徹底解決了。
首先復(fù)雜查詢的速度變快了,眾所周知分析型的數(shù)據(jù)引擎基本上全部使用的是列存。第二就是強一致性,整個 Raft 協(xié)議可以保證從 Learner 讀數(shù)據(jù)的時候可以選擇一致性的讀,可以從 Leader 那邊拿到 Learner 當(dāng)前的進(jìn)度,判斷是否可以對外提供請求。第三個是實時性可以保證,因為是通過 streaming 的方式復(fù)制的。
所以這些看上去非常復(fù)雜的問題用一個方案就可以解決,并且強化了原來的系統(tǒng)。這個「強化」怎么講?從用戶的角度看,他們不會考慮 Query 是 OLAP 還是 OLTP,只是想跑這條 Query,這很合理。用一套東西解決用戶的所有問題,對用戶來說就是「強化」的系統(tǒng)。
三、關(guān)于成本問題的思考很多用戶都跟我們反饋了成本問題,用戶覺得全部部署到 ?SSD 成本有點高。一開始聽到這個反饋,我們還不能理解,SSD 已經(jīng)很便宜了呀,而且在整個系統(tǒng)來看,存儲機(jī)器只是成本的一小部分。后來我們深刻思考了一下,其實用戶說得對,很多系統(tǒng)都是有早晚高峰的,如果在幾百 T 數(shù)據(jù)里跑報表,只在每天晚上收工時統(tǒng)計今天營業(yè)的狀況,那為什么要求用戶付出最高峰值的配置呢?這個要求是不合理的,合不合理是一回事,至于做不做得到、怎么做到是另外一回事。
于是我們開始面臨全新的思考,這個問題本質(zhì)上是用戶的數(shù)據(jù)只有一部分是熱的,但是付出的代價是要讓機(jī)器 Handle 所有的數(shù)據(jù),所以可以把問題轉(zhuǎn)化成:我們能不能在系統(tǒng)里面做到冷熱數(shù)據(jù)分離?能不能支持系統(tǒng)動態(tài)彈性的伸縮,伸展熱點數(shù)據(jù),用完就釋放?
如果對一個系統(tǒng)來說,峰值時段和非峰值時段的差別在于峰值時段多了 5% 的熱點。我們有必要去 Handle 所有的數(shù)據(jù)嗎?所以徹底的解決辦法是對系統(tǒng)進(jìn)行合理的監(jiān)控,檢測出熱點后,馬上創(chuàng)建一個新的節(jié)點,這個新的節(jié)點只負(fù)責(zé)處理熱點數(shù)據(jù),而不是把所有的數(shù)據(jù)做動態(tài)的 rebalance,重新搬遷。在峰值時間過去之后就可以把復(fù)制出來的熱點數(shù)據(jù)撤掉,占的這個機(jī)器可以直接停掉了,不需要長時間配備非常高配置的資源,而是動態(tài)彈性伸縮的。
TiDB 作為一個高度動態(tài)的系統(tǒng),本身的架構(gòu)就具有非常強的張力,像海綿一樣,能夠滿足這個要求,而且能根據(jù)系統(tǒng)負(fù)載動態(tài)的做這件事。這跟傳統(tǒng)數(shù)據(jù)庫的架構(gòu)有很大的區(qū)別。比如有一個 4T 的 MySQL 數(shù)據(jù)庫,一主一從,如果主庫很熱,只能馬上搞一個等配的機(jī)器重掛上去,然后復(fù)制全部數(shù)據(jù),但實際上用戶需要的只是 5% 的熱數(shù)據(jù)。而在 TiDB 里,數(shù)據(jù)被切成 64MB 一個塊,可以很精確的檢測熱數(shù)據(jù),很方便的為熱數(shù)據(jù)做伸展。這個特性預(yù)計在 TiDB 4.0 提供。
這也是一個良好的架構(gòu)本身帶來的強大的價值,再加上基于 K8s 和云的彈性架構(gòu),就可以得到非常多的不一樣的東西。同樣的思路,如果我要做數(shù)據(jù)分析,一定是掃全部數(shù)據(jù)嗎?對于一個多租戶的系統(tǒng),我想統(tǒng)計某個餐館今天的收入,數(shù)據(jù)庫里有成千上萬個餐館,我需要運算的數(shù)據(jù)只是其中一小塊。如果我要快速做列存計算時,需要把數(shù)據(jù)全部復(fù)制一份嗎?也不需要,只復(fù)制我需要的這部分?jǐn)?shù)據(jù)就行。這些事情只有一個具有彈性、高度張力的系統(tǒng)才能做到。這是 TiDB 相對于傳統(tǒng)架構(gòu)有非常不一樣的地方。時至今天,我們才算是把整個系統(tǒng)的架構(gòu)基本上穩(wěn)定了,基于這個穩(wěn)定的架構(gòu),我們還可以做更多非常具有張力的事情。
所以,用一句話總結(jié)我們解決成本問題的思路是:一定要解決真正的核心的問題,解決最本質(zhì)的問題。
四、關(guān)于橫向和縱向發(fā)展的哲學(xué)TiDB 還有一條哲學(xué)是關(guān)于橫向和縱向發(fā)展的選擇。
通常業(yè)內(nèi)會給創(chuàng)業(yè)公司的最佳建議是優(yōu)先打“透”一個行業(yè),因為行業(yè)內(nèi)復(fù)制成本是最低的,可復(fù)制性也是最好的。但 TiDB 從第一天開始就選擇了相反的一條路——「先往通用性發(fā)展」,這是一條非常艱難的路,意味著放棄了短時間的復(fù)制性,但其實我們換取的是更長時間的復(fù)制性,也就是通用性。
因為產(chǎn)品的整體價值取決于總的市場空間,產(chǎn)品的廣泛程度會決定產(chǎn)品最終的價值。早期堅定不移的往通用性上面走,有利于盡早感知整個系統(tǒng)是否有結(jié)構(gòu)性缺陷,驗證自己對用戶需求的理解是否具有足夠的廣度。如果只往一個行業(yè)去走,就無法知道這個產(chǎn)品在其他行業(yè)的適應(yīng)性和通用性。如果我們變成了某個行業(yè)專用數(shù)據(jù)庫,那么再往其他行業(yè)去發(fā)展時,面臨的第一個問題是自己的恐懼。這恐懼怎么講呢?Database 應(yīng)該是一個通用型的東西,如果在一個行業(yè)里固定了,那么你要如何確定它在其他場景和行業(yè)是否具有適應(yīng)性?
這個選擇也意味著我們會面臨非常大的挑戰(zhàn),一上來先做最厲害的、最有挑戰(zhàn)的用戶。 如果大家去關(guān)注整個 TiDB 發(fā)展的用戶案例的情況,你會注意到 TiDB 有這樣一個特點,TiDB 是先做百億美金以上的互聯(lián)網(wǎng)公司,這是一個非常難的選擇。但大家應(yīng)該知道,百億美金以上的互聯(lián)網(wǎng)公司,在選擇一個數(shù)據(jù)庫等技術(shù)產(chǎn)品的時候,是沒有任何商業(yè)上的考量的,對這些公司來說,你的實力是第一位的,一定要能解決他們問題,才會認(rèn)可你整個系統(tǒng)。但這個也不好做,因為這些公司的應(yīng)用場景通常都壓力巨大。數(shù)據(jù)量巨大,QPS 特別高,對穩(wěn)定性的要求也非常高。我們先做了百億美金的公司之后,去年我們有 80% 百億美金以上的公司用 TiDB,除了把我們當(dāng)成競爭對手的公司沒有用,其他全部在用。然后再做 30 億美金以上的公司,今年是 10 億美金以上的用戶,實際上現(xiàn)在是什么樣規(guī)模的用戶都有,甭管多少億美金的,“反正這東西挺好用的,我就用了?!彼晕覀儸F(xiàn)在也有人專門負(fù)責(zé)在用戶群里面回答大家的提問。
其實當(dāng)初這么定那個目標(biāo)主要是考慮數(shù)據(jù)量,因為 TiDB 作為一個分布式系統(tǒng)一定是要處理具有足夠數(shù)據(jù)量的用戶場景, 百億美金以上的公司肯定有足夠的數(shù)據(jù),30 億美金的公司也會有,因為他們的數(shù)據(jù)在高速增長,當(dāng)我們完成了這些,然后再開始切入到傳統(tǒng)行業(yè),因為在這之前我們經(jīng)過了穩(wěn)定性的驗證,經(jīng)過了規(guī)模的驗證,經(jīng)過了場景的驗證。
堅持全球化的技術(shù)視野也是一個以橫向優(yōu)先的發(fā)展哲學(xué)。 最厲害的產(chǎn)品一定是全球在用的。這個事情的最大差異在于視野和格局,而格局最終會反映到人才上,最終競爭不是在 PingCAP 這兩百個員工,也不是現(xiàn)在 400 多個 Contributors,未來可能會有上千人參與整個系統(tǒng)的進(jìn)化迭代,在不同的場景下對系統(tǒng)進(jìn)行打磨,所以競爭本質(zhì)上是人才和場景的競爭?;谶@一條哲學(xué),所以才有了現(xiàn)在 TiDB 在新一代分布式數(shù)據(jù)庫領(lǐng)域的全面領(lǐng)先,無論是從 GitHub Star 數(shù)、 Contributor 數(shù)量來看,還是從用戶數(shù)據(jù)的規(guī)模、用戶分布的行業(yè)來看,都是領(lǐng)先的。同樣是在做一個數(shù)據(jù)庫,大家的指導(dǎo)哲學(xué)不一樣會導(dǎo)致產(chǎn)品最終的表現(xiàn)和收獲不一樣,迭代過程也會完全不一樣。我們在做的方向是「攜全球的人才和全球的場景去競爭」。
關(guān)于橫向和縱向發(fā)展,并不是我們只取了橫向。
2019 年 TiDB 演進(jìn)的指導(dǎo)思想是:穩(wěn)定性排第一,易用性排第二,性能第三,新功能第四。 這是我在 2018 年經(jīng)過思考后,把我們發(fā)展的優(yōu)先級做了排序。上半年我們重點關(guān)注的是前兩個,穩(wěn)定性和易用性。下半年會關(guān)注縱向發(fā)展,「Make it fast」其實是縱向上精耕細(xì)作、釋放潛力的事情。這個指導(dǎo)思想看起來好像又跟其他廠商想法不太一樣。
我們前面講的三條哲學(xué)里面,最后一條就是「Make it fast」,如果要修建五百層的摩天大樓,要做的不是搭完一層、裝修一層,馬上給第一層做營業(yè),再去搭第二層。而一定要先把五百層的架構(gòu)搭好,然后想裝修哪一層都可以。TiDB 就是「摩天大樓先搭架構(gòu)后裝修」的思路,所以在 TiDB 3.0 發(fā)布之后,我們開始有足夠的時間去做「裝修」的事情。
五、總結(jié)與展望說了這么多故事,如果要我總結(jié)一下 2015 - 2019 年外面的朋友對 TiDB 的感受,是下圖這樣的:
2015 年,當(dāng)我們開始做 TiDB 的時候,大家說:啊?這事兒你們也敢干?因為寫一個數(shù)據(jù)庫本身非常難,寫一個分布式數(shù)據(jù)庫就是無比的難,然后還是國人自主研發(fā)。到 2016 年的時候,大家覺得你好像折騰了點東西,聽到點聲音,但也沒啥。到 2017、2018 年,大家看到有越來越多用戶在用。2019 年,能看到更多使用后點贊的朋友了。
我昨天翻了一下 2015 年 4 月 19 日發(fā)的一條微博。
當(dāng)時我們正準(zhǔn)備創(chuàng)業(yè),意氣風(fēng)發(fā)發(fā)了一條這樣微博。這一堆話其實不重要,大家看一下閱讀量 47.3 萬,有 101 條轉(zhuǎn)發(fā),44 條評論,然而我一封簡歷都沒收到。當(dāng)時大家看到我們都覺得,這事兒外國人都沒搞,你行嗎?折騰到今天,我想應(yīng)該沒有人再對這個問題有任何的懷疑。很多國人其實能力很強了,自信也可以同步跟上來,畢竟我們擁有全球最快的數(shù)據(jù)增速,很多廠家擁有最大的數(shù)據(jù)量,對產(chǎn)品有最佳的打磨場景。
想想當(dāng)時我也挺絕望的,想著應(yīng)該還有不少人血氣方剛,還有很多技術(shù)人員是有非常強大的理想的,但是前面我也說了,總有一個從理想到現(xiàn)實的距離,這個距離很長,好在現(xiàn)在我們能收到很多簡歷。所以很多時候大家也很難想象我們剛開始做這件事情的時候有多么的困難,以及中間的每一個堅持。只要稍微有一丁點的松懈,就可能走了另外一條更容易走的路,但是那條更容易走的路,從長遠(yuǎn)上看是一條更加困難的路,甚至是一條沒有出路的路。
最后再說一下 2020 年。在擁有行業(yè)復(fù)制能力的之后,在產(chǎn)品層面我們要開始向著更高的性能、更低的延遲、更多 Cloud 支持(不管是公有云還是私有云都可以很好的使用 TiDB)等方向縱向發(fā)展。同時也會支持我剛剛說的,熱點根據(jù) Workload 自動伸縮,用極小的成本去扛,僅僅需要處理部分熱點的數(shù)據(jù),而不是復(fù)制整個數(shù)據(jù)的傳統(tǒng)主-從思路。
大家去想一想,如果整個系統(tǒng)會根據(jù) Workload 自動伸縮,本質(zhì)上是一個 self-driving 的事情?,F(xiàn)在有越來越多的用戶把 TiDB 當(dāng)成一個數(shù)據(jù)中臺來用,有了 TiDB 行列混存,并且 TiDB 對用戶有足夠透明度,就相當(dāng)于是握有了 database 加上 ETL,加上 data warehouse,并且是保證了一致性、實時性的。
昨天我寫完 slides 之后想起了以前看的一個電視劇《大秦帝國》。第一部第九集里有一段關(guān)于圍棋的對話。商鞅執(zhí)黑子先行,先下在了一個應(yīng)該是叫天元位置,大約在棋盤的中間。大家知道一般下圍棋的時候都是先從角落開始落子居多。商鞅的對手就說,我許你重下,意思就是你不要開玩笑,誰下這兒???于是商鞅說這樣一句話,“中樞之地,輻射四極,雄視八荒”,這也是一個視野和格局的事情。然后對手說:“先生招招高位,步步懸空,全無根基實地”,就是看起來好像是都還挺厲害的,一點實際的基礎(chǔ)都沒有,商鞅說:“旦有高位,豈無實地?”,后來商鞅贏了這盤棋,他解釋道:“棋道以圍地為歸宿,但必以取勢為根本。勢高,則圍廣”。
這跟我們做 TiDB 其實很像,我們一上來就是先做最難最有挑戰(zhàn)的具有最高 QPS 和 TPS、最大數(shù)據(jù)量的場景,這就是一個「取勢」的思路,因為「勢高,則圍廣」。 所以我們更多時候是像我前面說的那樣,站在哲學(xué)層面思考整個公司的運轉(zhuǎn)和 TiDB 這個產(chǎn)品的演進(jìn)的思路。這些思路很多時候是大家看不見的,因為不是一個純粹的技術(shù)層面或者算法層面的事情。
我也聽說有很多同學(xué)對 TiDB 3.0 特別感興趣,不過今天沒有足夠的時間介紹,我們會在后續(xù)的 TechDay 上介紹 3.0 GA 的重大特性,因為從 2.0 到 3.0 產(chǎn)生了一個巨大的變化和提升,性能大幅提升,硬件成本也下降了一倍的樣子,需要一天的時間為大家詳細(xì)的拆解。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/18033.html
摘要:它是第一個把數(shù)據(jù)分布在全球范圍內(nèi)的系統(tǒng),并且支持外部一致性的分布式事務(wù)。目的是使得開發(fā)者閱讀之后,能對項目有一個初步了解,更好的參與進(jìn)入的開發(fā)中。深度探索數(shù)據(jù)庫并發(fā)控制技術(shù)并發(fā)控制技術(shù)是數(shù)據(jù)庫事務(wù)處理的核心技術(shù)。 存儲過程高級篇 講解了一些存儲過程的高級特性,包括 cursor、schema、控制語句、事務(wù)等。 數(shù)據(jù)庫索引與事務(wù)管理 本篇文章為對數(shù)據(jù)庫知識的查缺補漏,從索引,事務(wù)管理,...
閱讀 3966·2021-11-17 09:33
閱讀 1268·2021-10-09 09:44
閱讀 455·2019-08-30 13:59
閱讀 3564·2019-08-30 11:26
閱讀 2238·2019-08-29 16:56
閱讀 2913·2019-08-29 14:22
閱讀 3200·2019-08-29 12:11
閱讀 1344·2019-08-29 10:58