|
Tair是由淘寶網(wǎng)自主開(kāi)發(fā)的Key/Value結(jié)構(gòu)數(shù)據(jù)存儲(chǔ)系統(tǒng),在淘寶網(wǎng)有著大規(guī)模的應(yīng)用。您在登錄淘寶、查看商品詳情頁(yè)面或者在淘江湖和好友“搗漿糊”的時(shí)候,都在直接或間接地和Tair交互。
Tair于2010年6月30號(hào)在淘寶開(kāi)源平臺(tái)上正式對(duì)外開(kāi)源,本文較詳細(xì)地介紹了Tair提供的功能及其實(shí)現(xiàn)的細(xì)節(jié),希望對(duì)大家進(jìn)一步了解Tair有所幫助。
Tair的功能
Tair是一個(gè)Key/Value結(jié)構(gòu)數(shù)據(jù)的解決方案,它默認(rèn)支持基于內(nèi)存和文件的兩種存儲(chǔ)方式,分別和我們通常所說(shuō)的緩存和持久化存儲(chǔ)對(duì)應(yīng)。
Tair除了普通Key/Value系統(tǒng)提供的功能,比如get、put、delete以及批量接口外,還有一些附加的實(shí)用功能,使得其有更廣的適用場(chǎng)景,包括:
- Version支持>
- 原子計(jì)數(shù)器
- Item支持
Version支持
Tair中的每個(gè)數(shù)據(jù)都包含版本號(hào),版本號(hào)在每次更新后都會(huì)遞增。這個(gè)特性有助于防止由于數(shù)據(jù)的并發(fā)更新導(dǎo)致的問(wèn)題。
比如,系統(tǒng)有一個(gè)value為“a,b,c”,A和B同時(shí)get到這個(gè)value。A執(zhí)行操作,在后面添加一個(gè)d,value為“a,b,c,d”。B執(zhí)行操作添加一個(gè)e,value為”a,b,c,e”。如果不加控制,無(wú)論A和B誰(shuí)先更新成功,它的更新都會(huì)被后到的更新覆蓋。
Tair無(wú)法解決這個(gè)問(wèn)題,但是引入了version機(jī)制避免這樣的問(wèn)題。還是拿剛才的例子,A和B取到數(shù)據(jù),假設(shè)版本號(hào)為10,A先更新,更新成功后,value為”a,b,c,d”,與此同時(shí),版本號(hào)會(huì)變?yōu)?1。當(dāng)B更新時(shí),由于其基于的版本號(hào)是10,服務(wù)器會(huì)拒絕更新,從而避免A的更新被覆蓋。B可以選擇get新版本的value,然后在其基礎(chǔ)上修改,也可以選擇強(qiáng)行更新。
原子計(jì)數(shù)器
Tair從服務(wù)器端支持原子的計(jì)數(shù)器操作,這使得Tair成為一個(gè)簡(jiǎn)單易用的分布式計(jì)數(shù)器。
Item支持
Tair還支持將value視為一個(gè)item數(shù)組,對(duì)value中的部分item進(jìn)行操作。比如有個(gè)key的value為[1,2,3,4,5],我們可以只獲取前兩個(gè)item,返回[1,2],也可以刪除第一個(gè)item,還支持將數(shù)據(jù)刪除,并返回被刪除的數(shù)據(jù),通過(guò)這個(gè)接口可以實(shí)現(xiàn)一個(gè)原子的分布式FIFO的隊(duì)列。
Tair的內(nèi)部結(jié)構(gòu)

