缓存之Tair

介绍

​ 在Tair出现之前的很长一段时间里,像redis、memcache这些知名NoSql数据库是不支持分布式的,在这样的背景下,由淘宝网自主开发并在2010.6开源的一个高性能、高扩展、高可靠分布式缓存,类似map的key/value结构,在淘宝、天猫等各个应用中广泛应用。

​ Tair官网:https://www.oschina.net/p/tair
​ gitee地址:https://gitee.com/mirrors/Tair
​ github wiki地址:https://github.com/alibaba/tair/wiki

概念

  • configID:一个Tair集群的唯一标识
  • namespace:应用的一个内存或者持久化存储区域,0到65535之间的一个数字
  • quta:配额,对应了每个 namespace 储存区的大小限制,超过配额后将使用LRU(最少使用)策略淘汰
  • expireTime:数据的过期时间。当超过过期时间之后,数据将对应用不可见,不同的存储引擎有不同的策略清理掉过期的数据
  • prefix:前缀处理,保证了拥有相同前缀的key根据哈希算法后,分散在同一个dataserver上,提高了处理速度。

特性

​ Tair实现了集群部署,特性都是一些集群的特性,容错、解决单点故障、跨机房管理、多集群管理、支持副本等。Tair的特性有:
​ • Namespace
​ • Expire
​ • Prefix
​ • List,zset,hash,set
​ • LocalCache
​ • FlowControl
抽象存储层,内部采用MDB、RDB、LDB三中存储引擎满足了各种存储需求。
​ MDB是内存型,K/V结构,底层是memcache ,由于是内存型性能最高但是不支持持久化。
​ RDB底层是redis引擎,支持List、Set、Zset、Map、String等多种数据结构,性能略低于MDB。
​ LDB是持久化型引擎,底层是google的levelDB,K/V结构,性能最低,但是可靠性最高。

应用场景

​ 由于Tair底层的MDB、RDB、LDB三种引擎支持,既能作为缓存使用又可以作为持久化存储数据库,命令除了put、get、delete以及批量接口外,还有一些附加的实用功能比如version支持、原子计数器、item支持,可以用于实现分布式锁,队列等。

Tair与其他缓存对比

TairRedisMemcacheEhcache
是否开源开源开源开源开源
使用语言服务器端C++;客户端支持C、JAVA、PHP等ANSI C语言编写 ,提供多种语言(C/C++/JAVA/PHP等)的API服务端C,客户端支持c、php、java、python等java
集群支持3.0以后支持服务端不支持,客户端使用一致性hash算法将数据分布式存储支持,默认是异步同步
容灾支持3.0以后支持可通过客户端实现支持
高可用支持3.0以后支持不支持,可通过第三方应用比如magent实现支持
动态扩展支持3.0以后支持可通过客户端实现支持,本地存储在.data和.index文件
效率LDB < RDB < MDB高于redis高于memcache
持久化LDB、RDB引擎支持支持(AOF、默认RDB)不支持,可通过第三方应用实现支持
缓存过期失效策略支持支持支持,lru算法支持,LRU(默认),FIFO,LFU
数据结构K/V、list、hash、set、sortedsort等K/V、list、hash、set、sortedsort五种数据结构支持简单的K/V结构支持简单的K/V结构
分布式支持3.0以后支持客户端使用一致性hash做分布式支持
跨机房管理支持不支持不支持不支持
多集群管理支持不支持不支持不支持
使用状况只有阿里内部大规模使用普遍使用使用情况较多多用于hibernate的缓存实现
缺点文档不全,社区不活跃,单节点上性能没有redis高,不能对key实现模糊查询,单条数据不能太大key建议1k以下,value不能超过1M,建议10k以下3.0以前不支持集群,单线程无法充分利用多核服务器CPU,事务支持较弱,rdb每次都是写全量数据,成本高,aof追加导致log特别大结构单一,数据在内存重启会丢失,数据大小受内存限制结构单一、只适用于java体系,只能用java编写客户端,且使用磁盘做cache时占空间
优点采用分布式集群架构,具备自动容灾及故障迁移能力,对存储层做了抽象,底层方便切换不同的存储引擎,采用一致性哈希算法将key分散在Q个桶中,并将桶放到不同的dataserver上,保证数据平衡,tair高可用比较强,容灾性比redis强,支持多种集群结构,支持跨机房数据分布非常丰富的数据结构而且都是原子性操作、高速读写、支持事务,支持aof、rdb两种持久化机制,拥有丰富特性,订阅发布 Pub / Sub 功能、Key 过期策略、事务、支持多个 DB、计数、支持集群和数据备份简洁,灵活,多线程非阻塞io效率高,所有支持多种语言api,且在并发下用cas保证一致性效率高,功能强大,版本迭代特别快、缓存策略支持多种,可以通过rmi可插入api实现分布式缓存、具备缓存监听、支持多缓存实例、提供hibernate的缓存实现、支持非持久化和持久化缓存数据

Tair安装部署

虚拟机环境准备

连接方式:

NAT“ :

​ 网络地址转换(NAT)和 NAT网络 一个意思 ,全称Network Address Translation借助网络地址转换功能,通过宿主机所在的网络实现访问互联网。也是默认网络连接模式,虚拟机在外部网络中没有自己的IP地址,宿主机无法ping通虚拟机,虚拟机彼此间也不通,可访问外部网络。
​ 优点:轻松实现上网,不占用网段中的IP地址。
​ 缺点:宿主机不能访问虚拟机,同网段中的主机无法找到虚拟机

桥接网卡”:

​ 虚拟机有独立的IP,虚拟机和宿主机处于同一网段,真实存在于网络中,像是一台真实的主机,虚拟机和宿主机彼此互通,且网络中的其他主机也可以互通,主机需要有网络或接入到路由器,才能与虚拟机通信,虚拟机才可访问外网。
​ 优点:可以轻松实现上网,同网段中的主机任意互通。
​ 缺点:占用网段中的IP地址。

仅主机(Host-Only )网络“:

​ 是一种比较复杂的模式。是在主机中模拟的虚拟网卡,所有虚拟机连接这张虚拟网卡上,虚拟机和虚拟机之间处于一个网段默认可以相互访问,虚拟机和主机默认不能互相访问,但是可以通过配置这张虚拟网卡实现,互相访问和上网等功能

