1. Tair總述
1.1 系統架構
一個Tair集群主要包括3個必選模塊:configserver、dataserver和client,一個可選模塊:invalidserver。通常情況下,一個集群中包含2臺configserver及多臺dataServer。兩臺configserver互為主備并通過維護和dataserver之間的心跳獲知集群中存活可用的dataserver,構建數據在集群中的分布信息(對照表)。dataserver負責數據的存儲,并按照configserver的指示完成數據的復制和遷移工作。client在啟動的時候,從configserver獲取數據分布信息,根據數據分布信息和相應的dataserver交互完成用戶的請求。invalidserver主要負責對等集群的刪除和隱藏操作,保證對等集群的數據一致。
從架構上看,configserver的角色類似于傳統應用系統的中心節點,整個集群服務依賴于configserver的正常工作。但實際上相對來說,tair的configserver是非常輕量級的,當正在工作的服務器宕機的時候另外一臺會在秒級別時間內自動接管。而且,如果出現兩臺服務器同時宕機的最惡劣情況,只要應用服務器沒有新的變化, tair依然服務正常。而有了configserver這個中心節點,帶來的好處就是應用在使用的時候只需要配置configserver的地址(現在可以直接配置Diamond key),而不需要知道內部節點的情況。

1.1.1 ConfigServer的功能
1) 通過維護和dataserver心跳來獲知集群中存活節點的信息
2) 根據存活節點的信息來構建數據在集群中的分布表。
3) 提供數據分布表的查詢服務。
4) 調度dataserver之間的數據遷移、復制。
1.1.2 DataServer的功能
1) 提供存儲引擎
2) 接受client的put/get/remove等操作
3) 執行數據遷移,復制等
4) 插件:在接受請求的時候處理一些自定義功能
5) 訪問統計
1.1.3 InvalidServer的功能
1) 接收來自client的invalid/hide等請求后,對屬于同一組的集群(雙機房獨立集群部署方式)做delete/hide操作,保證同一組集群的一致。
2) 集群斷網之后的,臟數據清理。
3) 訪問統計。
1.1.4 client的功能
1) 在應用端提供訪問Tair集群的接口。
2) 更新并緩存數據分布表和invalidserver地址等。
3) LocalCache,避免過熱數據訪問影響tair集群服務。
4) 流控
1.2 存儲引擎與應用場景
Tair經過這兩年的發展演進,除了應用于cache緩存外,在存儲(持久化)上支持的應用需求也越來越廣泛。現在主要有mdb,rdb,ldb三種存儲引擎。
1.2.1 mdb
定位于cache緩存,類似于memcache。
支持k/v存取和prefix操作
1.2.1.1 mdb的應用場景
在實際業務中,大部分當緩存用(后端有DB之類的數據源)。
也可用做大訪問少量臨時數據的存儲(例如session登錄,防攻擊統計等)。
集團內絕對多數cache服務都是采用的tair mdb。
1.2.2 rdb
定位于cache緩存,采用了redis的內存存儲結構。
支持k/v,list,hash,set,sortedset等數據結構。
1.2.2.1 rdb的應用場景
適用于需要高速訪問某些數據結構的應用,例如SNS中常見的的粉絲存儲就可以采用set等結構;或者存儲一個商品的多個屬性(hashmap);高效的消息隊列(list)等。現在有30個左右的應用在使用rdb服務。
1.2.3 ldb
定位于高性能存儲,并可選擇內嵌mdb cache加速,這種情況下cache與持久化存儲的數據一致性由tair進行維護。 支持k/v,prefix等數據結構。今后將支持list,hash,set,sortedset等redis支持的數據結構。
1.2.3.1 ldb的應用場景
存儲,里面可以細分如下場景:
1) 持續大數據量的存入讀取,類似淘寶交易快照。
2) 高頻度的更新讀取,例如計數器,庫存等。
3) 離線大批量數據導入后做查詢。參見fastdump
也可以用作cache:
數據量大,響應時間敏感度不高的cache需求可以采用。例如天貓實時推薦。
1.3 基本概念
1.3.1 configID
唯一標識一個tair集群,每個集群都有一個對應的configID,在當前的大部分應用情況下configID是存放在diamond中的,對應了該集群的configserver地址和groupname。業務在初始化tairclient的時候需要配置此ConfigID。
1.3.2 namespace
又稱area, 是tair中分配給應用的一個內存或者持久化存儲區域, 可以認為應用的數據存在自己的namespace中。
同一集群(同一個configID)中namespace是唯一的。
通過引入namespace,我們可以支持不同的應用在同集群中使用相同的key來存放數據,也就是key相同,但內容不會沖突。一個namespace下是如果存放相同的key,那么內容會受到影響,在簡單K/V形式下會被覆蓋,rdb等帶有數據結構的存儲引擎內容會根據不同的接口發生不同的變化。
1.3.3 quota配額
對應了每個namespace儲存區的大小限制,超過配額后數據將面臨最近最少使用(LRU)的淘汰。
持久化引擎(ldb)本身沒有配額,ldb由于自帶了mdb cache,所以也可以設置cache的配額。超過配額后,在內置的mdb內部進行淘汰。
1.3.3.1 配額是怎樣計算的
配額大小直接影響數據的命中率和資源利用效率,業務方需要給出一個合適的值,通常的計算方法是評估在保證一定命中率情況下所需要的記錄條數,這樣配額大小即為: 記錄條數 * 平均單條記錄大小。
1.3.3.2 管理員如何配置配額
單份數據情況下,業務提供的配額就是需要配置在Tair系統中的配額。但對于多備份,在系統中實際計算的配額為: 業務配額 * 備份數
1.3.4 expireTime:過期時間
expiredTime 是指數據的過期時間,當超過過期時間之后,數據將對應用不可見,這個設置同樣影響到應用的命中率和資源利用率。不同的存儲引擎有不同的策略清理掉過期的數據。調用接口時,expiredTime單位是秒,可以是相對時間(比如:30s),也可以是絕對時間(比如:當天23時,轉換成距1970-1-1 00:00:00的秒數)。 小于0,不更改之前的過期時間
如果不傳或者傳入0,則表示數據永不過期;
大于0小于當前時間戳是相對時間過期;
大于當前時間戳是絕對時間過期;
1.3.5 version
Tair中存儲的每個數據都有版本號,版本號在每次更新后都會遞增,相應的,在Tair put接口中也有此version參數,這個參數是為了解決并發更新同一個數據而設置的,類似于樂觀鎖。
很多情況下,更新數據是先get,修改get回來的數據,然后put回系統。如果有多個客戶端get到同一份數據,都對其修改并保存,那么先保存的修改就會被后到達的修改覆蓋,從而導致數據一致性問題,在大部分情況下應用能夠接受,但在少量特殊情況下,這個是我們不希望發生的。
比如系統中有一個值”1”, 現在A和B客戶端同時都取到了這個值。之后A和B客戶端都想改動這個值,假設A要改成12,B要改成13,如果不加控制的話,無論A和B誰先更新成功,它的更新都會被后到的更新覆蓋。Tair引入的version機制避免了這樣的問題。剛剛的例子中,假設A和B同時取到數據,當時版本號是10,A先更新,更新成功后,值為12,版本為11。當B更新的時候,由于其基于的版本號是10,此時服務器會拒絕更新,返回version error,從而避免A的更新被覆蓋。B可以選擇get新版本的value,然后在其基礎上修改,也可以選擇強行更新。
1.3.5.1 如何獲取到當前key的version
get接口返回的是DataEntry對象,該對象中包含get到的數據的版本號,可以通過getVersion()接口獲得該版本號。在put時,將該版本號作為put的參數即可。 如果不考慮版本問題,則可設置version參數為0,系統將強行覆蓋數據,即使版本不一致。
1.3.5.2 version是如何改變的
Version改變的邏輯如下:
1) 如果put新數據且沒有設置版本號,會自動將版本設置成1。
2) 如果put是更新老數據且沒有版本號,或者put傳來的參數版本與當前版本一致,版本號自增1。
3) 如果put是更新老數據且傳來的參數版本與當前版本不一致,更新失敗,返回VersionError。
4) put時傳入的version參數為0,則強制更新成功,版本號自增1。
1.3.5.3 version返回不一致的時候,該如何處理
如果更新所基于的version和系統中當前的版本不一致,則服務器會返回ResultCode.VERERROR。 這時你可以重新get數據,然后在新版本的數據上修改;或者設置version為0重新請求,以達到強制更新的效果,應用可以根據自身對數據一致性的要求在這兩種策略間進行選擇。
1.3.5.4 version具體使用案例
如果應用有10個client會對key進行并發put,那么操作過程如下:
1) get key。如果get key成功,則進入步驟2;如果數據不存在,則進入步驟3.
2) 在調用put的時候將get key返回的verison重新傳入put接口。服務端根據version是否匹配來返回client是否put成功。
3) get key數據不存在,則新put數據。此時傳入的version必須不是0和1,其他的值都可以(例如1000,要保證所有client是一套邏輯)。因為傳入0,tair會認為強制覆蓋;而傳入1,第一個client寫入會成功,但是新寫入時服務端的version以0開始計數啊,所以此時version也是1,所以下一個到來的client寫入也會成功,這樣造成了沖突
1.3.5.5 version分布式鎖
Tair中存在該key,則認為該key所代表的鎖已被lock;不存在該key,在未加鎖。操作過程和上面相似。業務方可以在put的時候增加expire,已避免該鎖被長期鎖住。
當然業務方在選擇這種策略的情況下需要考慮并處理Tair宕機帶來的鎖丟失的情況。
1.3.5.6 什么情況下需要使用version
業務對數據一致性有較高的要求,并且訪問并發高,那么通過version可以避免數據的意外結果。
如果不關心并發,那么建議不傳入version或者直接傳0。
1.4 集群部署方式
Tair通過多種集群部署方式,來滿足各類應用的容災需求。
下面所述的雙機房可以擴展到多機房,現階段基本還是采用的雙機房。
現總共有4種方式:
mdb存儲引擎適用于雙機房單集群單份,雙機房獨立集群,雙機房單集群雙份。
rdb存儲引擎適用于雙機房單集群單份。
ldb存儲引擎適用于雙機房主備集群,雙機房單集群單份。
1.4.1 雙機房單集群單份
雙機房單集群單備份數是指,該Tair集群部署在兩個機房中(也就是該Tair集群的機器分別在兩個機房), 數據存儲份數為1, 該類型集群部署示意圖如下所示。數據服務器(Dataserver)分布在兩個機房中,他們都屬于同一集群。

