內存數據庫Tair實戰
今天,我們來聊聊“阿里云內存數據庫 Tair ”,我先介紹下自己,我的真名叫朱國云,花名宗岱,2008年加入阿里。在阿里主要從事存儲數據庫相關,包括文件存儲、緩存、內存數據庫等。一開始參與過阿里云飛天操作系統的研發,后來主要負責Tair的研發。
1.Tair的發展歷程
接下來,我們正式進入Tair 相關的交流。整體包括Tair的發展歷程、重大節點、技術難點以及相關實踐展開。我們先來看看“Tair的歷史和發展”,可以看下面這張圖:
Tair的歷史和發展
- 2009年,Tair1.0在淘寶孵化。
- 2014-2015年,阿里云剛起步不久,淘寶的一些基礎服務和阿里云整合在一起,所以在阿里云上也提供了云的緩存服務,包括云Memcache和云Redis。從Tair1.0到Tair2.0,兩者之間的核心區別就是一個是純KV,一個兼容了Redis。
- 2018年,阿里內部有非常多高度連接數據的場景,如數據的存儲、查詢和計算。這個過程中誕生了TairGraph。
- 2019年后,我們把Tair的這些能力推出到了公共云上。包括,在云Redis里面包含了Tair,這一版即Tair3.0。
- 今年,我們把Tair產品在阿里云上獨立了出來,客戶能夠直接從Tair產品購買和管理。在跟客戶交流中,他們有一個會經常會問到的疑問:為什么Tair這個系統能夠做13年?從淘寶這個時代就開始誕生的系統與產品,今天還在阿里內部依然大規模運行的其實是比較少了,Tair就是其中的一個。當然這里面經歷了非常多的系統迭代和架構的演進。
接下來,我們來看看Tair在阿里內部的應用。
現在在阿里集團內部,絕大部分BU的核心在線業務都使用了Tair,包括最開始淘寶、天貓電商的交易導購廣告,到菜鳥的電子面單物流送貨軌跡,再到釘釘消息的推送、優酷的視頻播放列表等,這些在線業務都是用了Tair。
今天在一些偏 TP 類的在線業務場景,業務主要核心依賴的就是Tair加數據庫。Tair在這里面的核心定位就是承載超大的流量和高速的存儲,且并不僅僅是一個緩存,有非常多業務直接把它作為內存的存儲去用。
從上文可以了解到,Tair在阿里支撐著大部分的項目,且不斷進行優化,在這過程中,Tair也遇到過很多的技術挑戰,接下來我們看看Tair發展過程中的重要節點和技術挑戰。
2.Tair的重要節點和技術挑戰
2.1 重要節點
在淘寶電商交易剛起步的時候,和現在的系統架構比,當時的業務架構相對來說是比較簡單的。
在Tair誕生之前,我們內部有一個TDBM系統,這是一個獨立的、單機緩存服務,容量是很有限的,所支撐的訪問量也有限。最關鍵的是它是一個單點,在高可用上是沒有的。所以在 2009 年的時候,開發了Tair 1.0。
Tair 1.0是一個獨立的、分布式的緩存服務,是集群模式的,也完整實現了節點的擴縮容,這是區別于TDBM系統的。在Tair 1.0形成基礎的技術架構后,基于這條路線上Tair演進了很多年。
隨著移動互聯網誕生,整個應用場景變得更豐富了。電商變得更繁榮、搜索廣告推薦用得越來越多、社交網絡的興起、手游的發展、 LBS的應用,在這些行業的在線場景中,對緩存和高速存儲系統的需求變得越來越大,從下圖可以看到,Tair 1.0也是隨著這些行業不斷演進和發展。
數據量的變大,對Tair的內存存儲提出了新的挑戰,如何低成本的解決面向互聯網在線數據的存儲和查詢。正恰SSD固態硬盤的成熟,Tair基于 SSD存儲介質,實現了Tair LDB持久存儲引擎,提供了一個高性能大容量的解決方案,而在2018 年之后持久內存的出現,新的存儲介質,也給Tair提供了一個新的演進契機。
整體來說,在這個階段,Tair從1.0的緩存定位逐步演進到了NoSQL的存儲系統。接口層面,它也從一個最簡單的 KV 接口演進到提供了更復雜更豐富的數據接口。
那么Tair的技術架構是怎樣的呢?在當時是比較典型的架構:SDK、管理節點和數據DB節點,集群內部通過類一致性哈希的算法,通過哈希把數據切分到多個分片上去。同時通過主從機制來實現數據DB節點的高可用。
整體系統除了數據流之外,還有一整套的泰斗(Tiddo)來配合完成系統的管理。例如宕機的自動切換,集群擴縮容后的自動遷移平衡數據。除此之外,也可以選擇帶Proxy的架構,Proxy可以實現更豐富的訪問聚合、連接收斂、QueryCache等高級功能。
圖上右邊其實是單個 DB 進程,它是統一的服務技術框架,它可以支持多個存儲引擎在里面。譬如,我們原來定義的 Tai1.0 MDB 那它就是一個 KV 內存的,就我們上面的這個進程框架是一模一樣的,下面的存儲引擎是可以替換的。
2.2 技術挑戰
接下來,我會講三個我們就在阿里集團這幾年面臨的這一些技術挑戰,就是阿里集團做單元化、熱點、性能與成本。
- 技術挑戰--單元化
單元化這個項目其實非常宏大,相當于要從整個應用層開始,到中間件,譬如 MQ、TTDL這一層,再到Tair跟數據庫這一層。Tair當時的三大塊包括MDB、RDB和LDB。對于MDB,我們是作為緩存去用的。所以在做單元化的時候,并不會主動去做數據同步,而是由數據庫這一層做數據同步之后到另外單元來做一個反向的失效。對于 RDB和LDB,很多業務是拿來作為數據最終的存儲去用的,所以這兩大塊我們相當于做了自己的數據同步方案。
這里面比較難解的問題是,怎么能夠確保源端寫入的能夠快速地在目的端所消費掉?這個問題會和源端的寫入速度目的端的消費速度、兩個集群間機房的距離、網絡速度都是相關的。第一是要做好容量規劃,第二是在進程上面,我們要更多地做批量的、合并的處理,流式地去發送。
另外,我們任何一個系統,特別是在線處理類的,沒有辦法確保沒有問題產生。無論是新發版還是觸發了一個很久之前有 bug 的情況,往往是很難定位的,可能在幾分鐘里面定位不出來或者半小時都定位不出來。那這個時候可以快速地把流量切到另外一個機房去,這樣對業務整體基本上沒影響。這也是單元化帶來了一個非常大的好處。
- 技術挑戰--熱點
2016年雙十一的一個小插曲,我們Tair的一臺機器流量特別大,最高大概到了70%+左右,該服務器的 QPS 在當時幾十萬次每秒,但是value size特別大。當時一看就是一個火熱的手機商品,也是那幾年雙十一最熱的商品項之一,它的訪問量最大,而流量都到了一臺服務器上。當時平穩度過了,如果訪問量再大一點,流量再大一點,那可能服務器流量真會跑到一個非常高的水位,對穩定性產生影響。
目前絕大部份存儲系統和數據庫系統,對于一份數據都是單節點訪問,這個問題其實是很難避免的。而單個數據節點訪問量大,造成該現象的原因很多,例如有熱點的商品反問,還是業務寫了個死循環之類,這些都可能造成某一個節點的訪問量特別大。
在那年雙十一,Tair最新的SDK 其實具備本地緩存的功能,可以通過推送開啟。但是有的業務升級到了新版的Tair SDK,有的還沒有,所以很難全部控制住,這也是系統復雜之后應用復雜之后常見的現象,很難確保版本統一。同時,SDK側的本地緩存,占用應用服務器的資源,內存是非常寶貴的,這個緩存可能會對業務產生影響。既然SDK側的方案并不是最合適的,所以我們考慮通過服務端來解決。
最終討論的方案是,每一個DB 節點上開一個熱點區域,然后實時監測到有熱點發生。熱點發生之后,會把熱點推送到一個集群里面的 N 臺機器數,譬如 10 臺左右。在有熱點發生情況下,我們可以用集群里面 10 臺機器來扛,而不是像原來一臺機器去扛。
這里面最核心的關鍵是如何快速精準地發現,然后推送到其他數據節點上。這個時候我們可能會有在可失效的時間里面讀到臟數據,對于絕大部分業務來說基本上都是可接受的。無法接受的,我們就不開啟這個特性。
- 技術挑戰--性能與成本
2017 年產生了一個新問題,就是隨著Tair在阿里內部的規模越來越大,對成本降低有了要求,比如成本降低10%、20%,甚至更多。
成本優化,最直接的一個工作就是提升單機單節點的服務能力。下圖左邊可以看到我們任何的服務進程基本上都會有鎖,因為鎖的存在,使得整個進程的性能沒有辦法跑得非常高,所以我們對整個MDB包括今天的Tair都進行了改造。改造之后把每一個操作盡量在單個線程里面做下去,相當于盡量把鎖去掉,然后再用上了DPDK加用戶態協議棧技術。通過一系列優化之后,在下圖可以看到鎖只占了1%。在32c的機器上極限可以跑到 500萬QPS ,如果是64c的話可以達到上千萬,這個吞吐基本上是線性的當然,真正線上運行的時候,并不是運行到這么高負載,而是確保高吞吐、低延時和穩定的一個權衡值。這個工作中的成果之一——Tair HotRing,我們也將之發布在FAST會議上。
以上是阿里集團內部Tair近幾年面臨的一些重要技術挑戰,穩定性、單元化和性能成本等等。
3.云原生內存數據庫Tair產品形態
阿里云的內存數據庫Tair經過多年演進,已經完整兼容了Memcache&Redis,還有一部分是我們的圖引擎,兼容了開源的 Gremlin和Neo4j的 Cypher。我們還有一個支持標準 SQL 的引擎,這個我們用來作為高性能的實時數據處理。所以,我們今天 Tair 內存數據庫的定義是一個緩存,加上高性能數據庫及數據實時處理的定義。
Tair產品的架構形態,與我們今天在阿里云上售賣的 Redis 其實是一樣的,分為標準的主從版、雙副本主從版,也有一個集群版。所以最大可以從1個 G 擴展到數個 T ,那么它跟社區托管的 Redis 不一樣的是什么呢?我們基于持久內存,基于云盤,推出了持久內存型和容量存儲型,這兩個其實能夠滿足客戶對訪問量與容量不同要求的情況與場景。性能增強型,它的整體性能比開源 Redis 會高兩倍及以上,包括我們在里面做了非常多企業級的功能,來面向客戶的關鍵業務場景。
我們今天主推的是兩種形態,一種是Tair 性能增強,這個相當于在客戶業務的核心關鍵場景,我們建議客戶去選。相比開源 Redis,首先是它的性能更強,能夠支持因運營活動或業務變化所帶來的流量突高,訪問連接數也會更多。開源的Redis其實支持活躍的上萬連接數比較困難,而Tair性能增強其實是可以支持數萬的。
例如我們其實看到有很多客戶用社區版Redis,它就是用了讀寫分離一主五從。這個架構可以看到整個可擴展性非常低,它從從節點上讀,其實讀到的一致性也會比較弱。所以我們給客戶推薦Tair的集群版,最終價格比社區版貴了 1.2 倍,但是總體容量是社區版的 4 倍,包括總吞吐它也是 4 倍。所以Tair的性能增強版比開源版在很多場景下對客戶的整個 TCO 來說相對更有優勢一些。
2018年之后我們花了非常多的經歷在是持久內存形態上,有兩個核心目標,第一是提供一個比社區 Redis成本更低的系統,性能和Redis差不多。吞吐大概是社區版redis的90%+,成本大概是社區版的70%。它比社區版好的是每一個操作都能夠做到持久化,落到持久內存上。
下面這一頁是我們的持久內存性能對比。左邊是 Redis 6.0,然后右邊是 Tair 持久內存版。我們可以看到寫跟讀的性能總吞吐大概都是 90% +。右邊這張圖,客戶端延遲 P95(us),我們把Redis 里面的 AOF 重寫機制給去掉了,所以這個毛刺抖動是更低的,讀的話確實比全內存版本慢一點,因為本身持久內存的訪問延遲會高一點。
接下來我們看看第4部分,這部分其實是講前面支撐我們 Tair 產品形態的關鍵能力,就包括跟開源的 Redis 的核心區別是什么、關鍵技術點是什么?先看看客戶用 Redis 的一些痛點。
4.云原生內存數據庫Tair關鍵能力
4.1 Redis的一些痛點
我們可以看一下左邊跟右邊的痛點為什么會是這樣的情況?
其實總結下來就是開源的 Redis 在超多訪問鏈接下,它的性能會下降。但是在容器化的時代下,應用的服務器變得越來越多,每一臺應用它的訪問連接數也會越來越多,幾千上萬是很常見的。
另外,在延時&抖動上, Redis 其實是一個單線程的,那在這種情況下,它只要有一個慢查詢,譬如 Hgetall 之類的,它往往會帶來整體變慢,其他的短查詢也得不到很好地處理。
HA 高可用會出現誤判,跟前面一樣,一個 Hgetall比較大的情況下,處理線程會把CPU 全占住, HA 的判活就有可能得不到處理,所以它的整個數據操作與控制操作都是在一個工作線程內處理的。還有整體的內存統計是沒有區分開的,所以用戶往往發現配了實例內存,還沒有用滿的情況下就發生了數據淘汰。
然后,我們從內核的技術上來講一下 Redis 與 Tair 的一個區別。
4.2 Redis vs Tair
上圖左邊是開源的 Redis 在6.0之前,它是一個單線程的。在 6.0 之后,它號稱是一個多線程的,但是從右圖也能夠看到,它只是在 IO 處理這塊搞成多線程了,但是在內部真正的數據操作這一塊,它依然是單線程在做。
為什么它很難做成多線程呢?一是因為在原來的 Redis 內部,所有都是單線程的,大部分操作是沒有鎖的,所以想改成多線程是非常困難的;二是代碼是在10年前寫的,并沒有進行重構過,在歷史代碼上去做優化是相對困難的。
對于Tair來說,我們脫離Redis,從頭自研,我們把網絡接收線程跟工作處理線程獨立開了,都可以用 N x M 的方式靈活地去配;這樣 Tair 就可以處理數十萬的活躍的連接數,因為網絡線程足夠多,單機的處理引擎可以提升得足夠高,甚至可以跑到百萬級。
在業內也有一種討論,到底是搞成分布式好還是搞成單機好?
在我看來,非常多情況下,單機的形態會有不少優勢。如今業務越來越復雜,如果把它搞成分布式,往往會有一些跨節點的計算,甚至要求這些計算要有事務。搞成集群后,跨節點的計算和事務會變得越來越復雜,很難去處理。在這種情況下,能夠給客戶一個大規格、大訪問處理量的單機引擎其實是最合適的。
當然,在多線程內部我們也做了一些慢查詢請求,把它實時監測出來,并且分離到慢查詢請求池里面。這一類的工作,我們盡量確保用戶的請求能夠在一個比較確定的訪問延時里面返回給用戶。
接下來我們看看Tair引擎的高可用,前面我們講了社區版的 Redis ,它的探活跟數據操作其實是在一個工作線程里面,因為數據操作慢了之后,會產生一些誤判,所以我們把所有的管控請求放到獨立的處理系統里面;就把這些 HA 把這些訪問、統計信息等完全隔離,包括用戶的數據訪問跟系統的高可用統計都是隔離開的,確保質量更好。
接下來我們講講Tair的集群架構。
4.3Tair的集群架構
Tair的集群架構,包括搬遷的擴縮容,與開源的社區版是完全不一樣的。開源的社區都是用 Gossip ,相當于是P2P 來做信息的同步與探活。另外它的節點變得越來越多的時候,想在集群里面達到信息的一致性也會變得越來越慢。社區版的遷移擴縮容是按 Key 級別的,所以在大 Key 的時候往往會出現一些遷移卡頓等,這個時候也會有一些 HA 的誤判。我們如今在這一方面也做了一些改進,相當于是由中心節點對整個集群做 HA 的判活,包括集群管理。整個數據搬遷是按slot去搬遷的,所以整個搬遷速度會比按key快很多。
4.4 特定重要場景的優化
Pubsub相當于是 Tair 與 Redis 里面做消息處理用的。原來的單線程,如果是掛載的客戶端多的話,其實推送起來會比較慢。它的單線處理,相當于在Tair 里面把它作為一個多線程處理,所以這是一個并發的處理操作。
4.5 TairStack:豐富的數據模型
TairStack有著豐富的數據模型,這其實是在阿里內部實踐中積累出的常用數據結構,目的就是讓業務開發更容易。從上圖可以看到,我們有些是對外開源了,包括:TairHash、TairString等,這些結構也是可以放到開源的 Redis 里面去用,跟開源的 Redis 是完全兼容的,這些module在公共云上也被非常多客戶使用了。
接下來我們看看Tair的企業級能力。
4.6 Tair的企業級能力
Tair的企業級能力這里我主要講3部分,包括全球多活、安全能力和 Tair引擎可觀測性。
- 全球多活
如今的一些客戶,特別是中大型的客戶,他希望在多個地域做多活。所以我們今天是可以做到三地域多活的同步。它的原理是通過 Binlog 來做 3地的多活。我們更建議應用在做多活的時候,能夠在應用層面按 key 分布到多個單元,這樣會更容易避免沖突。
- 安全能力
安全能力部分在公有云上也是比較重要的一個地方。我們提供給客戶的實例是在VPC內部,整個安全網絡上面是有確保的,客戶可以通過 SSL來加密訪問Tair,這個上面可以進行更高層次的訪問通信的加密。
我們有一個功能叫 PITR,可以幫助客戶把數據恢復到客戶指定的任意時間點,可以到秒級別。還有一個重要的功能就是用戶的審計。經常會有一些客戶說,我的訪問量怎么這么大?這個訪問源是從哪里過來的?或者是我的數據被清理掉了,是哪里被刪的,通過這個是能夠看得到的。所以從整個技術實現上來說,我們其實做了一些高頻的快照,大家可以認為是一個全量的快照,再加上增量的 Binlog 來幫助客戶恢復到那個時間點去。
- Tair引擎可觀測性
在可觀測性上我們投入的也比較多,當然還是有一些沒有做得特別好,譬如集群級別的聚合工作其實一直在探索。我們能夠把有熱 Key 的、有訪問量比較大 key 的實時地看到,包括在引擎級別,每一個操作的訪問延時是能夠看得到的。一旦慢了的話,我們可以看到在哪一塊操作上慢了。
5.Tair 應用
- 電商方面:
Tair在電商方面,主要是用做緩存與內存存儲,一般就用在登陸系統、用戶系統、商品系統、購物車、個性化推薦上面。
- 游戲方面:
游戲客戶最重要的除了低延遲、彈性伸縮、高可用之外,還有備份回檔、無感擴容。我們今天在主動擴容下,它的業務并不會掉線。這個是通過我們整體的集群方案,包括數據的遷移方案來提供給客戶的。
- 金融、安全風控方面:
在金融、安全風控方面,Tair里面做了一些計算的算值,可以在某一個時間段里面譬如購買商品的數量,這一類的計算來做防黃牛反作弊。
- 生活服務方面:
LBS 生活服務,主要通過即時的功能來完成。它與 Redis Geohash的核心區別是 Geohash只能做點對點關系的鄰近的查詢,譬如它只能搜最近10km的人或者是離我最近的店。
6.總結
第一部分講了Tair從阿里集團經過 13 年,發展到阿里云上推出給客戶使用。從單一緩存發展到幫助客戶構建多樣化實時場景。
第二部分是前幾年在阿里集團內部所面臨的一些重要技術挑戰,包括熱點、多活、性能、成本等問題的解決和優化。
第三、第四部分關于通過Tair自研引擎充分利用云基礎設施上面不同的存儲介質來給客戶提供更合適的選擇和更高的服務SLA。最后關于Tair的應用解讀,助力客戶構建在線實時場景。