内部网络”:

​ 内部网络模式,虚拟机与外网完全断开,只实现虚拟机于虚拟机之间的内部网络模式。 虚拟机和主机不能相互访问,不属于同一网络,虚拟机和虚拟机之间可以相互访问。

NATBridged Adapter桥接Internal内部网络Host-only Adapter仅主机
虚拟机访问主机×默认不行,需配置
主机访问虚拟机××默认不行,需配置
虚拟机访问其他主机×默认不行,需配置
其他主机访问虚拟机××默认不行,需配置
虚拟机之间×默认√

安装相关依赖库

[root@test ~]# yum install -y gcc gcc-c++ make m4 libtool boost-devel zlib-devel openssl-devel libcurl-devel
yum:是yellowdog updater modified 的缩写,Linux中的包管理工具
gcc:一开始称为GNU C Compiler,也就是一个C编译器,后来因为这个项目里集成了更多其他不同语言的编译器,所以就不再只是C编译器,而称为GNU编译器套件(GCC,GNU Compiler Collection),表示一堆编译器的合集
gcc-c++则是GCC编译器合集里的C++编译器。
make是gcc的编译器,m4:是一个宏处理器.将输入拷贝到输出,用来引用文件,执行命令,整数运算,文本操作,循环等.既可以作为编译器的 前端,也可以单独作为一个宏处理器.
libtool:是一个通用库支持脚本,作用是在编译大型软件的过程中解决了库的依赖问题;将繁重的库依赖关系的维护工作承担下来,提供统一的接口,隐藏了不同平台间库的名称的差异等。安装libtool会自动安装所依赖的automake和autoconfig, autoconf:是用来生成自动配置软件源代码脚本(configure)的工具.configure脚本能独立于autoconf运行, automake:会根据源码中的Makefile.am来自动生成Makefile.in文件,Makefile.am中定义了宏和目标,运行automake命令会生成Makefile文件,然后使用make命令编译代码。
boost-devel zlib-devel openssl-devel libcurl-devel:都是编译时所依赖的库。

下载源码

# 由于Tair依赖tbsys和tbnet库,需要安装这两个库,而这两库需要编译tb-common-utils安装
# 安装git:
[root@test ~]# yum install -y git# 从码云上下载tb-common-utils源码:
[root@test ~]# git clone https://gitee.com/abc0317/tb-common-utils.git
[root@test ~]# cd tb-common-utils/
[root@test tb-common-utils]# lltotal 16-rwxrwxrwx. 1 root root  820 Mar 20 09:28 build.sh-rw-r--r--. 1 root root   79 Mar 20 09:28 README.mddrwxr-xr-x. 5 root root 4096 Mar 20 09:34 tbnetdrwxr-xr-x. 5 root root 4096 Mar 20 09:33 tbsys
# 赋予执行权限
[root@test tb-common-utils]# chmod u+x build.sh
# 指定TBLIB_ROOT环境变量 TBLIB_ROOT为需要安装的目录。
[root@test tb-common-utils]# export TBLIB_ROOT=/root/tairlib# 进入源码目录, 执行build.sh进行安装
[root@test tb-common-utils]# sh build.sh# 从码云上下载Tair源码:
[root@test tb-common-utils]#cd ~
[root@test ~]# git clone https://gitee.com/mirrors/Tair.git

编译安装Tair

[root@test ~]# cd Tair
# 编译依赖
[root@test Tair]# ./bootstrap.sh
# 检测和生成 Makefile (默认安装位置是 ~/tair_bin, 修改使用 --prefix=目标目录)
[root@test Tair]# ./configure
# 编译和安装到目标目录
[root@test Tair]# make -j && make install

配置Tair

基于MDB内存引擎,采用最小化配置方式,1个ConfigServer,1个DataServer搭建Tair集群

由于MDB 引擎默认使用共享内存,所以需要查看并设置系统的tmpfs的大小,tmpfs是Linux/Unix系统上的一种基于内存的虚拟文件系统。

# df命令用于显示目前在Linux系统上的文件系统的磁盘使用情况统计
[root@test Tair]# df -hFilesystem               Size  Used Avail Use% Mounted ondevtmpfs                 908M     0  908M   0% /devtmpfs                    919M  185M  735M  21% /dev/shmtmpfs                    919M   17M  903M   2% /runtmpfs                    919M     0  919M   0% /sys/fs/cgroup/dev/mapper/centos-root   41G  2.0G   39G   5% //dev/sda1               1014M  146M  869M  15% /boot/dev/mapper/centos-home   20G   33M   20G   1% /hometmpfs                    184M     0  184M   0% /run/user/0

/dev/shm 目录位于 linux 系统的内存中,而不在磁盘里,所以它的效率非常高,这里我们将大小设置1G,

修改**/etc/fstab** 的这行,如果没有就在末尾加一行

tmpfs /dev/shm tmpfs defaults 0 0

改为

tmpfs /dev/shm tmpfs defaults,size=1G 0 0

改完之后,执行mount使其生效

mount -o remount /dev/shm

生效后再使用df -h 查看

[root@test Tair]# df -hFilesystem               Size  Used Avail Use% Mounted ondevtmpfs                 908M     0  908M   0% /devtmpfs                    1.0G  185M  840M  19% /dev/shmtmpfs                    919M   17M  903M   2% /runtmpfs                    919M     0  919M   0% /sys/fs/cgroup/dev/mapper/centos-root   41G  2.0G   39G   5% //dev/sda1               1014M  146M  869M  15% /boot/dev/mapper/centos-home   20G   33M   20G   1% /hometmpfs                    184M     0  184M   0% /run/user/0

切换到Tair安装目录,拷贝默认配置文件准备修改

[root@test ~]# cd /root/tair_bin/etc
[root@test etc]# mv configserver.conf.default configserver.conf
[root@test etc]# mv group.conf.default group.conf
[root@test etc]# mv dataserver.conf.default dataserver.conf

该机器ip是 192.168.31.97

configserver.conf