使用場景:
1) 后端有無數據源都可。
2) 后端有數據源,且更新比例很高的場景。
優點:
1) 服務器存在于雙機房,任一機房宕機保持可用。
2) 單份數據,無論應用在哪個機房,看到的都是同一個數據。
缺點:
1) 應用服務器會跨機房訪問。如上圖,并假設應用服務器在cm3和cm4,那么cm3的應用服務器也可能調用到cm4的tair機器,cm4的亦然。
2) 當一邊機房出現故障時,tair中的數據會失效一半(一半這個數值是按兩邊機房tair機器數相同估計的,如果不相同,則按對應比例估算)
該部署方式,應用在刪除數據時,只需要調用delete即可,無需調用invalid。當然,調用invalid也可,這種方式下會直接退化到delete。
1.4.2 雙機房獨立集群
雙機房獨立集群是指,在兩個機房中同時部署2個獨立的Tair集群,這兩個集群沒有直接關系。下圖是一個典型的雙機房獨立集部署示意圖,可以看到,cm3和cm4各有一個完整的tair集群(2個configserver+多個dataserver)。圖中還多了一個invalidserver的角色, invalidserver接收客戶端的invalid或者hide請求后,會對各機房內的集群進行delete或者hide操作,以此保障Tair中的數據和后端數據源保持一致的。

