目录
干货分享,感谢您的阅读!
一、Tair的基本认识总结
阿里巴巴的Tair(Tair数据库)是一种分布式存储系统,旨在为大规模数据存储和访问提供高性能、可靠性和可扩展性的解决方案。
Tair数据库广泛应用于阿里巴巴集团内部和外部的各种业务场景,包括电子商务、支付系统、广告平台和大数据分析等。它提供了高性能、可靠性和可扩展性的数据存储解决方案,帮助企业有效管理和处理海量数据,并提供快速响应和良好的用户体验。
(一)基本特点和功能分析
Tair数据库具有以下特点和功能:
- 分布式架构:Tair采用分布式架构,将数据存储在多个节点上,以实现数据的高可用性和容错性。这使得Tair能够处理大规模数据,并提供快速的读写访问。
- 多种数据模型:Tair支持多种数据模型,包括键值(Key-Value)、列表(List)、哈希(Hash)、集合(Set)和有序集合(Sorted Set),以满足不同应用场景的需求。
- 数据持久化:Tair支持数据持久化存储,可以将数据写入磁盘以保证数据的安全性和可靠性。
- 高性能:Tair具有优化的读写性能,通过将数据分布到多个节点上并实现负载均衡,实现了高并发和低延迟的数据访问。
- 可扩展性:Tair支持水平扩展,可以根据需求增加节点以扩展存储容量和处理能力,以适应不断增长的数据量和用户访问量。
- 数据一致性:Tair通过使用一致性哈希算法和复制机制来确保数据的一致性和可用性。它采用主从复制方式,将数据复制到多个节点上,以实现容错和高可用性。
- 实时监控和管理:Tair提供了实时监控和管理工具,以便管理员可以监控和管理集群的状态、性能和健康状况,从而进行及时的故障排除和性能优化。
(二)使用场景分析
适合使用的场景
- 缓存:Tair作为高性能的分布式存储系统,可以用作缓存层,提供快速的数据访问和响应。它可以减轻后端数据库的负载,加速数据检索,并提高系统的吞吐量和响应速度。
- 会话管理:Tair可用于管理用户会话数据,如登录状态、购物车内容等。通过将会话数据存储在Tair中,可以实现会话的高可用性和分布式访问,并支持快速的会话检索和更新。
- 分布式配置存储:Tair可以作为分布式配置存储的解决方案。将配置信息存储在Tair中,可以方便地进行配置的动态管理和更新,并确保配置在分布式环境中的一致性和可用性。
- 计数器和排行榜:Tair提供了集合和有序集合等数据类型,适合用于实现计数器和排行榜功能。例如,可以使用Tair来实时统计用户的点击次数、点赞数量,并根据排行榜数据进行排序和展示。
- 队列和消息系统:Tair的列表数据类型可用于实现队列和消息系统。通过将消息存储在Tair列表中,可以实现消息的持久化和分布式处理,支持可靠的消息传递和异步处理。
- 大规模数据存储和访问:Tair的分布式架构和可扩展性使其适用于大规模数据存储和访问的场景。无论是存储海量用户数据、物联网设备数据还是大数据分析结果,Tair都可以提供高性能和可靠的存储解决方案。
需要注意的是,Tair数据库在不同场景下的具体应用可能会有所差异。在实际使用时,需要根据业务需求和性能要求进行合理的数据建模和架构设计。
不适合使用的场景
- 复杂的关系型数据:如果数据之间存在复杂的关系和复杂的查询需求,而不仅仅是简单的键值对存储,那么传统的关系型数据库(如MySQL)可能更适合。Tair更适合于简单的数据模型和快速的键值查询。
- 数据一致性要求较高的场景:尽管Tair采用了主从复制和一致性哈希等机制来确保数据的一致性,但在一些对数据一致性要求非常高的场景中,例如金融交易系统或关键业务系统,可能需要使用具备更强一致性保证的数据库系统。
- 复杂的分布式事务:如果应用程序需要进行复杂的分布式事务管理,例如跨多个数据源的事务操作和回滚,Tair的分布式事务能力可能相对有限。在这种情况下,可能需要考虑使用其他专门支持分布式事务的数据库或分布式事务管理系统。
- 存储大型多媒体文件:Tair适用于存储较小的键值数据,但不适合存储大型的多媒体文件,例如视频文件或大型图片。对于这些情况,更适合使用专门的分布式文件系统或对象存储服务。
综上所述,尽管Tair数据库在许多场景下都是一个强大的选择,但在某些特定的场景中,可能需要考虑其他类型的数据库或存储系统来满足特定需求。在选择数据库时,需要综合考虑数据模型、一致性要求、事务需求以及存储容量和性能等因素。
只从缓存和存储角度分析使用场景建议
适合tair | 不适合tair |
|
|
(三)与redis的区别
Tair和Redis都是流行的分布式存储系统,具有许多相似的特性,但也存在一些区别:
- 数据模型:Tair和Redis的最大区别之一是数据模型。Tair支持多种数据类型,包括键值、列表、哈希、集合和有序集合,提供了更丰富的数据结构。而Redis主要以键值存储为主,支持更简单的数据结构,如字符串、列表、哈希、集合和有序集合。
- 数据持久化:在数据持久化方面,Tair和Redis也有不同的方法。Tair支持数据的持久化存储,可以将数据写入磁盘以确保数据的安全性和可靠性。Redis则提供了多种数据持久化选项,包括将数据快照存储到磁盘、写入日志文件以及使用AOF(Append-Only File)日志。
- 分布式架构:Tair和Redis都支持分布式架构,将数据存储在多个节点上以实现高可用性和可扩展性。但在分布式路由和负载均衡方面,Tair采用了一致性哈希算法和复制机制,而Redis使用了基于槽(slot)的分片机制。
- 一致性和事务支持:在一致性和事务支持方面,Tair相对于Redis更加注重数据一致性和分布式事务。Tair通过主从复制和一致性哈希等机制确保数据的一致性,并提供了分布式事务的支持。Redis在一些特殊情况下可能存在数据一致性的问题,并且其事务机制是基于乐观锁(optimistic locking)实现的。
- 生态系统和扩展性:Redis拥有非常活跃和丰富的开发社区,具有大量的扩展和插件,支持多种编程语言的客户端库。它在缓存、消息队列、发布/订阅等场景中非常流行。Tair作为阿里巴巴的内部产品,更加定位于满足大规模数据存储和访问的需求,并且与阿里巴巴的其他产品和服务紧密集成。
Tair和Redis在数据模型、数据持久化、分布式架构、一致性和事务支持以及生态系统等方面存在一些区别。在选择使用哪个系统时,需要根据具体的应用需求和场景来进行评估和选择。
二、基本局限性分析
Tair数据库作为一个分布式存储系统,也有一些局限性需要考虑:
- 数据一致性:虽然Tair通过一致性哈希算法和复制机制来维护数据的一致性,但在某些特殊情况下,例如网络分区或节点故障的发生,可能会导致一段时间内的数据不一致。在需要强一致性保证的场景中,可能需要采用其他具备更强一致性保证的数据库系统。
- 数据查询能力:Tair的主要数据访问模式是基于键的查找,适合于通过键值快速检索数据。但对于复杂的查询和分析需求,Tair的查询能力相对有限。在这种情况下,可能需要使用专门为复杂查询优化的数据库系统或将Tair与其他查询引擎结合使用。
- 存储容量限制:每个Tair节点的存储容量是有限的,虽然可以通过添加更多的节点来扩展总体存储容量,但单个节点的存储容量有限制。如果需要存储非常大量的数据,可能需要考虑其他分布式存储系统或对象存储服务。
- 数据迁移和维护:由于Tair是一个分布式系统,数据迁移和维护可能会相对复杂。在添加或删除节点、数据迁移、负载均衡等操作时,需要进行合理的规划和管理,以确保数据的连续性和可用性。
- 社区支持和生态系统:相对于一些开源数据库系统,Tair的社区支持和生态系统可能相对有限。虽然Tair是阿里巴巴的内部产品,但与一些开源数据库相比,可能会有较少的开发社区和第三方工具支持。
需要注意的是,这些局限性并不意味着Tair不适用于各种场景。具体是否适合使用Tair仍取决于应用需求和具体的使用情况。在选择数据库系统时,需要综合考虑数据模型、性能要求、一致性要求、扩展性、生态系统和维护成本等因素。
三、Java中使用的基本步骤
导入Tair客户端库
根据您所使用的Tair版本和具体的客户端库,将相应的依赖项添加到您的Java项目中。例如,如果您使用的是Tair的Java客户端库,可以在Maven或Gradle配置文件中添加相应的依赖项。
创建Tair客户端实例
使用Tair客户端库提供的类和方法,创建Tair客户端实例。通常,您需要指定Tair集群的地址、端口和其他配置信息。例如:
TairManager tairManager = new DefaultTairManager();
tairManager.setConfigServerList("127.0.0.1:5180");
tairManager.init();
执行数据操作
通过Tair客户端实例,您可以执行各种数据操作,如存储键值对、获取键值对、删除键值对等。以下是一些常见的示例:
存储键值对
boolean success = tairManager.put(0, "myKey", "myValue");
获取键值对
String value = tairManager.get(0, "myKey");
删除键值对
boolean success = tairManager.delete(0, "myKey");
错误处理和异常处理
在与Tair交互的过程中,可能会出现网络故障、请求超时或其他错误。您可以使用try-catch语句捕获和处理异常,以确保代码的稳定性。例如:
try {
String value = tairManager.get(0, "myKey");
// 处理获取到的值
} catch (TairException e) {
// 处理Tair异常
} catch (Exception e) {
// 处理其他异常
}
关闭Tair客户端
在您的程序结束时,记得关闭Tair客户端,释放资源。例如:
tairManager.close();
四、实现原理分析
(一)基本架构
一个 Tair 集群主要包括3个必选模块:ConfigServer、Dataserver和 Client,一个可选模块:invalidserver。
分布式设计,结合内存+固态硬盘的混合存储引擎(数据会优先存储在SSD硬盘上,再放入内存,磁盘上含有全量数据)
一般是2台互为主备的 Configserver 及多台 DataServer,如下图所示
ConfigServer
- 通过和 Dataserver 之间的心跳检测来获取集群中存活、可用的 Dataserver 节点信息,并根据获取的 Dataserver 节点信息构建数据在集群中的分布表【路由表——bucket与dataserver的对应关系表】
- 提供数据分布表的查询服务
- 调度 Dataserver 之间的数据迁移、复制
共维护四个路由表:hash_table【原始路由表】,m_hash_table【中间状态路由表】,d_hash_table【最终路由表】,backup_hash_table【hash_table的备份】
DataServer
- 提供存储引擎,支持存储引擎扩展
- 负责数据的存储,接受并处理client的请求(put、get、remove)
- 按照 Configserver 的指示完成数据的复制和迁移工作
- 访问统计
- 插件:在接受请求的时候处理一些自定义功能,支持动态加载/卸载(插件由 configserver 配置,configserver 会将插件配置同步给各个数据节点)
dataserver持有的路由表:hash_table,d_hash_table【用于数据迁移】
client
- 提供访问 Tair 集群的API
- 更新并缓存数据分布表
- LocalCache,避免过热的数据访问影响 Tair 集群服务
- 流量控制
client持有的路由表:hash_table。
InvalidServer
- 接收来自client的invalid/hide等请求后,对属于同一组的集群(双机房独立集群部署方式)做delete/hide操作,保证同一组集群的一致。
- 集群断网之后的,脏数据清理。
- 访问统计。
(二)数据存储和读取
- 客户端初始化时从ConfigServer中拉取路由表,对要进行请求的key进行计算获得对应的虚拟节点,根据本地缓存的路由表找到虚拟节点对应的数据节点,并对其进行请求,不再与ConfigServer进行交互
- ConfigServer维护路由表时会维护一个版本号,每次新生成路由表,该版本号都会增加。当数据节点发生变化时,ConfigServer会根据数据节点的心跳,重新生成当前可用节点对应的路由表,并通过数据节点的心跳,将新表同步给数据节点
- 当客户端请求数据节点时,数据节点每次都会将自己所具有的路由表的版本号放入response中回传给客户端
- 客户端接收到数据节点的response后,会将数据节点返回的版本号与自己具有的路由表的版本号进行对比,当两者不相同时,则主动和ConfigServer通信,请求新的路由表
- 对于ldb存储引擎来说,数据put的机制是:先顺序写WAL(磁盘log文件,服务重启用于恢复memtable中的数据),再写到内存中的memtable,之后内存的memtable写满通过后台线程flush到硬盘上生成sst文件——以此实现了磁盘的顺序写,提升了写性能数据get的机制是:按照数据的写入时间,先查数据最新的memtable,其次是immutable memtable,最后按从小到大查各个level上的SST,however查多个level上的SST会涉及多次读硬盘,这个会明显降低读效率,不过Leveldb做了相应优化
(三)数据的复制和迁移
数据复制:开源Tair只有集群内的异步复制,而且复制log没有落盘机制,单个bucket的复制请求队列中挤压100个,后续的请求直接丢弃,没有保证主从副本的最终一致性
数据迁移:迁移每个桶的时候会有迁移历史数据→迁移log,最后1MB加锁阻塞写-->等待加锁后数据都写到log中-->迁移剩余log-->等待复制队列为空
Tair在迁移一个桶的最后1MB数据时需要对桶进行加锁,加完锁之后需要保障正在写的数据写入到增量log中才可以迁移。为了保障这一点Tair通过sleep 500ms来解决,那么每迁移一个桶至少需要500ms
(四)分布式架构实现
负载均衡算法
一致性Hash算法,hash(Key)% bucketCount 得到bucket【负载均衡和数据迁移的基本单位】,ConfigServer建立bucket与dataServer的路由表,指导客户端读写数据
其中,当数据节点发生变化时,ConfigServer会重新构建路由表,构建依据两个原则:
- 数据在新表中均衡地分布到所有节点上
- 尽可能地保持现有的对照关系
具体生成路由表有两种策略:一种是负载均衡优先;一种是位置安全优先
分布式处理
Configserver 负责虚拟节点的选主,同时调度 Dataserver 之间的数据迁移、复制:对于多备份的情况,Tair涉及客户端的读写请求均和主虚拟节点进行交互,从虚拟节点均作为备份。当主虚拟节点出现故障不可用时,ConfigServer会重新指定一个从虚拟节点,升级为主虚拟节点,对外提供服务,并指定一个新的从虚拟节点,以确保数据的备份数;当从虚拟节点出现故障不可用时,configserver会重新为其指定一个从虚拟节点,在持久化模式下,会将故障的节点的数据复制到新的从虚拟节点上。因此,多备份的关联表在构建时需要尽可能保证各个节点作为主节点的个数相近。
(五)系统可用性
分布式集群架构,服务端实现负载均衡,结合自动数据迁移机制,可实现服务的自动容灾,保证服务不中断
轻量化中心节点:ConfigServer存在单点故障的风险,整个集群服务都依赖于ConfigServer的正常工作,但Tair将其轻量化,在DataServer没有发生变化时,ConfigServer不可用对集群服务不会造成影响;仅当客户端需要初始化,或是DataServer发生变化时,会导致客户端无法工作或是请求数据失败
请求转发、临时路由表等保证数据迁移时的可用性
(六)系统可靠性
支持多副本,且对所有存储引擎都有效,副本个数可配
自动数据复制:当数据写入一个主节点后,主节点会根据路由表自动将数据写入到其他备份节点
(七)解决数据同步/迁移时的一致性问题
通过代理解决:对于正常的数据迁移来说,假设桶2,3,4的数据从DataServer A同步到DataServer B,其中2的数据已经迁移完成,3的数据正在迁移,4的数据还没迁移。在迁移完成前,客户端仍访问原始路由表,即访问DataServer A:当访问2中的数据时,则A会将该请求转发给B,并且将B的返回结果返回给客户端;如果是访问3中的数据,当作修改操作时,A会记录修改的log,当3迁移完成时,A会把log发送给B,在B上根据log更新3的数据,当两者数据完全一致时,3的数据迁移才算完成;当访问4时,则正常访问A即可。
当因为某台dataserver宕机导致的数据迁移时,客户端会收到ConfigServer发送过来的中间临时状态的路由表,表中会把宕机的DataServer所负责的bucket临时指派给具有其备份副本的DataServer来处理,此时,服务保持可用,但负载可能不均衡,当迁移完成后,才能重新达到一个新的负载均衡的状态
(八)系统可扩展性
数据自动迁移:当有新节点加入或者有节点不可用时,数据节点会根据Configserver新生成的路由表,自动将在新表中不由自己负责的数据迁移到新的目标主节点中。迁移完成后,客户端可以从 configserver 同步到新的对照表,完成扩容或者容灾过程,具体的迁移过程如下:
ConfigServer维护hash_table【原始路由表】,m_hash_table【中间状态路由表】,d_hash_table【最终路由表】三张表,DataServer通过心跳获取到hash_table和d_hash_table,根据hash_table和d_hash_table的差异构建迁移任务,并按照d_hash_table进行数据迁移,每迁移完成一个桶,DataServer就会向ConfigServer更新状态,更新m_hash_table,当m_hash_table和d_hash_table完全一致,表示迁移完成
(九)处理热点数据
解决方案分为三部分:热点识别、读热点方案和写热点方案。
其中读写热点方案都是以服务端能对热点访问进行精准的识别为前提的。另外对于可以提前预知热点Key的情况,也提供相应的客户端API以支持特定数据Key或者特定Namespace的所有数据Key预先标记为热点Key的能力。
DataServer上的热点统计过程
DataServer收到客户端的请求后,由每个具体处理请求的工作线程(Worker Thread)进行请求的统计。工作线程用来统计热点的数据结构均为ThreadLocal模式的数据结构,完全无锁化设计。热点识别算法使用精心设计的多级加权LRU链和HashMap组合的数据结构,在保证服务端请求处理效率的前提下进行请求的全统计,支持QPS热点和流量热点(即请求的QPS不大但是数据本身过大而造成的大流量所形成的热点)的精准识别。每个采样周期结束时,工作线程会将统计的数据结构转交到后台的统计线程池进行分析处理。统计工作异步在后台进行,不抢占正常的数据请求的处理资源。
读热点方案
服务端设计
原始Tair的数据访问方式是先进行Hash(Key)%BucketCount的计算,得出具体的数据存储Bucket,再检索数据路由表找到该Bucket所在的DataServer后对其进行读写请求的。所以相同Key的读写请求必然落在固定的DataServer上,且无法通过水平扩展DataServer数量来解决。
本方案通过在DataServer上划分一块HotZone存储区域的方式来解决热点数据的访问。该区域存储当前产生的所有读热点的数据,由客户端配置的缓存访问逻辑来处理各级缓存的访问。多级缓存架构如下:
所有DataServer的HotZone存储区域之间没有权重关系,每个HotZone都存储相同的读热点数据。客户端对热点数据Key的请求会随机到任意一台DataServer的HotZone区域,这样单点的热点请求就被散列到多个节点乃至整个集群。
客户端设计
当客户端在第一次请求前初始化时,会获取整个Tair集群的节点信息以及完整的数据路由表,同时也会获取配置的热点散列机器数(即客户端访问的HotZone的节点范围)。随后客户端随机选择一个HotZone区域作为自身固定的读写HotZone区域。在DataServer数量和散列机器数配置未发生变化的情况下,不会改变选择。即每个客户端只访问唯一的HotZone区域。
客户端收到服务端反馈的热点Key信息后,至少在客户端生效N秒。在热点Key生效期间,当客户端访问到该Key时,热点的数据会首先尝试从HotZone节点进行访问,此时HotZone节点和源数据DataServer节点形成一个二级的Cache模型。客户端内部包含了两级Cache的处理逻辑,即对于热点数据,客户端首先请求HotZone节点,如果数据不存在,则继续请求源数据节点,获取数据后异步将数据存储到HotZone节点里。使用Tair客户端的应用常规调用获取数据的接口即可,整个热点的反馈、识别以及对多级缓存的访问对外部完全透明。HotZone缓存数据的一致性由客户端初始化时设置的过期时间来保证,具体的时间由具体业务对缓存数据不一致的最大容忍时间来决定。
客户端存储于本地的热点反馈过期后,数据Key会到源DataServer节点读取。如果该Key依旧在服务端处于热点状态,客户端会再次收到热点反馈包。因为所有客户端存储于本地的热点反馈信息的失效节奏不同,所以不会出现同一瞬间所有的请求都回源的情况。即使所有请求回源,也仅需要回源读取一次即可,最大的读取次数仅为应用机器数。若回源后发现该Key已不是热点,客户端便回到常规的访问模式。
写热点方案
服务端设计
对于写热点,因为一致性的问题,难以使用多级缓存的方式来解决。如果采用写本地Cache,再异步更新源DataServer的方案。那么在Cache写入但尚未更新的时候,如果业务机器宕机,就会有已写数据丢失的问题。同时,本地 Cache会导致进行数据更新的某应用机器当前更新周期内的修改对其他应用机器不可见,从而延长数据不一致的时间。故多级Cache的方案无法支持写热点。最终写热点采用在服务端进行请求合并的方式进行处理。
热点Key的写请求在IO线程被分发到专门的热点合并线程处理,该线程根据Key对写请求进行一定时间内的合并,随后由定时线程按照预设的合并周期将合并后的请求提交到引擎层。合并过程中请求结果暂时不返回给客户端,等请求合并写入引擎成功后统一返回。这样做不会有一致性的问题,不会出现写成功后却读到旧数据,也避免了LDB集群返回成功,数据并未落盘的情况(假写)。具体的合并周期在服务端可配置,并支持动态修改生效。
客户端设计
写热点的方案对客户端完全透明,不需要客户端做任何修改。
参考文献链接
- "Tair: An Efficient Cache for Web Applications" by Xianghua Lv et al. (ACM Transactions on Internet Technology): https://dl.acm.org/doi/10.1145/320974.320975
- "A Brief Introduction to Alibaba Tair" by Alibaba Cloud: PostgreSQL Feed Systems Similar to Weibo - Design and Performance Metrics - Alibaba Cloud Community
- "Tair: An Open Source Data Storage and Management System" by Wang Yifan et al. (Alibaba Group Technical Committee): https://www.usenix.org/system/files/conference/hotstorage15/hotstorage15-paper-yifan.pdf
- "Tair: A High-Performance Key-Value Storage System" by Alibaba Cloud: Windows Networking Troubleshooting 6: The Mystery of Disappearing IP Addresses - Alibaba Cloud Community
- "Tair: The Distributed Key-Value Storage System" by Alibaba Cloud: Migrating an Existing WordPress Blog to Alibaba Cloud - Alibaba Cloud Community
- "Tair: A Distributed Cache System from Alibaba" by Lin Dong et al. (IEEE): Preface of the 17th FRUCT Conference Proceeding | IEEE Conference Publication | IEEE Xplore
- "TairCache: Optimizing Data Placement for High Performance Key-Value Stores in Multi-Tenant Clouds" by Xiaoyang Li et al. (IEEE Transactions on Parallel and Distributed Systems): Digital Library Recommender System on Hadoop | IEEE Conference Publication | IEEE Xplore
- "Tair: The Next Generation Key-Value Store System" by Alibaba Cloud: PostgreSQL Graph Search Practices - 10 Billion-Scale Graph with Millisecond Response - Alibaba Cloud Community
- "Tair: A Highly Available Key-Value Storage System" by Yun Chen et al. (IEEE International Conference on Cloud Computing): New Opportunistic Interference Alignment Schemes in MIMO Interfering Broadcast Channels | IEEE Conference Publication | IEEE Xplore
- "Tair: An Efficient Cache Storage System in Alibaba" by Dong Lin et al. (International Journal of Digital Multimedia Broadcasting): https://www.hindawi.com/journals/ijdmb/2015/193595/
- "A Study of Tair and Its Performance Evaluation" by Chongbo Zhang et al. (International Journal of Distributed Sensor Networks): https://journals.sagepub.com/doi/10.1155/2015/215953
- 分布式缓存服务Tair的热点数据散列机制|Linux 中国◆开源社区