圖 1 Tair整體架構(gòu)圖
一個(gè)Tair集群主要包括client、configserver和dataserver 3個(gè)模塊。Configserver通過(guò)和dataserver的心跳(HeartBeat)維護(hù)集群中可用的節(jié)點(diǎn),并根據(jù)可用的節(jié)點(diǎn),構(gòu)建數(shù)據(jù)的在集群中的分布信息(見(jiàn)下文的對(duì)照表)。Client在初始化時(shí),從configserver處獲取數(shù)據(jù)的分布信息,根據(jù)分布信息和相應(yīng)的dataserver交互完成用戶的請(qǐng)求。Dataserver負(fù)責(zé)數(shù)據(jù)的存儲(chǔ),并按照configserver的指示完成數(shù)據(jù)的復(fù)制和遷移工作。
數(shù)據(jù)的分布
分布式系統(tǒng)需要解決的一個(gè)重要問(wèn)題便是決定數(shù)據(jù)在集群中的分布策略,好的分布策略應(yīng)該能將數(shù)據(jù)均衡地分布到所有節(jié)點(diǎn)上,并且還應(yīng)該能適應(yīng)集群節(jié)點(diǎn)的變化。Tair采用的對(duì)照表方式較好地滿足了這兩點(diǎn)。
對(duì)照表的行數(shù)是一個(gè)固定值,這個(gè)固定值應(yīng)該遠(yuǎn)大于一個(gè)集群的物理機(jī)器數(shù),由于對(duì)照表是需要和每個(gè)使用Tair的客戶端同步的,所以不能太大,不然同步將帶來(lái)較大的開(kāi)銷。我們?cè)谏a(chǎn)環(huán)境中的行數(shù)一般為1023 。
對(duì)照表簡(jiǎn)介
下面我們看對(duì)照表是怎么完成數(shù)據(jù)的分布功能的,為了方便,我們這里假設(shè)對(duì)照表的行數(shù)為6。最簡(jiǎn)單的對(duì)照表包含兩列,第一列為hash值,第二列為負(fù)責(zé)該hash值對(duì)應(yīng)數(shù)據(jù)的dataserver節(jié)點(diǎn)信息。比如我們有兩個(gè)節(jié)點(diǎn)192.168.10.1和192.168.10.2,那么對(duì)照表類似:
0 | 192.168.10.1 |
1 | 192.168.10.2 |
2 | 192.168.10.1 |
3 | 192.168.10.2 |
4 | 192.168.10.1 |
5 | 192.168.10.2 |
當(dāng)客戶端接收到請(qǐng)求后,將key的hash值和6取模,然后根據(jù)取模后的結(jié)果查找對(duì)照表。比如取模后的值為3,客戶端將和192.168.10.2通信。
對(duì)照表如何適應(yīng)節(jié)點(diǎn)數(shù)量的變化
我們假設(shè)新增了一個(gè)節(jié)點(diǎn)——192.168.10.3,當(dāng)configserver發(fā)現(xiàn)新增的節(jié)點(diǎn)后,會(huì)重新構(gòu)建對(duì)照表。構(gòu)建依據(jù)以下兩個(gè)原則:
- 數(shù)據(jù)在新表中均衡地分布到所有節(jié)點(diǎn)上。
- 盡可能地保持現(xiàn)有的對(duì)照關(guān)系。
更新之后的對(duì)照表如下所示:
0 | 192.168.10.1 |
1 | 192.168.10.2 |
2 | 192.168.10.1 |
3 | 192.168.10.2 |
4 | 192.168.10.3 |
5 | 192.168.10.3 |
這里將原本由192.168.10.1負(fù)責(zé)的4和192.168.10.2負(fù)責(zé)的5交由新加入的節(jié)點(diǎn)192.168.10.3負(fù)責(zé)。
如果是節(jié)點(diǎn)不可用,則相當(dāng)于上述過(guò)程反過(guò)來(lái),道理是一樣的。
多備份的支持
Tair支持自定義的備份數(shù),比如你可以設(shè)置數(shù)據(jù)備份為2,以提高數(shù)據(jù)的可靠性。對(duì)照表可以很方便地支持這個(gè)特性。我們以行數(shù)為6,兩個(gè)節(jié)點(diǎn)為例,2個(gè)備份的對(duì)照表類似:
0 | 192.168.10.1 | 192.168.10.2 |
1 | 192.168.10.2 | 192.168.10.1 |
2 | 192.168.10.1 | 192.168.10.2 |
3 | 192.168.10.2 | 192.168.10.1 |
4 | 192.168.10.1 | 192.168.10.2 |
5 | 192.168.10.2 | 192.168.10.1 |
第二列為主節(jié)點(diǎn)的信息,第三列為輔節(jié)點(diǎn)信息。在Tair中,客戶端的讀寫(xiě)請(qǐng)求都是和主節(jié)點(diǎn)交互,所以如果一個(gè)節(jié)點(diǎn)不做主節(jié)點(diǎn),那么它就退化成單純的備份節(jié)點(diǎn)。因此,多備份的對(duì)照表在構(gòu)建時(shí)需要盡可能保證各個(gè)節(jié)點(diǎn)作為主節(jié)點(diǎn)的個(gè)數(shù)相近。
當(dāng)有節(jié)點(diǎn)不可用時(shí),如果是輔節(jié)點(diǎn),那么configserver會(huì)重新為其指定一個(gè)輔節(jié)點(diǎn),如果是持久化存儲(chǔ),還將復(fù)制數(shù)據(jù)到新的輔節(jié)點(diǎn)上。如果是主節(jié)點(diǎn),那么configserver首先將輔節(jié)點(diǎn)提升為主節(jié)點(diǎn),對(duì)外提供服務(wù),并指定一個(gè)新的輔節(jié)點(diǎn),確保數(shù)據(jù)的備份數(shù)。
多機(jī)架和多數(shù)據(jù)中心的支持
對(duì)照表在構(gòu)建時(shí),可以配置將數(shù)據(jù)的備份分散到不同機(jī)架或數(shù)據(jù)中心的節(jié)點(diǎn)上。Tair當(dāng)前通過(guò)設(shè)置一個(gè)IP掩碼來(lái)判斷機(jī)器所屬的機(jī)架和數(shù)據(jù)中心信息。
比如你配置備份數(shù)為3,集群的節(jié)點(diǎn)分布在兩個(gè)不同的數(shù)據(jù)中心A和B,則Tair會(huì)確保每個(gè)機(jī)房至少有一份數(shù)據(jù)。假設(shè)A數(shù)據(jù)中心包含兩份數(shù)據(jù)時(shí),Tair會(huì)盡可能將這兩份數(shù)據(jù)分布在不同機(jī)架的節(jié)點(diǎn)上。這可以減少整個(gè)數(shù)據(jù)中心或某個(gè)機(jī)架發(fā)生故障是數(shù)據(jù)丟失的風(fēng)險(xiǎn)。
輕量級(jí)的configserver
從Tair的整體架構(gòu)圖上看,configserver很類似傳統(tǒng)分布式集群中的中心節(jié)點(diǎn)。整個(gè)集群服務(wù)都依賴于configserver的正常工作。
但Tair的configserver卻是一個(gè)輕量級(jí)的中心節(jié)點(diǎn),在大部分時(shí)候,configserver不可用對(duì)集群的服務(wù)是不造成影響的。
Tair用戶和configserver的交互主要是為了獲取數(shù)據(jù)分布的對(duì)照表,當(dāng)client獲取到對(duì)照表后,會(huì)cache這張表,然后通過(guò)查這張表決定數(shù)據(jù)存儲(chǔ)的節(jié)點(diǎn),所以請(qǐng)求不需要和configserver交互,這使得Tair對(duì)外的服務(wù)不依賴configserver,所以它不是傳統(tǒng)意義上的中心節(jié)點(diǎn)。
configserver維護(hù)的對(duì)照表有一個(gè)版本號(hào),每次新生成表,該版本號(hào)都會(huì)增加。當(dāng)有數(shù)據(jù)節(jié)點(diǎn)狀態(tài)發(fā)生變化(比如新增節(jié)點(diǎn)或者有節(jié)點(diǎn)不可用了)時(shí),configserver會(huì)根據(jù)當(dāng)前可用的節(jié)點(diǎn)重新生成對(duì)照表,并通過(guò)數(shù)據(jù)節(jié)點(diǎn)的心跳,將新表同步給數(shù)據(jù)節(jié)點(diǎn)。
當(dāng)客戶端請(qǐng)求數(shù)據(jù)節(jié)點(diǎn)時(shí),數(shù)據(jù)節(jié)點(diǎn)每次都會(huì)將自己的對(duì)照表的版本號(hào)放入response中返回給客戶端,客戶端接收到response后,會(huì)將數(shù)據(jù)節(jié)點(diǎn)返回的版本號(hào)和自己的版本號(hào)比較,如果不相同,則主動(dòng)和configserver通信,請(qǐng)求新的對(duì)照表。
所以客戶端也不需要和configserver保持心跳,以便及時(shí)地更新對(duì)照表。這使得在正常的情況下,客戶端不需要和configserver通信,即使configserver不可用了,也不會(huì)對(duì)整個(gè)集群的服務(wù)造成大的影響。
僅有當(dāng)configserver不可用,此時(shí)有客戶端需要初始化,那么客戶端將取不到對(duì)照表信息,這將使得客戶端無(wú)法正常工作。
DataServer內(nèi)部結(jié)構(gòu)
DataServer負(fù)責(zé)數(shù)據(jù)的物理存儲(chǔ),并根據(jù)configserver構(gòu)建的對(duì)照表完成數(shù)據(jù)的復(fù)制和遷移工作。DataServer具備抽象的存儲(chǔ)引擎層,可以很方便地添加新存儲(chǔ)引擎。DataServer還有一個(gè)插件容器,可以動(dòng)態(tài)地加載/卸載插件。
圖 2 DataServer的內(nèi)部結(jié)構(gòu)示意圖
抽象的存儲(chǔ)引擎層
Tair的存儲(chǔ)引擎有一個(gè)抽象層,只要滿足存儲(chǔ)引擎需要的接口,便可以很方便地替換Tair底層的存儲(chǔ)引擎。比如你可以很方便地將bdb、tc甚至MySQL作為Tair的存儲(chǔ)引擎,而同時(shí)使用Tair的分布方式、同步等特性。
Tair默認(rèn)包含兩個(gè)存儲(chǔ)引擎:mdb和fdb。
mdb是一個(gè)高效的緩存存儲(chǔ)引擎,它有著和memcached類似的內(nèi)存管理方式。mdb支持使用share memory,這使得我們?cè)谥貑air數(shù)據(jù)節(jié)點(diǎn)的進(jìn)程時(shí)不會(huì)導(dǎo)致數(shù)據(jù)的丟失,從而使升級(jí)對(duì)應(yīng)用來(lái)說(shuō)更平滑,不會(huì)導(dǎo)致命中率的較大波動(dòng)。
fdb是一個(gè)簡(jiǎn)單高效的持久化存儲(chǔ)引擎,使用樹(shù)的方式根據(jù)數(shù)據(jù)key的hash值索引數(shù)據(jù),加快查找速度。索引文件和數(shù)據(jù)文件分離,盡量保持索引文件在內(nèi)存中,以便減小IO開(kāi)銷。使用空閑空間池管理被刪除的空間。
自動(dòng)的復(fù)制和遷移
為了增強(qiáng)數(shù)據(jù)的安全性,Tair支持配置數(shù)據(jù)的備份數(shù)。比如你可以配置備份數(shù)為3,則每個(gè)數(shù)據(jù)都會(huì)寫(xiě)在不同的3臺(tái)機(jī)器上。得益于抽象的存儲(chǔ)引擎層,無(wú)論是作為cache的mdb,還是持久化的fdb,都支持可配的備份數(shù)。
當(dāng)數(shù)據(jù)寫(xiě)入一個(gè)節(jié)點(diǎn)(通常我們稱其為主節(jié)點(diǎn))后,主節(jié)點(diǎn)會(huì)根據(jù)對(duì)照表自動(dòng)將數(shù)據(jù)寫(xiě)入到其他備份節(jié)點(diǎn),整個(gè)過(guò)程對(duì)用戶是透明的。
當(dāng)有新節(jié)點(diǎn)加入或者有節(jié)點(diǎn)不可用時(shí),configserver會(huì)根據(jù)當(dāng)前可用的節(jié)點(diǎn),重新build一張對(duì)照表。數(shù)據(jù)節(jié)點(diǎn)同步到新的對(duì)照表時(shí),會(huì)自動(dòng)將在新表中不由自己負(fù)責(zé)的數(shù)據(jù)遷移到新的目標(biāo)節(jié)點(diǎn)。遷移完成后,客戶端可以從configserver同步到新的對(duì)照表,完成擴(kuò)容或者容災(zāi)過(guò)程。整個(gè)過(guò)程對(duì)用戶是透明的,服務(wù)不中斷。
插件容器
Tair還內(nèi)置了一個(gè)插件容器,可以支持熱插拔插件。
插件由configserver配置,configserver會(huì)將插件配置同步給各個(gè)數(shù)據(jù)節(jié)點(diǎn),數(shù)據(jù)節(jié)點(diǎn)會(huì)負(fù)責(zé)加載/卸載相應(yīng)的插件。
插件分為request和response兩類,可以分別在request和response時(shí)執(zhí)行相應(yīng)的操作,比如在put前檢查用戶的quota信息等。
插件容器也讓Tair在功能方便具有更好的靈活性。
Tair的未來(lái)
我們將Tair開(kāi)源,希望有更多的用戶能從我們開(kāi)發(fā)的產(chǎn)品中受益,更希望依托社區(qū)的力量,使Tair有更廣闊的發(fā)展空間。
Tair開(kāi)源后,有很多用戶關(guān)心我們是否會(huì)持續(xù)維護(hù)這個(gè)項(xiàng)目。我們將Tair開(kāi)源后,淘寶內(nèi)部已經(jīng)不再有私有的Tair分支,所有的開(kāi)發(fā)和應(yīng)用都基于開(kāi)源分支。Tair在淘寶有非常廣的應(yīng)用,我們內(nèi)部有一個(gè)團(tuán)隊(duì),專門負(fù)責(zé)Tair的開(kāi)發(fā)和維護(hù),相信我們會(huì)和社區(qū)一起,將Tair越做越好。
有很多用戶在淘寶開(kāi)源平臺(tái)上申請(qǐng)加入Tair項(xiàng)目,加入項(xiàng)目在我們的開(kāi)源平臺(tái)上意味著成為項(xiàng)目的提交者,可以向代碼庫(kù)直接提交代碼。所以我們暫時(shí)還沒(méi)有批準(zhǔn)外部用戶加入,我們將在大家對(duì)Tair有更深入的了解后和社區(qū)一起決定是否批準(zhǔn)加入項(xiàng)目的申請(qǐng),在此之前,如果你有對(duì)代碼的改進(jìn),歡迎使用patch的方式提交給我們,我們將在review后決定是否合并到代碼庫(kù)。
希望我們能和社區(qū)一起,將Tair做成一個(gè)真正對(duì)大家都有幫助的項(xiàng)目。
關(guān)于作者
若海,真名余剛,淘寶網(wǎng)核心系統(tǒng)研發(fā)部工程師,Tair的主要作者之一,當(dāng)前的方向是大型分布式緩存和存儲(chǔ)解決方案。
it知識(shí)庫(kù):淘寶開(kāi)源Key/Value結(jié)構(gòu)數(shù)據(jù)存儲(chǔ)系統(tǒng)Tair技術(shù)剖析,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。