揭祕!雙11萬億流量下的分佈式緩存系統 Tair,真的了不起

阿里妹導讀:本文以雙11面臨的挑戰爲背景,從Tair(阿里自研高速緩存系統)發展和應用開始談起,重點分享了性能優化方面的實踐,最後對緩存熱點難題給出瞭解決方案,希望能對大家的工作有所啓發。
本文作者爲宗岱,阿里巴巴資深技術專家,2008年加入淘寶,阿里分佈式緩存、NoSQL數據庫Tair和Tengine負責人。

Tair概覽

Tair發展歷程

Tair在阿里巴巴被廣泛使用,無論是淘寶天貓瀏覽下單,還是打開優酷瀏覽播放時,背後都有Tair的身影默默支撐巨大的流量。Tair的發展歷程如下:

  • 2010.04 Tair v1.0正式推出@淘寶核心系統;

  • 2012.06 Tair v2.0推出LDB持久化產品,滿足持久化存儲需求;

  • 2012.10 推出RDB緩存產品,引入類Redis接口,滿足複雜數據結構的存儲需求;

  • 2013.03 在LDB的基礎上針對全量導入場景上線Fastdump產品,大幅度降低導入時間和訪問延時;

  • 2014.07 Tair v3.0 正式上線,性能數倍提升;

  • 2016.11 泰斗智能運維平臺上線,助力2016雙11邁入千億時代;

  • 2017.11 性能飛躍,熱點散列,資源調度,支持萬億流量。

Tair是一個高性能、分佈式、可擴展、高可靠的key/value結構存儲系統!Tair特性主要體現在以下幾個方面:

  • 高性能:在高吞吐下保證低延遲,Tair是阿里集團內調用量最大系統之一,雙11達到每秒5億次峯值的調用量,平均訪問延遲在1毫秒以下;

  • 高可用:通過自動failover,限流,審計和機房內容災以及多單元多地域,確保系統在任何情況下都能正常運行;

  • 規模化:分佈全球各個數據中心,阿里集團各個BU都在使用;

  • 業務覆蓋:電商、螞蟻、合一、菜鳥、高德、阿里健康等。

Tair除了普通Key/Value系統提供的功能,比如get、put、delete以及批量接口外,還有一些附加的實用功能,使得其有更廣的適用場景。Tair應用場景包括以下四種:

  1. MDB 典型應用場景:用於緩存,降低對後端數據庫的訪問壓力,比如淘寶中的商品都是緩存在Tair中;用於臨時數據存儲,部分數據丟失不會對業務產生較大影響,例如登陸;

  2. LDB 典型應用場景:通用kv存儲、交易快照、安全風控等;存儲黑白單數據,讀qps很高;計數器功能,更新非常頻繁,且數據不可丟失。

  3. RDB 典型應用場景:複雜的數據結構的緩存與存儲,如播放列表,直播間等。

  4. FastDump 典型應用場景:週期性地將離線數據快速地導入到Tair集羣中,快速使用到新的數據,對在線讀取要求非常高;讀取低延遲,不能有毛刺。

雙 11 挑戰怎麼辦?

v2-0db65cf6ec6173bd00ae452aba9a7df5_hd.jpg

2012-2017年數據如圖,可以看到,2012年GMV小於200億,2017年GMV達到1682億,交易創建峯值從1.4萬達到32.5萬,峯值QPS從1300萬達到近5億。

從圖中可以看出,tair訪問增速遠大於交易創建峯值,交易創建峯值也大於GMV的增長。也就是0點的那刻,對Tair來說,在保證高併發訪問的同時,如何確保低延遲,如何確保成本低於業務增速的技術挑戰越來越大。

對於分佈式存儲系統來說,熱點問題都是比較難解決的。而緩存系統流量特別大,熱點問題更爲突出。2017年雙11,我們通過了熱點散列,徹底解決掉了緩存熱點問題。

同時,爲了承載每秒32.5萬筆交易阿里的技術架構也不斷演進成爲多地域多單元的架構,不僅採用了阿里雲上的單元,而且也有和離線服務混部的單元,這裏對我們的挑戰是如何快速彈性的部署和下線集羣。

多地域多單元

v2-b3ec8894fa00e4637f61d4e80e6a2b7b_hd.jpg

先看下我們大致整體的部署架構和tair在系統中的位置。從這張簡圖上看到,我們是一個多地域多機房多單元的部署架構。整個系統上從流量的接入層,到應用層。然後應用層依賴了各種中間件,例如消息隊列,配置中心等等。最底層是基礎的數據層,tair和數據庫。在數據這一層,我們需要爲業務做需要的數據同步,以保障上層業務是無狀態的。

