tair是淘宝在2010年开源的分布式k-v缓存/存储系统,主要支持以下四种引擎:
mdb:类似memcahe
rdb:采用redis中的存储结构,支持k/v,list,hash,set等
ldb:leveldb
kdb:Kyoto Cabinet
tair可以让我们更方便的使用这些kv数据库。其中mdb,rdb是分布式缓存,ldb,kdb是分布式存储。
tair支持version
每个数据中包含一个version信息,可以保证数据都是基于最新的数据进行更新。
比如有数据“1,2,3”,A和B同时获取到这个数据进行更新,如果使用redis可能需要考虑分布式锁来保证更新的准确性,在tair中可以使用version。A获取到的数据版本为10,更新之后版本为11,B在更新数据时,服务器判定版本不是最新,会拒绝更新,此时B可以get最新的数据进行更新,或强制更新。
使用场景
缓存(mdb,rdb)
数据可以以key/value的形式存储
数据可以接受丢失
访问速度要求很高
单个数据大小不是很大,一般在KB级别
数据量很大,并且有较大的增长可能性
数据更新不频繁
持久化(ldb,kdb)
数据可以以key/value的形式存储
数据需要持久化
单个数据大小不是很大,一般在KB级别
数据量很大,并且有较大的增长可能性
数据的读写比例较高
tair主要由client,configServer,dataServer三部分组成。 configServer类似于配置中心,记录集群的meta信息,dataServer则是真是的数据存储节点
CS中维护了一个对照表,存储数据桶和服务节点的关系。key的hash和桶长度取模,决定数据存储到哪个桶。比如现在有两个DS节点,172.11.12.1,172.11.12.2,设置桶大小为6,映射表关系如下
0 172.11.12.1
1 172.11.12.2
2 172.11.12.1
3 172.11.12.2
4 172.11.12.1
5 172.11.12.2
数据(1,q),(11,w),(2,e)分别存到了1,5,2号桶,也就是节点172.11.12.2存两条记录,172.11.12.1存一条记录。
tair支持自定义备份数量,备份数量不同,CS中的映射表也会有差别。备份数量为2,第一列还是hash值,第二列是主节点,第三列为备份节点。客户端都是直接和主节点进行交互。当辅节点不可用,CS会再指定一个新的辅节点,主节点不可以,会讲辅节点升级为主,同时再指定一个辅节点
0 172.11.12.1 172.11.12.2
1 172.11.12.2 172.11.12.1
2 172.11.12.1 172.11.12.2
3 172.11.12.2 172.11.12.1
4 172.11.12.1 172.11.12.2
5 172.11.12.2 172.11.12.1
当有节点变化,当configserver发现新增的节点后,会重新构建对照表。构建依据以下两个原则:
数据在新表中均衡地分布到所有节点上。
尽可能地保持现有的对照关系。
在tair中,CS和一般的控制中心不太一样,CS在首次将配置下发到客户端后,客户端会缓存一份配置,直至下一次配置发生变化,再去CS中拉配置,所以在配置无变化时,即使CS挂掉,也不会影响服务。CS会把对照表的版本信息下发到dataServer,客户端读数据时会将自己持有的CS版本号带过去,dataServer如果判断版本不一致,会通知客户端从新获取配置。
dataServer(以下称DS)DS 对外提供各种数据服务,并以心跳的形式将自身状况汇报给configServer;所有的DS地位都是等价的。
当有某台DS故障不可用的时候, configServer负责重新计算一张新的分布表, 将原来由故障机器服务的桶的访问重新指派到其它的DS中. 这个时候, 可能会发生数据的迁移. 比如原来由A负责的桶, 在新表中需要由B负责. 而B上并没有该桶的数据, 那么就将数据迁移到B上来. 同时configServer会发现哪些桶的备份数目减少了, 然后根据负载情况在负载较低的DS上增加这些桶的备份. 当系统增加DS的时候, configServer根据负载, 协调DS将他们控制的部分桶迁移到新的DS上. 迁移完成后调整路由. 当然, 系统中可能出现减少了某些DS同时增加另外的一些DS. 处理原理同上. 每次路由的变更, configServer都会将新的配置信息推给DS. 在客户端访问DS的时候, 会发送客户端缓存的路由表的版本号. 如果DS发现客户端的版本号过旧, 则会通知客户端去configServer取一次新的路由表. 如果客户端访问某台DS 发生了不可达的情况(该 DS可能宕机了), 客户端会主动去configServer取新的路由表.
当迁移发生的时候, 我们举个例子, 假设DS A要把 桶 3,4,5 迁移给DS B. 因为迁移完成前, 客户端的路由表没有变化, 客户端对3, 4, 5 的访问请求都会路由到A. 现在假设3还没迁移, 4正在迁移中, 5已经迁移完成. 那么对3的访问, 跟以前一样. 对5的访问, 则A会把该请求转发给B,并且将B的返回结果返回给客户, 对4的访问, 在A处理, 同时如果是对4的修改操作, 会记录修改log.当桶4迁移完成的时候, 还要把log发送到B, 在B上应用这些log. 最终A B上对于桶4来说, 数据完全一致才是真正的迁移完成. 当然, 如果是因为某DS宕机而引发的迁移, 客户端会收到一张中间临时状态的分配表. 这张表中, 把宕机的DS所负责的桶临时指派给有其备份DS来处理. 这个时候, 服务是可用的, 但是负载可能不均衡. 当迁移完成之后, 才能重新达到一个新的负载均衡的状态.
Tair和RedisCluster都是集群模式,Redis是单机缓存系统,所以在应用场景中,更多的是对Tair和RedisCluster进行对比,看哪一个更适合。
| Redis | RedisCluster | Tair | |
|---|---|---|---|
| 支持Value大小 | 理论上不超过1GB(建议不超过1MB) | 理论上不超过1GB(建议不超过1MB) | 256M |
| 支持Value结构 | byte[]/list map/set/string | byte[]/list map/set/string | (1)kv/map/list (2)支持big_list(list无长度限制) (3)支持创建schema,cmd query |
| 支持的总数据量 | 1000+instance | 理论上总数据量无限制 | |
| 适宜的读写比 | 存内存型,均适合 | 存内存型,均适合 | 支持多引擎,适宜各种比例的读写。读多写少(mdb+leveldb),读少写多(leveldb) |
| 数据是否可改写 | Y | Y | Y |
| 是否支持Scan/Range Query | 不支持,并且不支持merge operations | 支持Scan/Range Query | |
| CAP | CP | 用户可配置,CP或AP | |
| 数据自动过期 | 支持 | 支持 | 支持 |



