作者 | 黃東旭
寫這篇文章的起因是有一次和朋友聊到一個很有趣的話題:如果我要為 1 億用戶提供免費的資料庫雲服務,這個系統應該如何設計?為了回答這個問題,我在之前的兩篇 Blog 中隱隱約約提到,我們在使用一些全新的視角和思路去看待和構建資料庫服務,並將這些思考變成了實際的產品:tidb.cloud/serverless,很多朋友很想了解 TiDB Cloud Serverless (下面會簡稱為 TiDB Serverless)的更多細節,所以便有了這篇博客。
有些朋友可能還不太了解 TiDB,請允許我先快速介紹一下 TiDB 本身。對 TiDB 比較熟悉的朋友可以跳過這段,主要是一些關鍵的名詞和定義:
- TiDB:特指由 tidb (負責 SQL 解析和執行) / tikv (負責數據存儲) / pd (負責元信息和調度) 等組件組成的分布式資料庫系統。
- TiDB Cloud:一個提供 TiDB 的雲服務,在雲上提供全託管的 TiDB。
- TiDB Cloud Serverless:一個提供 TiDB 的雲服務,雲原生 / 多租戶,擁有極低的使用成本與啟動時間,使用 Pay-As-You-Go 的付費模式,並在小規模的場景上完全面向開發者免費。
2015 年初,我們啟動了一個非常有野心的計劃。受到 Google Spanner 和 F1 的啟發(我更願意稱之為鼓舞),我們希望構建一個理想的分布式資料庫:支持 SQL、使用 MySQL 協議和語法、支持 ACID 事務語義、不對一致性妥協;對業務透明且無上限的水平擴展能力,能夠根據而業務流量和存儲特徵動態調整數據的物理分布達到極高的硬體利用率;高可用及故障自愈能力,降低人工運維的負擔。
在這些目標的驅動下,從一開始我們就做出了如下的技術決定:
- 高度模塊化。例如:tidb-server 負責 SQL 的解析和優化,tikv / tiflash 負責存儲(和一部分分布式計算),pd 負責元信息存儲及發起調度指令。
- 存儲層採用一個支持 ACID 事務的 Share-Nothing 架構的 Key-Value Database (tikv)以支撐彈性擴展,其他模塊儘量設計成無狀態的模式。如:當基礎的 TiDB bootstrap 完畢後,很多信息都可以存儲在 TiDB 自己的系統表中,如 SQL 優化要使用的統計信息等。儘量避免局部狀態(例如不單獨區分本地索引和全局索引)以降低故障恢復邏輯的複雜度。
可以看得出,這個設計就是奔著極強的擴展性和超大規模的場景去的,早期也確實如此。最初,TiDB 的想法來自於替換一些超大規模的 MySQL 分庫分表方案,這個策略很成功,在無數的客戶那已經得到驗證,甚至還替換了一些以規模見長的 NoSQL 的系統,例如 Pinterest 在他們的 Blog 中提到他們將他們的 HBase 成功替換成了 TiDB( https://medium.com/pinterest-engineering/online-data-migration-from-hbase-to-tidb-with-zero-downtime-43f0fb474b84)
回顧當年做的一些決定,TiDB 是很正確的:
- 大的模塊上清晰的分離設計。計算、存儲、調度、元信息管理都在不同的服務中,這樣的好處是把複雜性限制在模塊內部和無狀態的組件(例如 TiDB 的 SQL 層)中,很容易水平擴展以及負載均衡。
- 儘管用戶看到的是一個關係型資料庫,但是 TiDB 的存儲層使用簡單的 KV 作為抽象 + 極其細粒度的調度單元(region,96MB 的連續 Key-Value Pairs)+ 靈活的數據移動原語。好處是能夠以很細的粒度移動數據,這讓業務層理論上可以以任意的方式擺放任意數據,這是後來的 Placement Rules 等功能實現的基礎。
但是隨著時間的推移,我們漸漸發現了兩個趨勢:
- 當 OLTP 業務可以很好地支持橫向水平擴展後,對於一個支持 SQL 的資料庫來說,用戶在上面進行簡單的實時 OLAP 請求是很自然的選擇,這個觀察催生了 TiFlash。
- 並不是所有的業務一開始都有如此巨大的數據需要分布式的存儲,但是增長的預期是普遍存在的,所以更重要的問題是:當數據量和業務量真的增長到需要分布式資料庫的容量時,開發體驗是否還能保持一致(例如分庫分表就是一個破壞開發體驗的行為),而在剛開始數據量較小的時候又能以一個很低的成本起步。
上面的需求,在傳統的 Shared-nothing 架構下,會有以下幾點限制。
對於第一個趨勢來說,OLTP 和 OLAP 確實在融合,但是在傳統的 Shared-nothing 架構下其實是成本很高的,原因是對於 OLAP 應用來說,大多數時候 CPU 會成為瓶頸,CPU 是最昂貴且的資源。為了追求性能,我們只能增加更多的計算資源(也就是物理伺服器),而 OLAP 業務通常又不是在線服務,所以這些 workload 其實並不要求 7x24 小時獨占這些資源,但是為了運行這些 workload,我們不得不提前將這些資源準備好,即使 TiFlash 在存儲層已經能很好的彈性伸縮(可以按需對特定的表 Ad-hoc 的創建 TiFlash 副本)但很難在非雲的環境下對計算資源進行彈性伸縮。
對於第二個趨勢,傳統 shared-nothing 架構的分布式資料庫通常假設所有物理節點的硬體配置對等,否則會加大調度的難度;另外為了追求極致的性能,通常會放棄多租戶的設計,因為在雲下大多數的資料庫部署對於應用來說都是獨占式的。而要降低資料庫的使用成本不外乎兩條路:
- 多業務(租戶)共享一個資料庫集群
- 冷熱數據分離,使用更便宜的硬體存儲冷數據。
另外就是業務開始上雲,這點提的比較多,就不贅述了。
基於以上的假設,我們思考一個問題:如果今天重寫 TiDB,應該有哪些新的假設、作出哪些選擇,去覆蓋更多應用場景和更高的穩定性。
假設:
- 人人都愛低成本起步。
- 按需計價,能夠支持 Scale-to-Zero,不用的時候不收錢是很好的體驗,而且當有海量用戶時絕大多數用戶是非活躍的,workload 的分布也滿足二八定律。
- 對於關係型資料庫市場來說,OLTP 仍然是主流,OLAP 最重要的是彈性和低成本(其實並非性能)。另外一個容易被忽略的場景是輕量的 data transformation(一個好的例子是 dbt),頻繁在不同的數據服務商之間移動數據並不是好體驗。大量冷數據、少量熱數據,但是常常沒有辦法很清楚地劃分冷熱邊界(就像你不能突然阻止我在 3 年前的朋友圈上回復某個對話一樣)。
- 大數據量的在線服務場景是存在的(例如社交網絡),但是一定會配合有區分度極高的二級索引使用(例如:user_id / account_id 等),在這個索引的覆蓋下,一個查詢掃描的數據量不會太大。這種場景下,內存緩存的命中率及其重要。CPU 很難拓展,存儲很好擴展;CPU 很貴,存儲很便宜。
- 雲基礎設施在雲上和雲下都會普及(對象存儲、容器平台等)。
- 「穩定 + 可預測的性能」,比不穩定的高性能更好。
選擇:
- Built-in 的多租戶隔離能力:需要能夠低成本支持粒度很細(小)的海量租戶,畢竟只有共享資源才能將單位成本持續降低。
- 存儲層:利用不同的存儲和計算服務,而不是對等的物理機器,尤其是利用好對象存儲。
- 仍然沿用分離的設計,但不再是以一個軟體的形式交付,而是以一組微服務組成的平台服務進行交付。
更重要的選擇是我在之前文章提到的:與其把資料庫放到雲上運維,更應該將雲資料庫作為一個完整的雲服務設計。在這個指導思想下,我們開始了 TiDB Cloud Serverless,因為細節太多,我不可能在這篇文章內一一照顧到,思來想去挑了兩個重點在這篇文章中介紹一下:存儲引擎和多租戶。
存儲引擎設計
在傳統的上下文中,我們提到存儲引擎時一般都想到 LSM-Tree、B-Tree、Bitcask 什麼的,另外在傳統的語境中,這些存儲引擎都是單機的,對於一個分布式資料庫來說,需要在本地存儲引擎之上再構建一層 Sharding 邏輯決定數據在不同物理節點上的分布。
但是在雲上,尤其對於構建一個 Serverless 的存儲服務,數據的物理分布不再重要,因為 S3 (對象存儲,這裡包含但也並不特指 AWS S3) 已經將擴展性和分布式可用性的問題解決得足夠好(而且在開源社區也有高質量的對象存儲實現,如 MinIO 等)。如果我們將在 S3 的基礎之上構建的一個新的「存儲引擎「看成整體的話,我們會發現整個分布式資料庫的設計邏輯被大大簡化了。
為什麼強調存儲引擎?因為計算層抽象得好的話是可以做到無狀態的(參考 TiDB 的 SQL 層),無狀態系統的彈性伸縮相對容易做到,真正的挑戰在於存儲層。從 AWS S3 在 2022 年的論文中我們可以看到,AWS 在解決 S3 的彈性和穩定性問題上花了極大的功夫(其實 S3 才是 AWS 真正的 Serverless 產品!)。
但是 S3 的問題在於小 I/O 的延遲,在 OLTP workload 的主要讀寫鏈路上不能直接穿透到 S3,所以對於寫入而言,仍然需要寫入本地磁碟,但是好在只要確保日誌寫入成功就好。實現一個分布式、低延遲、高可用的日誌存儲(append-only)比起實現一個完整的存儲引擎簡單太多了。所以日誌的複製仍然是需要單獨處理的,可以選擇 Raft 或者 Multi-Paxos 之類的 RSM 算法,偷懶一點也可以直接依賴 EBS。
對於讀請求來說,極低的延遲(<10ms) 基本上只有依靠內存緩存,所以優化的方向也只是做幾級的緩存,或者是否需要用本地磁碟、是按照 page 還是按照 row 來做緩存的問題。另外在分布式環境下還有一個好處是,由於可以在邏輯上將數據分片,所以緩存也可以分散在多台機器上。
對於這個新的存儲引擎,有以下的幾個設計目標:
支持讀寫分離
對於 OLTP 業務來說,通常讀是遠大於寫的,這裡的一個隱含假設是對於強一致讀(read after write)的需求可能只占全部讀請求的很小部分,大多數讀場景可以容忍 100ms 左右 inconsistent gap,但是寫請求對於硬體資源的消耗是更大的(不考慮 cache miss 的場景)。在單機的環境下,這其實是無解的,因為就那麼一畝三分地,讀 / 寫 /compaction 都要消耗本地資源,所以能做的只能有平衡。
但是在雲的環境下,完全可以將讀寫的節點分開:本地通過 Raft 協議複製到多個 Peer 上,同時在後台持續異步同步日誌數據到 S3(遠端的 compact 節點進行 compaction)。如果用戶需要強一致讀,那麼可以在 Raft Leader 上讀,如果沒有強一致的需求,那麼可以在其他的 Peer 節點上讀(考慮到即使異步複製日誌的 gap 也不會太長,畢竟是 Raft),即使在 Non-Leader Peer 上想實現強一致讀,也很簡單,只需要向 Leader 請求一下最新的 Log Index,然後在本地等待這個 Index 的 log 同步過來即可;新增的讀節點,只需要考慮從 S3 上加載 Snapshot 然後緩存預熱後即可對外提供服務。
另外,通過 S3 傳輸 snapshot 數據的額外好處是,在同一個 region 內部,跨 az 的流量是不計的。而且對於 HTAP 場景中的分析請求,因為數據都已經在 S3 上,且大多數分析的場景大約只需要 Read-committed 的隔離級別 + Stale Read 就能滿足需求,因此只需要按照上面描述的讀節點來處理即可,ETL 的反向數據回填也可以通過 S3 完成。
Before
After
支持冷熱分離
對於 OLTP 場景來說,我們觀察到儘管總數據量可能很大,有時 OLTP 單個業務上百 TB 我們也經常見到,但是絕大多數場景下都有冷熱之分,而且對於冷數據來說,只需要提供「可接受」的體驗即可,例如讀寫冷數據的延遲容忍度通常會比較高。
但是就像開始提到的,我們多數時候並不能二元地劃分冷熱,但是我們又希望能通過冷熱分離將冷數據使用更便宜的硬體資源存儲,同時不犧牲熱數據的訪問體驗。在 Serverless TiDB 中,很自然的,冷數據將只存儲在 S3 上,因為分層的存儲設計會很自然地將熱數據保留在本地磁碟和內存中,冷數據在最下層也就是 S3 上。這個設計的壞處是犧牲了冷數據緩存預熱時的延遲,因為要從 S3 上加載。但是就像上面說到的,在現實的場景中,這個延遲通常是可以被容忍的,想要提升這種情況的用戶體驗也很容易,再加入一級緩存即可。
支持極快的彈性伸縮(Scale-out / in),並支持 Scale-to-Zero
在提到冷熱分離的時候,有兩個隱含的話題沒有 cover:
- 寫請求熱點如何處理?
- 如何快速感知到熱點?
- 寫請求熱點如何處理?
- 如何快速感知到熱點?
要回答這兩個問題,需要討論:數據分片,請求路由以及數據調度,這三個話題也是支持彈性伸縮的關鍵。
我們先說數據分片。傳統 Shared Nothing 架構的數據分片方式在邏輯上和物理上是一一對應的,例如 TiKV 的一個 region 對應的就是某台 TiKV 節點上的 RocksDB 一段物理數據。另一個更好理解的例子是 MySQL 分庫分表,每個分片就是一台具體的 MySQL。
但是在雲上,如果有這樣一個雲原生的存儲引擎,那我們其實已經不太需要關心數據的物理分布,但是邏輯分片仍然是重要的,因為涉及到計算資源的分配(以及緩存)。過去 Shared-nothing 架構的分布式資料庫的問題是:如果要調整分片就會涉及到數據移動和搬遷,例如添加 / 刪除存儲節點後的 Rebalance。這個過程是最容易出問題的,因為只要涉及到物理數據的移動,保證一致性和高可用都將是複雜的工作,TiKV 的 Multi-Raft 花了無數的精力在這塊。但是對於基於 S3 的存儲引擎來說,數據在分片之間的移動其實只是一個元信息修改,所謂的物理的移動也只是在新的節點上的緩存預熱問題。
有數據的邏輯分片就意味著需要有對應的請求路由層,需要根據規則將請求定位到具體某台機器上。目前我仍然認為就像 TiKV 一樣,KV Range 是一個很好分片方式。像字典一樣,當你拿到一個單詞,通過字典序就能很精準的定位。在 TiDB Serverless 中我們仍然保留了 KV 的分片和邏輯路由,但是會在原本的 TiDB 之上增加一層 Proxy 用於保持不同租戶的 Session ,我們姑且叫它 Gateway。
Gateway 是租戶隔離及流量感知的重要一環(後邊會提到), Gateway 感知到某個租戶的連接被創建後,會在一個緩存的計算資源池中(tidb-server 的 container pool)撈出一個 idle 狀態的 tidb-server pod 來接管客戶端的請求,然後當連接斷開或者超時一段時間後自動歸還給 pool。這個設計對於計算資源的快速伸縮是非常有效的,而且 tidb-server 的無狀態設計,也讓我們在給 TiDB Serverless 實現這部分能力的時候簡單了很多,而且在 Gateway 感知到熱點出現後可以很快的彈性擴容。計算的擴容很好理解,存儲層的擴容也很簡單,只需修改一下元信息 + 在新的節點上掛載遠端存儲並預熱緩存即可。
經濟性
在雲上,一切資源都是需要付費的,而且不同的服務定價差別巨大,對比一下 S3 / RDS / DynamoDB 的定價即可看到很大的區別,而且相比服務費用和存儲成本,大家很容易忽略流量的費用(有時候你看帳單會發現其實比起存儲成本,流量會是更大的開銷)。節省成本有幾個關鍵:
- 利用 S3 進行跨 AZ 的數據移動和共享,節省跨 AZ 流量費用。
- 利用 Spot Instances ,進行離線任務。離線任務定義:無狀態(持久化在 S3 上)、可重入。典型的離線任務是 LSM-Tree 的 compaction 或者備份恢復什麼的。
- 利用 S3 進行跨 AZ 的數據移動和共享,節省跨 AZ 流量費用。
- 利用 Spot Instances ,進行離線任務。離線任務定義:無狀態(持久化在 S3 上)、可重入。典型的離線任務是 LSM-Tree 的 compaction 或者備份恢復什麼的。
能夠重用原來 TiDB 的大部分代碼
TiKV 對於存儲引擎有著很好的抽象,其實主要修改的地方大概只有原來 RocksDB 的部分。關於 Raft 和分片的邏輯基本是能夠復用的。至於 SQL 引擎和事務的部分,因為原本就和存儲的耦合比較低,所以主要修改的部分就是添加租戶相關的邏輯。這也是為什麼我們能使用一個小團隊,大概一年時間就能推出產品的原因。
多租戶
想像一下,如果你需要支撐一個龐大規模的用戶資料庫,集群中有成千上萬的用戶,每個用戶基本上只訪問自己的數據,並且有明顯的冷熱數據區分。而且就像一開始提到的那樣,可能有 90% 的用戶是小型用戶,但你無法確定這些用戶何時會突然增長。你需要設計一個這樣的系統,以應對這種情況。
最原始的方法很簡單,就是直接將一批機器提供給一個用戶,將另一批機器提供給另一個用戶。這樣的物理隔離方法非常簡單,但缺點是資源分配不夠靈活,並且有許多共享成本。例如,每個租戶都有自己管控系統和日誌存儲等方面的成本。顯然,這是最笨重的物理隔離方法。
第二種方法是在容器平台上進行部署,利用虛擬化,儘可能利用底層雲平台的資源。這種方法可能比第一種方案稍好一些,至少可以更充分地利用底層硬體資源。然而,仍然存在前面提到的共享成本問題。
以上兩種方案的核心思想是:隔離。其實包括所謂的在 SQL 引擎內部做虛擬機之類的方式本質上都是在強調隔離。但如果要實現用戶數量越多、單位成本會越低的效果,光強調隔離是不夠的,還需要共享:在共享的基礎上進行調度,以實現隔離的效果。
TiDB Serverless 允許多個租戶共享一個物理 Cluster 但是從不同用戶的視角來看是相互隔離的。這是降低單位成本的關鍵所在,因為多個用戶共享同一資源池。不過,這種基於共享的方案也存在一些問題,例如資源共享不足以滿足大租戶的需要、租戶之間的數據可能會混淆、無法對每個租戶的需求進行個性化的定製等。此外,如果一個租戶需要定製化的功能,整個系統需要被更改以適應這個租戶的需要,這會導致系統的可維護性下降。因此,需要一種更靈活且可定製化的多租戶實現方式,以滿足不同租戶的不同需求。
我們看看在 TiDB Serverless 中是如何解決這些問題的。在介紹設計方案前,我們先看看一些重要的設計目標:
- 不同租戶之間可以不會相互影響 SLA,不同用戶的數據互相不可見。
- 不同租戶之間可以靈活的共享 / 隔離硬體資源。
- 系統故障的時候儘可能小的爆炸半徑。
對於第一點,不同租戶的數據如何隔離而且互相不可見,要回答這個問題需要從兩個方面考慮:物理存儲和元信息。
物理存儲的隔離反而是容易的。在上面提到了 TiKV 內部是會對數據進行分片的,即使數據存儲在 S3 上,我們也可以利用不同的 Key 的編碼很好地區分不同租戶的數據。TiDB 5.0 中也引入了一套名為 Placement Rules 的機制在語意層提供用戶控制數據物理分布的操作介面(目前還沒有在 TiDB 的雲產品產品線中直接暴露給用戶)( https://docs.pingcap.com/tidb/stable/placement-rules-in-sql)。TiDB 在設計之初為了性能考慮儘可能精簡存儲層對 key 的編碼,並沒有引入 namespace 的概念也沒有對用戶的數據進行額外的前綴編碼,例如:不同用戶的數據加上租戶 id,為了實現租戶的區分,這些工作現在都需要做,在存儲層這部分並不算困難,更多要考慮的是兼容性和遷移方案。
傳統的分布式資料庫中,元信息存儲是系統的一部分,例如在傳統的 TiDB 中,PD 組件存儲的元信息的主要部分是 TiKV 的 Key 和 Value 與具體的某個存儲節點的對應關係。但是在一個 DBaaS 中,元信息遠不止如此,更好的設計是將源信息存儲單獨抽離出來作為一個公共服務為多個集群服務,理由如下:
- 元信息應該是多級的。就像上面提到除了最底層 Key-Value 和存儲節點的對應關係外,還有 DB/Table Meta 與 Key-Value 的關係,租戶信息和 DB/Table 的關係,租戶和 Cluster Deployment 的關係等,這些信息對於調度是很有價值的。現在回頭反思早期設計 的 TiDB,其中一個重要的 lesson learned 是元信息應該設計多一些邏輯分層,而不只是簡單的 KV Range 的映射(這個在 Spanner 的設計中做的很好)。
- 元信息服務應該是可擴展的。當元信息服務化後,意味著它可能需要支撐成千上萬個集群的信息,這意味著元信息的數據量可能會很大,如果去看 Google Colossus 的元信息事實上是存儲在一個 Big Table 上( https://cloud.google.com/blog/products/storage-data-transfer/a-peek-behind-colossus-googles-file-system )的。
- 元信息會被資料庫內核之外的其他各種服務依賴。 最典型的例子是計費和聯邦查詢服務或者數據共享等場景。
在連接建立之初就知道了租戶 id 後,所有的邏輯隔離都可以通過這個 id 實現。
Gateway 會幹比起普通 Proxy 更多的事情,事實上在 TiDB Serverless 中,我們直接將原本 TiDB 代碼中的 Session 管理模塊的代碼單獨抽出來,用於實現 Gateway。這個設計帶來的好處很多:
- 區分租戶,感知連接的來源(地理 region),這個很明顯就不用說了。
- 流量感知 / 控制。Flow control 這類事情做在越上層越好,存儲層都已經感受到壓力山大的時候通常留給流控的空間就不大了。由於 Gateway 是一切流量的出入口,而且 TiDB Serverless 和 AWS Dynamo 在論文中提到的一樣,引入了 RU ( Request Unit,https://www.pingcap.com/tidb-cloud-serverless-pricing-details/ ) 的概念,在這裡進行 RU 的控制是最精確的。
- 無感升級 / 擴縮容。和第二點類似,當 Gateway 感知到突發流量或者長時間沒有流量的時候,可以很方便告訴底層的 tidb-server(SQL processing) 資源池增減計算節點,或者對於不同類型的請求申請不同規格的計算節點。這點也是支持 Scale-to-Zero 的關鍵。
- 計費。結合第二、第三點以及前面提到的存儲層的自動冷熱分離設計,Gateway 上針對具體租戶的流量信息是:準確 + 底層可以根據實際流量動態調整底層的計算資源 + 通常成本很低的(S3)冷存儲,這幾點讓我們都能夠實現 Pay-as-you-go 的付費模式。即使 Gateway 本身是常駐的,但這部分成本均攤到海量的用戶上是可以接受的。
- 用戶無感的升級。傳統方案中如果底層資料庫需要更新,必然會中斷用戶的連接,這對於有些保持資料庫長連結的應用是不友好的(很多開發者基本上都不太會考慮斷開重連的情況🤷)。而 Gateway 模塊是比較輕量的也很少升級,於是我們可以在這層保持用戶的連接,底層就可以做到無縫地更新進程。在用戶側觀察到的顯現無非就是某幾個請求的延遲稍稍升高,之後就恢復正常了。
- 極快的新集群啟動時間。新集群的創建只是添加一些元信息 + 從 tidb-server 的資源池裡撈一個 pod 出來的代價 :)
Gateway 作為常駐模塊,本身也是無狀態的。增加的延遲和與帶來的好處相比,我們認為是可以接受的。
我們通過 Gateway 和元信息的修改實現了多租戶在一個物理集群上的邏輯層的隔離,但是如何避免 Noisy Neiberhood 的問題?在上面提到我們引入了 RU 的概念,這裡就不得不提一下我們在 TiDB 7.0 中引入的名為 Resource Control 的新框架( https://docs.pingcap.com/tidb/dev/tidb-resource-control)。和 Dynamo 類似,TiDB 的 Resource Control 也是使用了 Token bucket 的算法( https://en.wikipedia.org/wiki/Token_bucket)。將不同類型的物理資源和 RU 對應起來,然後通過 Token bucket 進行全局的資源控制:
比起硬性的物理隔離,這樣實現資源隔離方式的好處是很明顯的:
- 靈活。因為這套機制對用戶的訪問層是沒有侵入的,也就是和 TiDB 原本的 Data Placement 機制是正交的:如果一個大客戶需要完全隔離的環境,可以配合 Placement Rule 將用戶的數據移動到一批額外的硬體資源上,就完成了硬隔離;反向的話,也很容易實現。
- 支持 Burst 和搶占式的資源共享方式。在總資源有限的情況下,應對重要業務突發流量的很重要的應對方式是 Burst 和搶占,也就是將低優先級的資源(或者預留的資源)臨時借給高優先級的應用,這點對於降低總成本的同時獲得一個良好的用戶體驗(對於付費客戶)很重要。
- 資源預留以實現 Predictable 的性能。這點和上面類似,但是不太一樣。在 Dynamo 2022 年的新論文中提到類似的 DBaaaS 更重要的是提供 Predictable 性能的概念,我非常認同,而且我認為 Predictable 的關鍵在於儘可能避免硬體資源過載,而避免硬體資源過載最有效的辦法就是提前預留資源,因為所有資源都被這套 Resource Control 框架精確控制,所以預留資源也是很容易實現的。
其實還有更多好處也在 Dynamo 那篇論文里提到,這和我們實際的感受是一致的。
但是,基於共享大集群的多租戶服務實現,會帶來一個挑戰:爆炸半徑的控制。例如當某一個服務出現故障或者發現嚴重的 Bug,可能影響的范不是一個租戶,而是一片。目前我們的解法是簡單的 sharding,至少一個 region 故障不會影響到另一個 region。另外對於大租戶,我們也提供傳統的 dedicated cluster 服務,也算是在業務層對這個問題提供了解決方案。當然,這方面我們也仍然在持續的探索中,有些工作很快會有一些可以看到的效果,到時候再與大家分享。
還有很多很有趣的話題,例如上面提到整個系統都是通過 Kubernetes 串聯在一起的,那麼為這樣一個複雜的 DBaaS 提供 Devops,如何池化雲上資源和多 region 支持?另外設計思路的改變不僅影響了上面提到的內容,對於資料庫的周邊工具的設計也會有重大的影響,例如 CDC、備份恢復什麼的。因為篇幅關係就不在這裡寫了,以後有機會再說。
對話賈揚清、關濤、張伯翰:AI 平民化趨勢下,數據架構將被徹底顛覆?
一場馬斯克的反爬鬧劇:Twitter一夜回到五年前?
對話開源泰斗陸首群教授:中國開源發展應追求0到1的爆發性創新,而不是0到0的假創新
離職員工竊取原始碼,半年狂賺1.5 億;美團「1元現金」火速收購光年之外;53歲周鴻禕清華讀博:重新學習做一個工程師|Q 資訊