多地域多單元除了防止黑天鵝之外,另外一個重要的作用是能夠通過快速上線一個單元來實現承載部分的流量。Tair也做了一整套控制系統來實現快速的彈性建站。

彈性建站

v2-4566c487d69ebbcd838372e24bb4ebc0_hd.jpg

Tair本身是一個很複雜分佈式存儲系統,規模也非常龐大。所以我們有一個叫泰斗的運營管理平臺。在這裏面通過任務編排,任務執行,驗證和交付等流程來確保快速的一鍵建站,離在線混部集羣的快上快下工作。在部署工作完成後,會經過一系列系統,集羣,實例上的連通性驗證來確保服務完整無誤後,再交付上線使用。如果有一絲遺漏,那麼業務流量過來時,可能會觸發大規模故障。這裏面,如果是帶數據的持久化集羣,那麼在部署完成後,還需要等待存量數據遷移完成並且數據達到同步後才能進入驗證階段。

Tair的每一個業務集羣水位其實是不一樣的,雙11前的每一次全鏈路壓測,由於業務模型的變化,所用Tair資源會發生變化,造成水位出現變化。在此情況下,我們每次都需要壓測多個集羣間調度的Tair資源。如果水位低,就會把某些機器服務器資源往水位高挪,達到所有集羣水位值接近。

數據同步

v2-ddc0e2dbedd33b3a3258bff949ea5bc1_hd.jpg

多地域多單元,必須要求我們數據層能夠做到數據的同步,並且能夠提供給業務各種不同的讀寫模式。對於單元化業務,我們提供了本單元訪問本地Tair的能力,對於有些非單元化業務,我們也提供了更靈活的訪問模型。同步延遲是我們一直在做的事情,2017年雙11每秒同步數據已經達到了千萬級別,那麼,如何更好地解決非單元化業務在多單元寫入數據衝突問題?這也是我們一直考慮的。

性能優化降成本

服務器成本並不是隨着訪問量線性增長,每年以百分之三四十成本在下降,我們主要通過服務器性能優化、客戶端性能優化和不同的業務解決方案三方面達到此目標。

先來看下我們如何從服務端角度提升性能和降低成本的。這裏的工作主要分爲兩大塊:一塊是避免線程切換調度,降低鎖競爭和無鎖化,另外一塊是採用用戶態協議棧+DPDK來將run-to-completion進行到底。

內存數據結構

v2-fc5a3e193cbc5099c0da4a9c1a2b8d5d_hd.jpgMDB內存數據結構示意圖

我們在進程啓動之後會申請一大塊內存,在內存中將格式組織起來。主要有slab分配器、hashmap和內存池,內存寫滿後會經過LRU鏈進行數據淘汰。隨着服務器CPU核數不斷增加,如果不能很好處理鎖競爭,很難提升整體性能。

v2-d841769e412e1cd444e197ce3f93d07a_hd.jpg

通過參考各種文獻,並結合tair自身引擎需求,我們使用了細粒度鎖、無鎖數據結構、CPU本地數據結構和RCU機制來提升引擎的並行性。左圖爲未經過優化時各個功能模塊的CPU消耗圖,可以看到網絡部分和數據查找部分消耗最多,優化後(右圖)有80%的處理都是在網絡和數據的查找,這是符合我們期望的。

用戶態協議棧

v2-0043f27704bacaaca9f70719225aa61e_hd.jpg

鎖優化後,我們發現很多CPU消耗在內核態上,這時我們採用DPDK+Alisocket來替換掉原有內核態協議棧,Alisocket採用DPDK在用戶態進行網卡收包,並利用自身協議棧提供socket API,對其進行集成。我們將tair,memcached以及業內以性能著稱的seastar框架相比,tair的性能優勢在seastar 10%以上。

內存合併

v2-904f125467e8b7095f0dd7a6b3a01ff3_hd.jpg

當性能提升後,單位qps所佔用的內存就變少了,所以內存變得很緊缺。另外一個現狀,tair是一個多租戶的系統,各個業務行爲不太一樣,時常會造成page已經分配完畢,但是很多slab裏的page都是未寫滿的。而有少量slab確實已經全佔滿了,造成了看上去有容量,但無法分配數據的情況。

此時,我們實施了一個將同一slab裏未寫滿page內存合併的功能,可以釋放出大量空閒內存。從圖中可以看到,在同一個slab裏,記錄了每個page的使用率,並掛載到不同規格的bucket上。合併時,將使用率低的page往使用率高的page上合併。同時還需要將各個相關聯的數據結構,包括LRU鏈,相當於整個內存結構的重整。這個功能在線上的公用集羣裏效果特別好,根據不同場景,可以大幅提升內存使用效率。