# tair 2.3 --- configserver config
#
[public]
# 主备 ConfigServer 的地址和端口号,第一行为主,第二行为备,目前采用最简单集群只配置一个ConfigServer
#config_server=192.168.1.1:5198
#config_server=192.168.1.2:5198
config_server=192.168.31.97:5198[configserver]
# ConfigServer 的工作端口号,和上面的配置以及 dataserver.conf 里的要一致
port=5198
# 日志文件位置
log_file=logs/config.log
# pid 存储的文件位置
pid_file=logs/config.pid
# 默认日志级别
log_level=warn
# group.conf 文件的位置
group_file=etc/group.conf
# 运行时状态持久化文件的位置
data_dir=data/data
# 使用的网卡设备名设置为你自己当前网络接口的名称,默认为eth0
dev_name=eth0

group.conf

#group name
# 集群分组的名字,tair 支持一组 ConfigServer 管理多个集群 (不建议,避免流量瓶颈在 ConfigServer 上)
#[group_1]
[group_test]# data move is 1 means when some data serve down, the migrating will be start.
# default value is 0
# 是否允许数据迁移,双份数据情况下,要设置为 1 (内部逻辑判断是双份的话,内部也会强制置为1)
_data_move=0
#_min_data_server_count: when data servers left in a group less than this value, config server will stop serve for this group
#default value is copy count.
# 过载保护的参数,当可用的 DataServer 节点少于这个数字时,ConfigServer 不再自动检测宕机并重建路由表(避免逐台击穿而雪崩)
_min_data_server_count=1
#_plugIns_list=libStaticPlugIn.so
# 建表算法的选择和一些参数,一般默认即可
_build_strategy=1 #1 normal 2 rack
_build_diff_ratio=0.6 #how much difference is allowd between different rack
# diff_ratio =  |data_sever_count_in_rack1 - data_server_count_in_rack2| / max (data_sever_count_in_rack1, data_server_count_in_rack2)
# diff_ration must less than _build_diff_ratio
_pos_mask=65535  # 65535 is 0xffff  this will be used to gernerate rack info. 64 bit serverId & _pos_mask is the rack info,
# 数据的备份数,注意集群一旦初始化,不能修改这个值
_copy_count=1
# 虚拟节点的个数,当集群机器数量很多时,可以调整这个值
# 注意一旦集群初始化完毕,这个值不能修改
_bucket_number=1023
# accept ds strategy. 1 means accept ds automatically
# 该文件的修改会触发 ConfigServer 自动 reload,下面的参数控制是否自动加入本文件新增的 DataServer 节点到集群
# _min_data_server_count 参数也会影响,如果节点总数小于 _min_data_server_count,也不会自动加入
_accept_strategy=1
# 是否允许 failover 机制
# 这个机制工作在 LDB 引擎模式的集群下,当 _min_data_server_count 参数大于集群机器数(阻止自动剔除宕机机器)时,
# 如果该参数为1,宕机的第一个节点会进入 failover 模式,此时备机接管读写请求,同时记录恢复日志,当宕机节点恢复时,
# 自动进入 recovery 模式,根据恢复日志补全数据。注意此时第二台如果宕机,不会自动处理,所以第一台一旦宕机收到告警,
# 请尽快人为干预处理。  **failover 机制想正常工作,需要 dataserver.conf 的 do_dup_depot 为 1 才可以**
_allow_failover_server=0# 下面是 DataServer 节点列表,注释 data center A/B 并不是集群组的概念
# 集群组的配置是当前这个文件所有内容,复制整个内容追加到本文件尾部,可以添加一个集群组
# 注意一个节点不能出现在两个集群组里!配置文件不做该校验。
# data center A
#_server_list=192.168.1.1:5191
#_server_list=192.168.1.2:5191
#_server_list=192.168.1.3:5191
#_server_list=192.168.1.4:5191
_server_list=192.168.31.97:5191# data center B
#_server_list=192.168.2.1:5191
#_server_list=192.168.2.2:5191
#_server_list=192.168.2.3:5191
#_server_list=192.168.2.4:5191#quota info
# 配额信息
# 当引擎是 MDB 时,控制每个 Namespace 的内存配额,单位是字节
# Tair 支持 0~65535 的 Namespace 范围,每个 Namespace 内部的 key 命名空间隔离
# 代码中出现的 area 是 Namespace 的同义词
_areaCapacity_list=0,1124000;

dataserver.conf