適用場景:
1) 后端必須要有數據源,否則則退化成單機房集群,Tair集群本身不做同步。
2) 讀寫比不能過小,不然可能會帶來Tair命中率降低。例如某個key,在數據庫中被頻繁更新,那么此時應用必須調用invalid來確保Tair和DB的一致性。此時應用讀Tair一直會不命中,導致整體命中率低,可能造成DB壓力比較大。 如果依然有疑問的話,請聯系 tair答疑。
優點:
1) 每個機房擁有獨立Tair集群,應用在哪個機房就訪問相同機房的Tair集群,不會出現跨機房調用和流量。
2) 單邊機房故障,不會影響業務訪問tair命中率。
缺點:
1) 后端必須要有數據源,也就是這種部署方式下,Tair必然是當作傳統意義上的cache存在的。因為Tair mdb集群之間本身不會做數據同步,多集群間一致性保證依賴于后端數據源,如DB。
2) 當后端數據源數據發生更新后,業務不能直接把數據put到Tair,而是先需要調用invalid接口來失效這些對等集群中的數據(來保持各Tair集群的數據和后端數據源的一致性)。之后業務可以把數據put到當前Tair集群(注意:只會put到本機房的Tair集群,不會put到對端集群)或者在讀Tair時發生not exist的時候從后端數據源取來放入Tair。
1.4.3 雙機房單集群雙份
雙機房單集群雙份,是指一個Tair集群部署在2個機房中,數據保存2份,并且同一數據的2個備份不會放在同一個數據服務器上。根據數據分布策略的不同,還可以將同一份數據的不同備份分布到不同的機房上。該類型的集群部署方式與雙機房單集群單份數據的部署方式一樣。其不同之處,數據保存份數不一樣。該類型集群部署方式示意圖如下圖所示,數據服務器分別部署在兩個不同的機房里,所有的數據服務器都被相同的配置服務器管理,在邏輯上,他們構成一個獨立的集群。

現只有tbsession集群使用了這種部署方式。
適用場景:
后端無數據源,臨時數據的存放,非cache。
cache類應用推薦使用雙機房獨立集群和雙機房單集群單份部署方式。
優點:
1) 數據存放兩份,數據安全性有一定保障。但由于存儲引擎是mdb,數據存放在內存中,無法絕對保證數據不丟失。
2) 當一邊機房故障時,另外一邊機房依然可以服務,并且數據不丟失。
缺點:
1) 如果機房間網絡出現異常情況,依然有較小幾率丟失數據。
1.4.4 雙機房主備集群
這種部署方式中,存在一個主集群和一個備份集群,分別在兩個機房中。如下圖所示,不妨假設CM3中部署的是主集群,CM4中部署的是備份集群。那么,在正常情況下,用戶只使用主集群,讀寫數據都與主集群交互。主備集群會自動同步數據(不需要業務去更新兩邊),保證兩個機房數據的最終一致性。當一個機房發生故障后,備集群會自動切換成主集群,提供服務,保證系統可用性。

適用場景:
該方式只在ldb存儲引擎中存在,也就是業務將Tair當作最終存儲使用。我們會在當前主集群存兩份數據,并由Tair異步將數據更新到備集群,確保數據安全和服務可用。
優點:
1) 數據安全和服務可用性高。
2) 用戶調用方便,無需考慮多集群間數據一致性的問題。