客戶端優化

v2-2eab0b594c417384086c193399c294cf_hd.jpg

上面這些是服務端的變化,接下來看看客戶端的性能。我們的客戶端是運行在客戶服務器上的,所以佔用了客戶的資源。如果能儘可能低的降低資源消耗,對我們整個系統來說,成本都是有利的。客戶端我們做了兩方面優化:網絡框架替換,適配協程,從原有的mina替換成netty,吞吐量提升40%;序列化優化,集成 kryo和hessian,吞吐量提升16%+。

內存網格

v2-7947363316961eccc12b7463d617efea_hd.jpg

如何與業務結合來降低整體Tair與業務成本?Tair提供了多級存儲一體化解決業務問題,比如安全風控場景,讀寫量超大、有大量本地計算,我們可以在業務機器本地存下該業務機器所要訪問的數據,大量讀會命中在本地,而且寫在一段時間內是可合併的,在一定週期後,合併寫到遠端Tair集羣上作爲最終存儲。我們提供讀寫穿透,包括合併寫和原有Tair本身具有多單元複製的能力,雙11時業務對Tair讀取降至27.68%,對Tair寫入降至55.75%。

熱點難題已解決

緩存擊穿

v2-8dd2733e416972dace276b9167220a40_hd.jpg

緩存從開始的單點發展到分佈式系統,通過數據分片方式組織,但對每一個數據分片來說,還是作爲單點存在的。當有大促活動或熱點新聞時,數據往往是在某一個分片上的,這就會造成單點訪問,進而緩存中某個節點就會無法承受這麼大壓力,致使大量請求沒有辦法響應。對於緩存系統一個自保的方法是限流。但是限流對於整個系統來說,並無濟於事。限流後,一部分流量會去訪問數據庫,那依然和剛剛所說的無法承受是一樣的結果,整個系統出現異常。

所以在這裏,唯一的解決辦法是緩存系統能夠作爲流量的終結點。不管是大促,還是熱點新聞,還是業務自己的異常。緩存都能夠把這些流量吸收掉,並且能讓業務看到熱點的情況。

熱點散列

v2-909e5aad3c23945429749d9cbbe4b96f_hd.jpg

經過多種方案的探索,採用了熱點散列方案。我們評估過客戶端本地cache方案和二級緩存方案,它們可以在一定程度上解決熱點問題,但各有弊端。例如二級緩存的服務器數目無法預估,本地cache方案對的業務側內存和性能的影響。而熱點散列直接在數據節點上加hotzone區域,讓hotzone承擔熱點數據存儲。對於整個方案來說,最關鍵有以下幾步:

  • 智能識別。熱點數據總是在變化的,或是頻率熱點,或是流量熱點。內部實現採用多級LRU的數據結構,設定不同權值放到不同層級的LRU上,一旦LRU數據寫滿後,會從低級LRU鏈開始淘汰,確保權值高的得到保留。

  • 實時反饋和動態散列。當訪問到熱點時,appserver和服務端就會聯動起來,根據預先設定好的訪問模型動態散列到其它數據節點hotzone上去訪問,集羣中所有節點都會承擔這個功能。

通過這種方式,我們將原來單點訪問承擔的流量通過集羣中部分機器來承擔。

v2-ced543b4c3742d47a8d6d1ab6cc5644b_hd.jpg

整個工程實現是很複雜的,熱點散列在雙11中取得了非常顯著的效果。峯值每秒吸收了800多w的訪問量。從右圖可以看到,紅色的線是如果未開啓熱點散列的水位,綠色的線是開啓熱點散列的水位。如果未開啓,很多集羣都超過了死亡水位,也就是我們集羣水位的130%。而開啓之後,通過將熱點散列到整個集羣,水位降低到了安全線下。換而言之,如果不開啓,那麼很多集羣都可能出現問題。

寫熱點

v2-dea254adf2755a8a297e1b8ea738d122_hd.jpg

寫熱點與讀熱點有類似的地方,這塊主要是通過合併寫操作來實施。首先依然是識別出熱點,如果是熱點寫操作,那麼該請求會被分發到專門的熱點合併線程處理,該線程根據key對寫請求進行一定時間內的合併,隨後由定時線程按照預設的合併週期將合併後的請求提交到引擎層。通過這種方式來大幅降低引擎層的壓力。

經過雙11考驗對讀寫熱點的處理,我們可以放心的說,Tair將緩存包括kv存儲部分的讀寫熱點徹底解決了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章