#
#  tair 2.3 --- tairserver config
#
[public]
# 主备 ConfigServer 的地址
#config_server=192.168.1.1:5198
#config_server=192.168.1.2:5198
config_server=192.168.31.97:5198[tairserver]
#
#storage_engine:
#
# mdb
# ldb
#
# 使用的引擎,支持 MDB 和 LDB
storage_engine=mdb
local_mode=0
#
#mdb_type:
# mdb
# mdb_shm
#
# 如果引擎是 MDB,这里选择使用普通内存还是共享内存
mdb_type=mdb_shm# shm file prefix, located in /dev/shm/, the leading '/' is must
# MDB 实例的命名前缀,一般在单机部署多个节点时需要修改
mdb_shm_path=/mdb_shm_inst
# (1<<mdb_inst_shift) would be the instance count
# MDB 引擎的实例个数,多个实例减少锁竞争但是会增加元数据而浪费内存
#mdb_inst_shift=3
mdb_inst_shift=0# (1<<mdb_hash_bucket_shift) would be the overall bucket count of hashtable
# (1<<mdb_hash_bucket_shift) * 8 bytes memory would be allocated as hashtable
# MDB 实例内部 hash 表的 bucket 数,24~27均可(取决于实例大小)
mdb_hash_bucket_shift=24
# milliseconds, time of one round of the checking in mdb lasts before having a break
mdb_check_granularity=15
# increase this factor when the check thread of mdb incurs heavy load
# cpu load would be around 1/(1+mdb_check_granularity_factor)
mdb_check_granularity_factor=10#tairserver listen port
port=5191supported_admin=0
# 工作时的 IO 线程数和 Worker 线程数
#process_thread_num=12
process_thread_num=4#io_thread_num=12
io_thread_num=4# 双份数据时,往副本写数据的 IO 线程数,只能是 1
dup_io_thread_num=1
#
#mdb size in MB
#
# MDB 引擎使用的存储数据的内存池总大小 这里 slab_mem_size控制MDB内存池的总大小,mdb_inst_shift 控制实例的个数,每个实例的大小是 slab_mem_size/(1 << mdb_inst_shift) MB,注意这里一个实例必须大于512MB且小于64GB
#slab_mem_size=4096
slab_mem_size=512log_file=logs/server.log
pid_file=logs/server.pidis_namespace_load=1
is_flowcontrol_load=1
tair_admin_file = etc/admin.conf# 是否在put操作遍历 hash 表冲突链时,顺带删除已经 expired 的数据
# 会导致 put 的时延增大一点点,但是有利于控制过期数据很多的场景下内存增幅
put_remove_expired=0
# set same number means to disable the memory merge, like 5-5
mem_merge_hour_range=5-5
# 1ms copy 300 items
mem_merge_move_count=300log_level=warn
dev_name=eth0
ulog_dir=data/ulog
ulog_file_number=3
ulog_file_size=64
check_expired_hour_range=2-4
check_slab_hour_range=5-7
dup_sync=1
dup_timeout=500# 是否使用 LDB 集群间的数据自动同步
do_rsync=0rsync_io_thread_num=1
rsync_task_thread_num=4rsync_listen=1
# 0 mean old version
# 1 mean new version
# 这里只能是 1
rsync_version=1
# 同步的详细配置地址,也可以使用 file:// 来指定本地磁盘的配置位置
rsync_config_service=http://localhost:8080/hangzhou/group_1
rsync_config_update_interval=60# much resemble json format
# one local cluster config and one or multi remote cluster config.
# {local:[master_cs_addr,slave_cs_addr,group_name,timeout_ms,queue_limit],remote:[...],remote:[...]}
# rsync_conf={local:[10.0.0.1:5198,10.0.0.2:5198,group_local,2000,1000],remote:[10.0.1.1:5198,10.0.1.2:5198,group_remote,2000,800]}
# if same data can be updated in local and remote cluster, then we need care modify time to
# reserve latest update when do rsync to each other.
rsync_mtime_care=0
# rsync data directory(retry_log/fail_log..)
rsync_data_dir=./data/remote
# max log file size to record failed rsync data, rotate to a new file when over the limit
rsync_fail_log_size=30000000
# when doing retry,  size limit of retry log's memory use
rsync_retry_log_mem_size=100000000# depot duplicate update when one server down
# failover 机制的 DataServer 开关,见 group.conf 相关说明
do_dup_depot=0
dup_depot_dir=./data/dupdepot# 默认的流控配置,total 为整机限制
[flow_control]
# default flow control setting
default_net_upper = 30000000
default_net_lower = 15000000
default_ops_upper = 30000
default_ops_lower = 20000
default_total_net_upper = 75000000
default_total_net_lower = 65000000
default_total_ops_upper = 50000
default_total_ops_lower = 40000[ldb]
#### ldb manager config
## data dir prefix, db path will be data/ldbxx, "xx" means db instance index.
## so if ldb_db_instance_count = 2, then leveldb will init in
## /data/ldb1/ldb/, /data/ldb2/ldb/. We can mount each disk to
## data/ldb1, data/ldb2, so we can init each instance on each disk.
data_dir=data/ldb
## leveldb instance count, buckets will be well-distributed to instances
ldb_db_instance_count=1
## whether load backup version when startup.
## backup version may be created to maintain some db data of specifid version.
ldb_load_backup_version=0
## whether support version strategy.
## if yes, put will do get operation to update existed items's meta info(version .etc),
## get unexist item is expensive for leveldb. set 0 to disable if nobody even care version stuff.
ldb_db_version_care=1
## time range to compact for gc, 1-1 means do no compaction at all
ldb_compact_gc_range = 3-6
## backgroud task check compact interval (s)
ldb_check_compact_interval = 120
## use cache count, 0 means NOT use cache,`ldb_use_cache_count should NOT be larger
## than `ldb_db_instance_count, and better to be a factor of `ldb_db_instance_count.
## each cache mdb's config depends on mdb's config item(mdb_type, slab_mem_size, etc)
ldb_use_cache_count=1
## cache stat can't report configserver, record stat locally, stat file size.
## file will be rotate when file size is over this.
ldb_cache_stat_file_size=20971520
## migrate item batch size one time (1M)
ldb_migrate_batch_size = 3145728
## migrate item batch count.
## real batch migrate items depends on the smaller size/count
ldb_migrate_batch_count = 5000
## comparator_type bitcmp by default
# ldb_comparator_type=numeric
## numeric comparator: special compare method for user_key sorting in order to reducing compact
## parameters for numeric compare. format: [meta][prefix][delimiter][number][suffix]
## skip meta size in compare
# ldb_userkey_skip_meta_size=2
## delimiter between prefix and number
# ldb_userkey_num_delimiter=:
####
## use blommfilter
ldb_use_bloomfilter=1
## use mmap to speed up random acess file(sstable),may cost much memory
ldb_use_mmap_random_access=0
## how many highest levels to limit compaction
ldb_limit_compact_level_count=0
## limit compaction ratio: allow doing one compaction every ldb_limit_compact_interval
## 0 means limit all compaction
ldb_limit_compact_count_interval=0
## limit compaction time interval
## 0 means limit all compaction
ldb_limit_compact_time_interval=0
## limit compaction time range, start == end means doing limit the whole day.
ldb_limit_compact_time_range=6-1
## limit delete obsolete files when finishing one compaction
ldb_limit_delete_obsolete_file_interval=5
## whether trigger compaction by seek
ldb_do_seek_compaction=0
## whether split mmt when compaction with user-define logic(bucket range, eg)
ldb_do_split_mmt_compaction=0## do specify compact
## time range 24 hours
ldb_specify_compact_time_range=0-6
ldb_specify_compact_max_threshold=10000
## score threshold default = 1
ldb_specify_compact_score_threshold=1#### following config effects on FastDump ####
## when ldb_db_instance_count > 1, bucket will be sharded to instance base on config strategy.
## current supported:
##  hash : just do integer hash to bucket number then module to instance, instance's balance may be
##         not perfect in small buckets set. same bucket will be sharded to same instance
##         all the time, so data will be reused even if buckets owned by server changed(maybe cluster has changed),
##  map  : handle to get better balance among all instances. same bucket may be sharded to different instance based
##         on different buckets set(data will be migrated among instances).
ldb_bucket_index_to_instance_strategy=map
## bucket index can be updated. this is useful if the cluster wouldn't change once started
## even server down/up accidently.
ldb_bucket_index_can_update=1
## strategy map will save bucket index statistics into file, this is the file's directory
ldb_bucket_index_file_dir=./data/bindex
## memory usage for memtable sharded by bucket when batch-put(especially for FastDump)
ldb_max_mem_usage_for_memtable=3221225472
######## leveldb config (Warning: you should know what you're doing.)
## one leveldb instance max open files(actually table_cache_ capacity, consider as working set, see `ldb_table_cache_size)
ldb_max_open_files=65535
## whether return fail when occure fail when init/load db, and
## if true, read data when compactiong will verify checksum
ldb_paranoid_check=0
## memtable size
ldb_write_buffer_size=67108864
## sstable size
ldb_target_file_size=8388608
## max file size in each level. level-n (n > 0): (n - 1) * 10 * ldb_base_level_size
ldb_base_level_size=134217728
## sstable's block size
# ldb_block_size=4096
## sstable cache size (override `ldb_max_open_files)
ldb_table_cache_size=1073741824
##block cache size
ldb_block_cache_size=16777216
## arena used by memtable, arena block size
#ldb_arenablock_size=4096
## key is prefix-compressed period in block,
## this is period length(how many keys will be prefix-compressed period)
# ldb_block_restart_interval=16
## specifid compression method (snappy only now)
# ldb_compression=1
## compact when sstables count in level-0 is over this trigger
ldb_l0_compaction_trigger=1
## whether limit write with l0's filecount, if false
ldb_l0_limit_write_with_count=0
## write will slow down when sstables count in level-0 is over this trigger
## or sstables' filesize in level-0 is over trigger * ldb_write_buffer_size if ldb_l0_limit_write_with_count=0
ldb_l0_slowdown_write_trigger=32
## write will stop(wait until trigger down)
ldb_l0_stop_write_trigger=64
## when write memtable, max level to below maybe
ldb_max_memcompact_level=3
## read verify checksum
ldb_read_verify_checksums=0
## write sync log. (one write will sync log once, expensive)
ldb_write_sync=0
## bits per key when use bloom filter
#ldb_bloomfilter_bits_per_key=10
## filter data base logarithm. filterbasesize=1<<ldb_filter_base_logarithm
#ldb_filter_base_logarithm=12[extras]
######## RT-related ########
#rt_oplist=1,2
# Threashold of latency beyond which would let the request be dumped out.
rt_threshold=8000
# Enable RT Module at startup
rt_auto_enable=0
# How many requests would be subject to RT Module
rt_percent=100
# Interval to reset the latency statistics, by seconds
rt_reset_interval=10######## HotKey-related ########
hotk_oplist=2
# Sample count
hotk_sample_max=50000
# Reap count
hotk_reap_max=32
# Whether to send client feedback response
hotk_need_feedback=0
# Whether to dump out packets, caches or hot keys
hotk_need_dump=0
# Whether to just Do Hot one round
hotk_one_shot=0
# Whether having hot key depends on: sigma >= (average * hotk_hot_factor)
hotk_hot_factor=0.8

