Tair的內部結構
圖 1 Tair整體架構圖
一個Tair集羣主要包括client、configserver和dataserver 3個模塊。Configserver通過和dataserver的心跳(HeartBeat)維護集羣中可用的節點,並根據可用的節點,構建數據的在集羣中的分佈信息(見下文的對照表)。Client在初始化時,從configserver處獲取數據的分佈信息,根據分佈信息和相應的dataserver交互完成用戶的請求。Dataserver負責數據的存儲,並按照configserver的指示完成數據的複製和遷移工作。
數據的分佈
分佈式系統需要解決的一個重要問題便是決定數據在集羣中的分佈策略,好的分佈策略應該能將數據均衡地分佈到所有節點上,並且還應該能適應集羣節點的變化。Tair採用的對照表方式較好地滿足了這兩點。
對照表的行數是一個固定值,這個固定值應該遠大於一個集羣的物理機器數,由於對照表是需要和每個使用Tair的客戶端同步的,所以不能太大,不然同步將帶來較大的開銷。我們在生產環境中的行數一般爲1023 。
對照表簡介
下面我們看對照表是怎麼完成數據的分佈功能的,爲了方便,我們這裏假設對照表的行數爲6。最簡單的對照表包含兩列,第一列爲hash值,第二列爲負責該hash值對應數據的dataserver節點信息。比如我們有兩個節點192.168.10.1和192.168.10.2,那麼對照表類似:
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 |
當客戶端接收到請求後,將key的hash值和6取模,然後根據取模後的結果查找對照表。比如取模後的值爲3,客戶端將和192.168.10.2通信。
對照表如何適應節點數量的變化
我們假設新增了一個節點——192.168.10.3,當configserver發現新增的節點後,會重新構建對照表。構建依據以下兩個原則:
1. 數據在新表中均衡地分佈到所有節點上。
2. 儘可能地保持現有的對照關係。
更新之後的對照表如下所示:
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負責的4和192.168.10.2負責的5交由新加入的節點192.168.10.3負責。
如果是節點不可用,則相當於上述過程反過來,道理是一樣的。
多備份的支持
Tair支持自定義的備份數,比如你可以設置數據備份爲2,以提高數據的可靠性。對照表可以很方便地支持這個特性。我們以行數爲6,兩個節點爲例,2個備份的對照表類似:
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 |
第二列爲主節點的信息,第三列爲輔節點信息。在Tair中,客戶端的讀寫請求都是和主節點交互,所以如果一個節點不做主節點,那麼它就退化成單純的備份節點。因此,多備份的對照表在構建時需要儘可能保證各個節點作爲主節點的個數相近。
當有節點不可用時,如果是輔節點,那麼configserver會重新爲其指定一個輔節點,如果是持久化存儲,還將複製數據到新的輔節點上。如果是主節點,那麼configserver首先將輔節點提升爲主節點,對外提供服務,並指定一個新的輔節點,確保數據的備份數。
多機架和多數據中心的支持
對照表在構建時,可以配置將數據的備份分散到不同機架或數據中心的節點上。Tair當前通過設置一個IP掩碼來判斷機器所屬的機架和數據中心信息。
比如你配置備份數爲3,集羣的節點分佈在兩個不同的數據中心A和B,則Tair會確保每個機房至少有一份數據。假設A數據中心包含兩份數據時,Tair會儘可能將這兩份數據分佈在不同機架的節點上。這可以減少整個數據中心或某個機架發生故障是數據丟失的風險。
輕量級的configserver
從Tair的整體架構圖上看,configserver很類似傳統分佈式集羣中的中心節點。整個集羣服務都依賴於configserver的正常工作。
但Tair的configserver卻是一個輕量級的中心節點,在大部分時候,configserver不可用對集羣的服務是不造成影響的。
Tair用戶和configserver的交互主要是爲了獲取數據分佈的對照表,當client獲取到對照表後,會cache這張表,然後通過查這張表決定數據存儲的節點,所以請求不需要和configserver交互,這使得Tair對外的服務不依賴configserver,所以它不是傳統意義上的中心節點。
configserver維護的對照表有一個版本號,每次新生成表,該版本號都會增加。當有數據節點狀態發生變化(比如新增節點或者有節點不可用了)時,configserver會根據當前可用的節點重新生成對照表,並通過數據節點的心跳,將新表同步給數據節點。
當客戶端請求數據節點時,數據節點每次都會將自己的對照表的版本號放入response中返回給客戶端,客戶端接收到response後,會將數據節點返回的版本號和自己的版本號比較,如果不相同,則主動和configserver通信,請求新的對照表。
所以客戶端也不需要和configserver保持心跳,以便及時地更新對照表。這使得在正常的情況下,客戶端不需要和configserver通信,即使configserver不可用了,也不會對整個集羣的服務造成大的影響。
僅有當configserver不可用,此時有客戶端需要初始化,那麼客戶端將取不到對照表信息,這將使得客戶端無法正常工作。
DataServer內部結構
DataServer負責數據的物理存儲,並根據configserver構建的對照表完成數據的複製和遷移工作。DataServer具備抽象的存儲引擎層,可以很方便地添加新存儲引擎。DataServer還有一個插件容器,可以動態地加載/卸載插件。
圖 2 DataServer的內部結構示意圖
抽象的存儲引擎層
Tair的存儲引擎有一個抽象層,只要滿足存儲引擎需要的接口,便可以很方便地替換Tair底層的存儲引擎。比如你可以很方便地將bdb、tc甚至MySQL作爲Tair的存儲引擎,而同時使用Tair的分佈方式、同步等特性。
Tair默認包含兩個存儲引擎:mdb和fdb。
mdb是一個高效的緩存存儲引擎,它有着和memcached類似的內存管理方式。mdb支持使用share memory,這使得我們在重啓Tair數據節點的進程時不會導致數據的丟失,從而使升級對應用來說更平滑,不會導致命中率的較大波動。
fdb是一個簡單高效的持久化存儲引擎,使用樹的方式根據數據key的hash值索引數據,加快查找速度。索引文件和數據文件分離,儘量保持索引文件在內存中,以便減小IO開銷。使用空閒空間池管理被刪除的空間。
自動的複製和遷移
爲了增強數據的安全性,Tair支持配置數據的備份數。比如你可以配置備份數爲3,則每個數據都會寫在不同的3臺機器上。得益於抽象的存儲引擎層,無論是作爲cache的mdb,還是持久化的fdb,都支持可配的備份數。
當數據寫入一個節點(通常我們稱其爲主節點)後,主節點會根據對照表自動將數據寫入到其他備份節點,整個過程對用戶是透明的。
當有新節點加入或者有節點不可用時,configserver會根據當前可用的節點,重新build一張對照表。數據節點同步到新的對照表時,會自動將在新表中不由自己負責的數據遷移到新的目標節點。遷移完成後,客戶端可以從configserver同步到新的對照表,完成擴容或者容災過程。整個過程對用戶是透明的,服務不中斷。
插件容器
Tair還內置了一個插件容器,可以支持熱插拔插件。
插件由configserver配置,configserver會將插件配置同步給各個數據節點,數據節點會負責加載/卸載相應的插件。
插件分爲request和response兩類,可以分別在request和response時執行相應的操作,比如在put前檢查用戶的quota信息等。
插件容器也讓Tair在功能方便具有更好的靈活性。