做者介紹: 陳東明,餓了麼北京技術中心架構組負責人,負責餓了麼的產品線架構設計以及餓了麼基礎架構研發工做。曾任百度架構師,負責百度即時通信產品的架構設計。具備豐富的大規模系統構 建和基礎架構的研發經驗,善於複雜業務需求下的大併發、分佈式系統設計和持續優化。我的微信公衆號 dongming_cdm。html
Tedis(https://github.com/eleme/tedis)是基於開源 TiKV 的兼容 Redis 協議的強一致性的 NoSQL 數據庫開源項目。 本文介紹一下 Tedis 開源項目的架構設計和特性,以及架構背後的一些思考(包括爲什麼選擇 TiKV 和 Redis 協議)。git
先來討論爲何基於 TiKV 構建咱們本身的 NoSQL 數據庫。github
首先簡述一下 TiKV[1],TiKV 是 TiDB 的一個子項目,TiDB 是一個分佈式的關係型數據庫 [2],TiKV 是 TiDB 的存儲層。TiKV 自己是可獨立於 TiDB 的單獨項目。它是一個強一致、可水平擴展的、高可用的分佈式 Key-Value 存儲系統。數據庫
選擇 TiKV 的第一個緣由是 TiKV 是一個強一致的系統。 在個人另一篇文章中(發表在 InfoQ, 參看 https://www.infoq.cn/article/rhzs0KI2G*Y2r9PMdeNv ),我闡述了一個觀點:NoSQL 數據庫應該具備一致性,而且經過多副本技術達到實際的高可用,也就是說 NoSQL 數據庫應該是一個「實際上的 CA」 (effectively CA)系統。可是在這篇文章中我並無明確說明 NoSQL 該具備的一致性是哪一種一致性。實際上,我所說的一致性其實就是一種強一致性 [3],或者更準確的說是線性一致性 [4]。TiKV 正是具備這種線性一致性。TiKV 中的每一個數據都會保存 3 個副本,在只有一個副本的節點宕機或者出現網絡分區的狀況下,另外 2 個副本仍然可以對外提供服務。理論上來說,同時出現 2 個以上副本同時壞掉的可能性很小,也就是理論上能夠達到很是高的可用性。經過 TiKV 滾動升級等運維輔助,若是在實際的生產中,有良好的運維,能夠達到實際上很是高的可用性。也就是稱爲一個「實際上的 CA」(effectively CA)系統。數組
TiKV 經過 Raft [5] 協議實現了線性一致性和高可用 2 個特性。Raft 是一種分佈式共識協議,經過 Raft 協議,數據能夠被認爲是原子的寫入到 3 個副本上。共識協議的一個特色就是要寫入大多數,纔會認爲寫入成功,3 個副本的大多數就是 2 個,也就是在只有一個副本宕機或者網絡分區的狀況下,仍然能夠成功寫入,而且提供讀服務。緩存
選擇 TiKV 的第二個緣由是 TiKV 的架構可擴展和生態。 在 TiDB 中 TiKV 是獨立的一層,造成了一個很好的可擴展架構,實際上能夠在 TiKV 上擴展出不少不一樣的數據庫出來。TiDB 層自己就是這種架構上的一個擴展。這種架構相似於 Google 公司的第一代的 Spanner 系統 [6],Spanner 系統自己也是一個強一致性的、高可用的分佈式 Key-Value 系統。在 Spanner 的基礎之上,Google 構建了 F1 系統 [7],實現了 SQL 協議。2017 年,Google 升級了 Spanner 到第二代 [8],讓 Spanner 自己就具備了 SQL 能力。雖然一代 Spanner+F1 是這樣的架構,但它仍然是一種很是優秀的架構。咱們的 Tedis 項目,也是構建在這一可擴展架構上的一個項目,依託於 TiKV 提供的底層能力,向上構建了不一樣於 SQL 協議的 Redis 協議。我相信 TiKV 的這種可擴展架構,將來能夠成爲一種生態,還能夠在上面「⻓出」其餘的類型的數據庫,好比說 Mango 協議、圖協議。這些數據庫都具備與底層 TiKV 相同的線性一致性和高可用性,區別只在於對外的接口協議不一樣。 目前這種生態已初⻅端倪,Titan(https://github.com/distributedio/titan) 這個開源項目,與咱們的 Tedis 項目很是相似,他們的開源步伐先於咱們,目前作的也很是不錯。我相信,咱們確定不是這個生態中的最後一個。微信
總之基於 TiKV,Tedis 實現瞭如下的技術特性:網絡
1. 大數據量,能夠存儲至少數十 TB 級別的數據。數據結構
2. 高性能,在知足高 QPS 的同時,保證比較低的延時。架構
3. 高可靠,數據被可靠的持久化存儲,少許機器的損壞不會致使數據的丟失。
4. 高可用,做爲在線服務的底層依賴存儲,要有很是完善的高可用性能力,外賣服務不一樣於電子商務,對實時性要求很是高,對系統的可用性的要求則是更高的。
5. 易運維,能夠在不停服的基礎上進行數據遷移和集羣擴容。
接下來,咱們討論第二個問題,爲何選擇 Redis 協議。
SQL 語言與其背後的關係模型,從 1970s 發明以來,一直在應用開發領域佔據這統治地位,雖然在 CAP 定理的推進下 [4],在 NoSQL 運動中,出現不少 NoSQL 系統,就如我前面闡述的同樣,一致性不該該是 NoSQL 出現的理由,去 SQL 和關係模型纔是 NoSQL 出現的動力。但我並不認爲 NoSQL 會代替 SQL。雖然 NoSQL 出現的時候,本來表達的意思是 「NO SQL(沒有 SQL)」,可是我以爲另一種對 NoSQL 的解釋更合適,也就是「Not Only SQL(不只僅有 SQL)」。NoSQL 不是 SQL 的替代品,應該是 SQL 的有力補充。在 NoSQL 運動中,涌現出來的很是優秀的 NoSQL 系統大多都有本身的獨有的接口協議,好比 Redis、MongoDB、Cassandra、圖數據庫等等。他們都有各自很是適用的使用場景,好比 MongoDB 貼近面向對象,圖數據庫適合節點的圖關係運算。而 Redis 貼近開發者數據結構思惟,相信每一個開發者都是從數組、hash 表、隊列這樣的數據結構中成⻓起來的。
另外,Redis 自己是一個很是優秀的產品,它的普及程度很是高,特別是在互聯網行業。在每一個互聯網公司,Redis 都已經成爲工程師開發工具箱中,必備的工具之一。Redis 已是開發者除 SQL 以外,第二熟悉的產品了。
可是,選擇 Redis 協議,也給我帶來一些實際的困擾,咱們有些使用者最初接觸 Tedis 時,老是拿咱們和 Redis 相比。可是,雖然咱們採用的是 Redis 接口,可是 Tedis 自己並不對標 Redis 這個產品。Redis 是很是優秀的緩存。雖然 Redis 也能夠開啓持久化功能,因爲 Redis 自己架構設計,開啓持久化的 Redis 仍然不能達到「實際上的 CA」(effectively CA),和 100% 的持久性(durability)。這是 Redis 和 Tedis 的一個很大的區別,Tedis 是一個數據庫,不是一個緩存。
討論完上面的 2 個架構思考,咱們來看一下 Tedis 的架構設計。
在 Tedis 中,咱們封裝了一個 TiKV 的 SDK,對 Redis 的協議進行了解析,而且將 Redis 協議轉成對 TiKV 的調用。
目前 Tedis 仍然有不少要完善的地方,可是咱們會盡快完善以下的事項,在咱們的開源日程表中:
1. Redis 命令的補全
2. 壓縮和限流等一些擴展功能
3. Cassandra 協議的支持
寫在最後
做爲存儲系統,不該該讓使用者在一致性、可用性這些技術特性上作過多的選擇,使用者應該更多的考慮哪一種接口更適合本身的應用場景,本身更熟練使用哪一種接口,能用哪一種接口更快的進行功能開發。
因爲篇幅所限,本文中關於強一致性、線性一致性、Redis、Raft、Spanner 的不少技術細節的闡述未能詳盡,擬另行成文討論。
參考資料:
Eventually Consistent - Revisited,Werner Vogels, 2008, http://www.allthingsdistributed.com/2008/12/event ually_consistent .html
Linearizability: A Correctness Condition for Concurrent Objects,Maurice P. Herlihy and Jeannette M. Wing,1990
In Search of an Understandable Consensus Algorithm, Diego Ongaro and John Ousterhout, 2014
Spanner: Google’s Globally-Distributed Database, James C. Corbett, Jeffrey Dean et al., 2012
F1: A Distributed SQL Database That Scales, Jeff Shute et al., 2013 8.Spanner: Becoming a SQL System, David F. Bacon et al., 2017