在CentOS 7下,安装目录下的 tair.sh 启动脚本有一行代码(55行)需要修改

tmpfs_size=`df -m |grep tmpfs | awk '{print $2}'`
#这行改成下面这一行
tmpfs_size=`df -m |grep /dev/shm | awk '{print $2}'`

启动Tair实例

# 需要跟参数
[root@test tair_bin]# ./tair.sh
usage: ./tair.sh {start_cs|stop_cs|start_ds|stop_ds|start_iv|stop_iv|start_px|start_px [SERVER_COUNT]|clean|log_debug2warn|log_warn2debug}
# start_ds启动数据节点
[root@test tair_bin]# ./tair.sh start_ds
mdb engine. tmpfs_size: 1024  safety_size: 524  slab_mem_size: 512
[root@test tair_bin]# ps -ef | grep tair
root      1983     1  1 08:51 pts/0    00:00:00 ./sbin/tair_server -f ./etc/dataserver.conf
root      2011  1626  0 08:51 pts/0    00:00:00 grep --color=auto tair
# start_ds启动config配置节点
[root@test tair_bin]# ./tair.sh start_cs
[root@test tair_bin]# ps -ef | grep tair
root      1983     1  1 08:51 pts/0    00:00:05 ./sbin/tair_server -f ./etc/dataserver.conf
root      2018     1  0 08:58 pts/0    00:00:00 ./sbin/tair_cfg_svr -f ./etc/configserver.conf
root      2034  1626  0 08:58 pts/0    00:00:00 grep --color=auto tair

使用自带客户端测试读写

[root@test tair_bin]# ./sbin/tairclient -c 192.168.31.97:5198 -g group_test
TAIR> put name itheima
put: success
TAIR> get name
KEY: name, LEN: 7raw data: itheima, \69\74\68\65\69\6D\61
TAIR> remove name
remove: success.
TAIR> get name
get failed: data not exists.

停止tair服务

# 停止数据节点
[root@test tair_bin]# ./tair.sh stop_ds
# 停止配置节点
[root@test tair_bin]# ./tair.sh stop_cs
[root@test tair_bin]# ps -ef | grep tair
root      2061  1626  0 09:02 pts/0    00:00:00 grep --color=auto tair

Tair入门demo

搭工程导入依赖

 <dependency><groupId>com.taobao.tair</groupId><artifactId>tair-client</artifactId><version>2.3.5</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.59</version></dependency>

测试简单put和get命令

TestTair类

