Tair是淘寶的一個開源項目,它是一個分佈式的key/value結構數據的解決方案。算法
做爲一個分佈式系統,Tair由一箇中心控制節點(config server)和一系列的服務節點(data server)組成,緩存
config server 負責管理全部的data server,並維護data server的狀態信息;爲了保證高可用(High Available),config server可經過hearbeat 以一主一備形式提供服務安全
client 和 config server的交互主要是爲了獲取數據分佈的對照表,當client啓動時獲取到對照表後,會cache這張表,而後經過查這張表決定數據存儲的節點,因此請求不須要和config server交互,這使得Tair對外的服務不依賴configserver,因此它不是傳統意義上的中心節點,也並不會成爲集羣的瓶頸。併發
config server維護的對照表有一個版本號,每次新生成表,該版本號都會增長。當有data server狀態發生變化(好比新增節點或者有節點不可用了)時,configserver會根據當前可用的節點從新生成對照表,並經過數據節點的心跳,將新表同步給data server。當client請求data server時,後者每次都會將本身的對照表的版本號放入response中返回給客client,client接收到response後,會將data server返回的版本號和本身的版本號比較,若是不相同,則主動和config server通訊,請求新的對照表。負載均衡
這使得在正常的狀況下,client不須要和configserver通訊,即便config server不可用了,也不會對整個集羣的服務形成大的影響。有了config server,client不須要配置data server列表,也不須要處理節點的的狀態變化,這使得Tair對最終用戶來講使用和配置都很簡單。分佈式
data server 對外提供各類數據服務,並以心跳的形式將自身情況彙報給config server;全部的 data server 地位都是等價的。ui
tair 分爲持久化和非持久化兩種使用方式:spa
對於全部的key,分到Q個桶中,桶是負載均衡和數據遷移的基本單位。config server 根據必定的策略把每一個桶指派到不一樣的data server上,由於數據按照key作hash算法,因此能夠認爲每一個桶中的數據基本是平衡的,保證了桶分佈的均衡性, 就保證了數據分佈的均衡性。插件
具體說,首先計算Hash(key),獲得key所對應的bucket,而後再去config server查找該bucket對應的data server,再與相應的data server進行通訊。也就是說,config server維護了一張由bucket映射到data server的對照表,好比:code
bucket data server
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
這裏共6個bucket,由兩臺機器負責,每臺機器負責3個bucket。客戶端將key hash後,對6取模,找到負責的數據節點,而後和其直接通訊。表的大小(行數)一般會遠大於集羣的節點數,這和consistent hash中的虛擬節點很類似。
假設咱們加入了一臺新的機器——192.168.10.3,Tair會自動調整對照表,將部分bucket交由新的節點負責,好比新的表極可能相似下表:
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
在老的表中,每一個節點負責3個桶,當擴容後,每一個節點將負責2個桶,數據被均衡的分佈到全部節點上。
爲了加強數據的安全性,Tair支持配置數據的備份數(COPY_COUNT)。好比你能夠配置備份數爲3,則每一個bucket都會寫在不一樣的3臺機器上。當數據寫入一個節點(一般咱們稱其爲主節點)後,主節點會根據對照表自動將數據寫入到其餘備份節點,整個過程對用戶是透明的。
若是有多個備份,那麼對照表將包含多列,好比備份是爲3,則表有4列,後面的3列都是數據存儲的節點。
當有新節點加入或者有節點不可用時,config server會根據當前可用的節點,從新build一張對照表。數據節點同步到新的對照表時,會自動將在新表中不禁本身負責的數據遷移到新的目標節點。遷移完成後,客戶端能夠從config server同步到新的對照表,完成擴容或者容災過程。整個過程對用戶是透明的,服務不中斷。
當系統增長data server的時候,config server根據負載,協調data server將他們控制的部分桶遷移到新的data server上,遷移完成後調整路由。
注意:
不論是發生故障仍是擴容,每次路由的變動,config server都會將新的配置信息推給data server。在client訪問data server的時候,會發送client緩存的路由表的版本號,若是data server發現client的版本號過舊,則會通知client去config server取一次新的路由表。若是client訪問某臺data server 發生了不可達的狀況(該 data server可能宕機了),客戶端會主動去config server取新的路由表。
當發生遷移的時候,假設data server A 要把 桶 3,4,5 遷移給data server B。由於遷移完成前,client的路由表沒有變化,所以對 3, 4, 5 的訪問請求都會路由到A。如今假設 3還沒遷移,4 正在遷移中,5已經遷移完成,那麼:
位置優先策略還有一個問題,假如只有兩個機房,機房1中有100臺data server,機房2中只有1臺data server。這個時候,機房2中data server的壓力必然會很是大,因而這裏產生了一個控制參數 _build_diff_ratio(參見安裝部署文檔),當機房差別比率大於這個配置值時,config server也再也不build新表,機房差別比率是如何計出來的呢?首先找到機器最多的機房,不妨設使RA,data server數量是SA,那麼其他的data server的數量記作SB,則機房差別比率=|SA – SB|/SA,由於通常咱們線上系統配置的COPY_COUNT=3,在這個狀況下,不妨設只有兩個機房RA和RB,那麼兩個機房什麼樣的data server數量是均衡的範圍呢? 當差別比率小於 0.5的時候是能夠作到各臺data server負載都徹底均衡的。這裏有一點要注意,假設RA機房有機器6臺,RB有機器3臺,那麼差別比率 = 6 – 3 / 6 = 0.5,這個時候若是進行擴容,在機房A增長一臺data server,擴容後的差別比率 = 7 – 3 / 7 = 0.57,也就是說,只在機器數多的機房增長data server會擴大差別比率。若是咱們的_build_diff_ratio配置值是0.5,那麼進行這種擴容後,config server會拒絕再繼續build新表。
Tair中的每一個數據都包含版本號,版本號在每次更新後都會遞增。這個特性能夠幫助防止數據的併發更新致使的問題。
Version改變的邏輯以下:
version分佈式鎖
Tair中存在該key,則認爲該key所表明的鎖已被lock;不存在該key,在未加鎖。操做過程和上面類似。業務方能夠在put的時候增長expire,已避免該鎖被長期鎖住。
固然業務方在選擇這種策略的狀況下須要考慮並處理Tair宕機帶來的鎖丟失的狀況。
Tair還內置了一個插件容器,能夠支持熱插拔插件。
插件由config server配置,config server會將插件配置同步給各個數據節點,數據節點會負責加載/卸載相應的插件。
插件分爲request和response兩類,能夠分別在request和response時執行相應的操做,好比在put前檢查用戶的quota信息等。
插件容器也讓Tair在功能方便具備更好的靈活性。