package com.itheima;import com.alibaba.fastjson.JSON;
import com.taobao.tair.DataEntry;
import com.taobao.tair.Result;
import com.taobao.tair.impl.DefaultTairManager;import java.util.ArrayList;
import java.util.List;public class TestTair {public static void main(String[] args) {List<String> configList = new ArrayList<String>();configList.add("192.168.31.97:5198");//ConfigServer的ip和端口DefaultTairManager tairManager = new DefaultTairManager();tairManager.setConfigServerList(configList);tairManager.setGroupName("group_test");//和配置中的组名称保持一致tairManager.init();ResultCode putResult = tairManager.put(1, "name", "itcast");System.out.println(JSON.toJSONString(putResult));//{"code":0,"message":"success","success":true}Result<DataEntry> getResult = tairManager.get(1, "name");System.out.println(JSON.toJSONString(getResult));	//{"rc":{"code":0,"message":"success","success":true},"success":true,"value":{"createDate":0,"expriedDate":0,"key":"name","locked":false,"modifyDate":1585119311,"value":"itcast","version":1}}System.out.println(getResult.getValue());//value: key: name, value: itcast, version: 1 cdate: 1970-01-01 08:00:00 mdate: 2020-03-25 02:55:11 edate: NEVERSystem.out.println(getResult.getValue().getValue());//itcast}
}

Tair原理架构

在这里插入图片描述
在这里插入图片描述
一个Tair集群主要包括3个必选模块:ConfigServerDataserverClient

通常情况下,一个 Tair 集群中包含2台 Configserver 及多台 DataServer。其中两台 Configserver 互为主备。通过和 Dataserver 之间的心跳检测获取集群中存活可用的 Dataserver,构建数据在集群中的分布信息(对照表)。Dataserver 负责数据的存储,并按照 Configserver 的指示完成数据的复制和迁移工作。Client 在启动的时候,从 Configserver 获取数据分布信息,根据数据分布信息,和相应的 Dataserver 进行交互,完成用户的请求。

从架构上看,Configserver 的角色类似于传统应用系统的中心节点,整个集群服务依赖于 Configserver 的正常工作。而实际上,Tair 的 Configserver 是非常轻量级的,当正在工作的 Configserver 宕机的时候,另一台会在秒级别时间内自动接管。而且,即使出现两台 ConfigServer 同时宕机的恶劣情况,只要 DataServer 没有新的变化,Tair 依然服务正常。应用在使用时只需要连接 Configserver,而不需要知道内部节点的情况。

table

​ 对照表,存放了桶和dataserver的对应关系,put数据时,会对key进行hash计算,在对桶数量取模,然后根据对照表找到相应的dataserver

0192.168.10.1
1192.168.10.2
2192.168.10.1
3192.168.10.2
4192.168.10.1
5192.168.10.2

假设新增了一个节点——192.168.10.3,当configserver发现新增的节点后,会重新构建对照表。构建依据以下两个原则:

  1. 数据在新表中均衡地分布到所有节点上。
  2. 尽可能地保持现有的对照关系。

更新之后的对照表如下所示:

0192.168.10.1
1192.168.10.2
2192.168.10.1
3192.168.10.2
4192.168.10.3
5192.168.10.3

Client

  • 提供访问 Tair 集群的API
  • 更新并缓存数据分布表
  • LocalCache,避免过热的数据访问影响 Tair 集群服务。
  • 流量控制

common

​ common 目录提供基础数据结构和组件

ConfigServer

  • 两台 Configserver 互为主备
  • 通过和 Dataserver 之间的心跳检测来获取集群中存活、可用的 Dataserver 节点信息
  • 根据获取的 Dataserver 节点信息构建数据在集群中的分布表
  • 提供数据分布表的查询服务
  • 调度 Dataserver 之间的数据迁移、复制

DataServer

  • 提供存储引擎
  • 接受 Client 发起的 put/get/remove 等操作
  • 执行数据迁移、复制
  • 访问统计

Storage

​ Tair的存储分为两种:persistence(持久化)和 cache(非持久化) ,非持久化Tair看成是分布式缓存,持久化Tair将数据序列化到磁盘,还可以配置备份数量,将一份数据放到不同的主机上,防止数据丢失。
​ Tair对存储做了一个抽象层,可以很方便的替换 tair 底层的存储引擎,主要有下面三种存储引擎:

mdb

​ 一个高效率的关系型缓存存储数据库,定位于 cache 缓存,类似于 memcache。采用page/slab管理内存。支持 k/v 存取、prefix 操作、expire数据过期,采用共享内存方式,重启数据不丢。阿里内部大都采用此种模式。
图中mempool是申请到的内存池,大小在配置文件dataserver.conf中指定slab_mem_size=4096,默认是4个g,mempool被划分很多slab组,每组slab下又包含了若干page,每个page下又包含了一组chunk,memcache中叫chunk在图中指定item,item是真正存放数据的地方。

在这里插入图片描述

rdb

​ 定位于 cache 缓存,采用了 redis 的内存存储结构。支持 k/v, list, hash, set, sortedset 等数据结构。
在这里插入图片描述
在这里插入图片描述

ldb

​ ldb,定位于高性能存储, 多实例配置使用,充分利用IO,采用了 levelDB 作为引擎,并可选择内嵌mdb作为KV级别cache 加速,这种情况下 cache 与持久化存储的数据一致性由 tair 进行维护。支持 k/v,prefix 等数据结构。

Memtable:内存数据结构,新的数据会首先写入这里。
Log文件:写Memtable前会先写Log文件,Log通过append的方式顺序写入,Log的存在使得机器宕机导致的内存数据丢失得以恢复。
compact:压缩,LevelDB的一个重要特性就是数据的分层,由于数据的分层, 越旧的数据处在越大的层级,越新的数据在越小的层级,compaction的过程是产生SSTable的过程,在查询数据的时候, 最先读取MemTable里面的数据, 然后是L0的SSTable里面, 接着是L1, L2直到最大的层级。在分层设计中, 越往上层,数据的容量越大, 大约Ln是Ln-1层数据的10倍。 在各个层级的SSTable文件, 只有L0层的数据是有MemTable直接flush到磁盘上, 其它层的数据是经过compaction过程进行排序整理产生的。这意味着L0层以上的数据, 各个SSTable文件内的数据是有序且不会重叠的。

在这里插入图片描述
在这里插入图片描述

packets

​ packets目录提供了通信协议中各种数据包的实现。基础库主要包括tbsys和tbnet,其中tbsys是主要的数据结构和文件操作的实现,包括排它锁和读写锁实现,对线程的包装,以及配置文件读写和分析等。tbnet是主要实现了单线程的网络读写数据流,采用了epoll的模式。

plugin

​ tair 还内置了一个插件容器,可以支持热插拔插件。插件由 config server 配置,config server 会将插件配置同步给各个数据节点,数据节点会负责加载/卸载相应的插件。
在这里插入图片描述
插件分为 request 和 response 两类,可以分别在 request 和 response 时执行相应的操作,比如在 put 前检查用户的 quota 信息等。插件容器也让 tair 在功能方便具有更好的灵活性。

Tair核心方法

  • put

    put重载了三个方法,namespace是存储空间,0到65535之间,key和value都会序列化,version是版本号,expireTime是失效时间,单位为秒

    ResultCode put(int namespace, Serializable key, Serializable value)
    ResultCode put(int namespace, Serializable key, Serializable value, int version)
    ResultCode put(int namespace, Serializable key, Serializable value, int version, int expireTime)
    
  • get

    Result<DataEntry> get(int namespace, Serializable key)
    

    get接口用于获取单个数据,要获取的数据由namespace和key指定。
    当数据存在时,返回成功,数据存放在DataEntry对象中;
    当数据不存在时,返回成功,ResultCode为ResultCode.DATANOTEXSITS,value为null。

  • mget

    Result<List<DataEntry>> mget(int namespace, List<? extends Object> keys)
    

    mget接口用于批量获取数据,要获取的数据由namespace和keys 集合指定。

    数据存放在DataEntry对象中病放到List中返回

  • delete

    ResultCode delete(int namespace, Serializable key)
    

    根据namespace和key删除指定缓存

  • mdelete

    ResultCode mdelete(int namespace, List<? extends Object> keys)
    

    根据namespace和 keys 批量删除

  • getStat

    Map<String,String> getStat(int qtype, String groupName, long serverId)
    

    得到统计信息

  • incr/decr

    Result<Integer> incr(int namespace, Serializable key, int value,int defaultValue, int expireTime)
    Result<Integer> decr(int namespace, Serializable key, int value,int defaultValue, int expireTime)
    

    namespace:计数器所在的namespace,key:缓存的key,value:本次增加 或者 减少值,defaultValue: 当计数器不存在时的初始化值 ,expireTime:过期时间,单位为秒

  • setCount

    ResultCode setCount(int namespace, Serializable key, int count)
    ResultCode setCount(int namespace, Serializable key, int count, int version, int expireTime)
    

    将key对应的计数设置成count,忽略key原来是否存在以及是否是计数类型。因为Tair中计数的数据有特别标志,所以不能直接使用put设置计数值。

  • lock/unlock

    ResultCode lock(int namespace, Serializable key)
    ResultCode unlock(int namespace, Serializable key)
    

    在并发情况下可以通过lock和unlock来实现分布式锁

  • invalid/minvalid

    ResultCode invalid(int namespace, Serializable key)
    ResultCode minvalid(int namespace, List<? extends Object> keys)
    

    删除缓存

  • version支持

    ​ 在Tair的put接口中,有一个version参数,这个参数是为了解决并发更新同一个数据而设置的。很多情况下,更新数据是先get,修改get回来的数据,然后put回系统。如果有多个客户端get到同一份数据,都对其修改并保存,那么先保存的修改就会被后到达的修改覆盖,从而导致数据丢失问题。
    ​ 比如,缓存中有一个value值为 “a,b,c”,A和B同时get到这个value。A执行操作,在后面添加一个d,value为 “a,b,c,d”。B执行操作添加一个e,value为”a,b,c,e”。如果不加控制,无论A和B谁先更新成功,它的更新都可能会被后到的更新覆盖。

    version使用方式

    ​ get接口返回的是DataEntry对象,该对象中包含get到的数据的版本号,可以通过getVersion()接口获得该版本号。在put时,将该版本号作为put的参数即可。 如果不考虑版本问题,则可设置version参数为0,系统将强行覆盖数据,即使版本不一致。

    如果返回version不一致,怎么办?

    ​ 如果更新所基于的version和系统中当前的版本不一致,则服务器会返回ResultCode.VERERROR。 这时你可以选择重新get数据,然后在新版本的数据上修改;或者设置version为0重新请求,以达到强制更新的效果。

Tair使用规范

key和value不能设置太大,否则耗时大,服务qps(每秒查询率)低,影响性能

key不要使用相同的值作为前缀,否则数据都会落到一个dataserver上,增加该数据节点的压力

批量请求的key个数不要太大,否则也会影响性能

超时时间也不要设置太大或者太小,设置太小容易超时,设置太大容易阻塞,建议使用默认值

Tair虽然支持list,set,map等复杂数据结构,但是支持不是很好,元素个数不易过多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/52356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法】粒子群优化

一、引言 粒子群优化算法&#xff08;Particle Swarm Optimization, PSO&#xff09;是一种基于群体智能的优化技术&#xff0c;由Eberhart和Kennedy在1995年提出。它模拟鸟群觅食行为&#xff0c;通过个体与群体的协作来寻找最优解。通过模拟一群粒子的运动来寻找最优解。每个…

qtcreator的vim模式下commit快捷键ctrl+g,ctrl+c没有反应的问题

首先开启vim后&#xff0c;CtrlG&#xff0c;CtrlC无法用 解决&#xff1a; 工具 -> 选项->FakeVim 转到Ex Command Mapping 搜索Commit 底栏Regular expression 输入commit &#xff08;理论上可以是随意的单词&#xff09; 设置好后&#xff0c;以后要运行&#x…

ETF指数通行红绿灯对接自动交易框架!添加绿灯品种进交易池!股票量化分析工具QTYX-V2.8.9...

前言 我们的股票量化系统QTYX在实战中不断迭代升级!!! 指数通行红绿灯作用就是识别出上升和下降趋势品种。对于上升趋势的品种&#xff0c;在红转绿时买入&#xff0c;绿转红时卖出&#xff0c;当识别出下降趋势后要果断离场&#xff01; 在QTYX的2.8.7版本我们推出了“ETF全自…

【css】伪元素实现跟随鼠标移动的渐变效果

主要功能是在按钮上实现鼠标跟随渐变效果。每当用户将鼠标移动到按钮上时&#xff0c;按钮会显示一个以鼠标位置为中心的渐变效果。 1. 核心部分: 监听鼠标在元素内移动 监听鼠标在元素内移动&#xff0c;并触发该事件。 const handleMouseMove (e: MouseEvent) > {if (…

el-form中使用v-model和prop实现动态校验

如何在Vue的el-form中使用v-model和prop实现动态校验&#xff0c;包括多个变量控制校验、数组循环校验和字段级条件显示。通过实例演示了如何配合rules和自定义验证函数来确保表单的完整性和有效性。 公式&#xff1a; 动态校验项的v-model的绑定值 el-form的属性 :model的值 …

多系统萎缩不慌张,这些维生素是你的“守护神”✨

亲爱的朋友们&#xff0c;今天我们来聊聊一个可能不太为人熟知但至关重要的健康话题——多系统萎缩&#xff08;MSA&#xff09;。面对这样的挑战&#xff0c;除了医疗治疗&#xff0c;日常的营养补充也是不可或缺的一环。特别是维生素&#xff0c;它们在我们的身体中扮演着举足…

FastGPT+ollama 搭建私有AI大模型智能体工作流-Mac

一、大模型工作流的优势 1. 降低任务门槛&#xff1a;工作流可以将复杂任务分解成多个小任务&#xff0c;降低每个任务的复杂度&#xff0c;从而减少对提示词和大模型推理能力的依赖。这样可以提升大模型处理复杂任务的性能和容错能力。 2. 提升任务效率&#xff1a;工作流可以…

【OpenHarmony】openharmony移植到RK3568------获取源码编译OpenHarmony源码

一、源码获取 源码获取有好几种方式&#xff0c;在这里直接在镜像网站下载源码&#xff0c;点击下面连接下载全量版本的OpenHarmony4.1 https://repo.huaweicloud.com/openharmony/os/4.1-Release/code-v4.1-Release.tar.gz 将源码放到自己建立的目录下解压&#xff0c;我放…

PHP轻创推客集淘客地推任务平台于一体的综合营销平台系统源码

&#x1f680;轻创推客&#xff0c;营销新纪元 —— 集淘客与地推任务于一体的全能平台&#x1f310; &#x1f308;【开篇&#xff1a;营销新潮流&#xff0c;轻创推客引领未来】 在瞬息万变的营销世界里&#xff0c;你还在为寻找高效、全面的营销渠道而烦恼吗&#xff1f;&…

[Meachines] [Easy] jerry Tomcat用户暴力破解+war包webshell上传

信息收集 IP AddressOpening Ports10.10.10.95TCP:8080 $ sudo masscan -p1-65535 10.10.10.95 --rate1000 -e tun0 > /tmp/ports $ ports$(cat /tmp/ports | awk -F " " {print $4} | awk -F "/" {print $1} | sort -n | tr \n , | sed s/,$//) $ …

微服务——远程调用

为什么需要远程调用&#xff1f; 在微服务架构中&#xff0c;每个服务都是独立部署和运行的&#xff0c;它们之间需要相互协作以完成复杂的业务逻辑。因此&#xff0c;远程调用成为微服务之间通信的主要方式。通过远程调用&#xff0c;一个服务可以请求另一个服务执行某些操作或…

【前端面试】操作系统

进程与线程 进程线程定义是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位是进程中的一个实体&#xff0c;是CPU调度和分派的基本单位&#xff0c;共享进程的资源资源分配拥有独立的内存空间和系统资源共享进程的内存和资源开销…

Educational Codeforces Round 169 (Rated for Div. 2)

前言 电脑显示屏一闪一闪地感觉要拿去修了&#xff0c;比赛时重启了好几次。 手速场&#xff0c;E 题没学过 Sprague-Grundy 吃了亏&#xff0c;好在前四题都一发过才不至于掉分。 Standings&#xff1a;1214 题目链接&#xff1a;Dashboard - Educational Codeforces Round 16…

【架构设计】-- aarch(ARM) and X86

1、aarch(ARM) 架构 &#xff08;1&#xff09;操作系统支持&#xff1a;早期为 32 位操作系统&#xff0c;目前大部分都是 64 位操作系统 &#xff08;2&#xff09;全称&#xff1a;Advanced RISC Machine&#xff0c;由英国ARM Holdings plc公司开发 这种架构主要⽤于智能…

Android车载蓝牙音乐实例(附Demo源码):实现手机播放音乐后车机应用显示音乐名称,歌手,专辑名。且可控制上一曲下一曲,暂停播放功能

一、功能需求 功能需求是在Android10以上设备上实现蓝牙音乐功能&#xff0c;细分为两个功能点&#xff1a; 1、手机和车载设备实现蓝牙连接 &#xff08;本Demo文只做监听蓝牙连接状态&#xff0c;需手动到设置中连接蓝牙&#xff09; 2、连接蓝牙成功后手机播放音乐时车载…

leetcode 递归(回溯)——java实现

递归算法与DFS类似&#xff0c;也与二叉树的先序遍历类似 以下摘自 leetcode回溯算法入门级详解 回溯法 采用试错的思想&#xff0c;它尝试分步的去解决一个问题。在分步解决问题的过程中&#xff0c;当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候&#xff…

MySQL笔记01: MySQL入门_1.2 MySQL下载安装与配置

2.2 MySQL下载安装与配置 2.2.1 MySQL下载 MySQL中文官网&#xff1a;https://www.mysql.com/cn/ MySQL英文官网&#xff1a;https://www.mysql.com/ MySQL官网下载地址&#xff1a;https://www.mysql.com/downloads/ &#xff08;1&#xff09;点击“MySQL Community (GPL) Do…

TinaSDKV2.0 自定义系统开发

TinaSDKV2.0 自定义系统开发 什么是自定义系统&#xff1f; TinaSDK Kconfig界面配置 Tina Linux采用 Kconfig 机制对 SDK 和内核进行配置。 Kconfig 是一种固定格式的配置文件。Linux 编译环境中的 menuconfig 程序可以识别这种格式的配置文件&#xff0c;并提取出有效信息…

从力扣中等+困难题+表白HTML测试 -- 文心快码(Baidu Comate)

0 写在前面 &#xff08;通过如下链接/二维码进入官网注册&#xff0c;并在IDE使用三次及以上可以找我领计算机基础/ML/DL 面经/知识点一份~&#xff09; 官网地址&#xff1a;Baidu Comate Step1 打开文心快码&#xff08;Baidu Comate&#xff09;官网&#xff0c;点击「免…

[Python可视化]空气污染物浓度地图可视化

[Python可视化]空气污染物浓度地图可视化&#xff0c;果然是路边浓度最大 在本篇文章中&#xff0c;我将展示如何使用 Python 结合 OSMnx、NetworkX 和 GeoPandas 等库&#xff0c;计算给定路径的最短路线&#xff0c;并基于该路径穿过的网格单元计算总污染量。最终&#xff0c…