一、准备工作与基础知识
TDengine官网:https://www.taosdata.com/
1、服务器资源分配:
节点 |
操作系统 | TDengine版本 |
hostname |
IP | 备注 |
td1 | Centos7 | server-2.6.0.30 | td1.jiguiquan.com | 192.168.56.31 | 节点1 |
td2 | server-2.6.0.30 | td2.jiguiquan.com | 192.168.56.32 | 节点2 | |
td3 | server-2.6.0.30 | td3.jiguiquan.com | 192.168.56.33 | 节点3 | |
app | client-2.6.0.30 | app.jiguiquan.com | 192.168.56.34 | 测试用客户端 |
之所以选择2.0而不是3.0是因为,此时TDengine3.0是2022年9月才刚发布的,太不稳定了,而且API跟TDengine2.0相差太大,遇到问题,很难找到解决方案!
2、TDengine高可用逻辑架构和重点概念:
一个完整的 TDengine 系统是运行在一到多个物理节点上的,逻辑上,它包含数据节点(dnode)、TDengine 应用驱动(taosc)以及应用(app)。系统中存在一到多个数据节点(dnode),这些数据节点组成一个集群(cluster)。应用通过 taosc 的 API 与 TDengine 集群进行互动。
物理节点(pnode):就是指的我们部署用的服务器、虚拟机、docker容器等物理资源;
数据节点(dnode):dnode 是 TDengine 服务器侧执行代码 taosd 在物理节点上的一个运行实例,一个工作的系统必须有至少一个数据节点。dnode 包含零到多个逻辑的虚拟节点(vnode),零或者至多一个逻辑的管理节点(mnode),零或者至多一个逻辑的弹性计算节点(qnode),零或者至多一个逻辑的流计算节点(snode)。—— 可以理解为:物理节点上的一个TDEngine进程,所以一个物理节点(pnode)上可以多个数据节点(dnode);
虚拟节点(vnode):为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点(dnode)被虚拟化成多个虚拟节点(vnode,图中 V2,V3,V4 等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。—— 每个数据库在被创建时需要指定副本数,也就是vnode的数量,这些vnode共同由所属的vgroup管理;
管理节点(mnode):一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中 M)。同时,管理节点也负责元数据(包括用户、数据库、超级表等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过 3 个)mnode,它们自动构建成为一个虚拟管理节点组(图中 M1,M2,M3)。
虚拟节点组(vgroup):不同数据节点上的 vnode 可以组成一个虚拟节点组(vgroup),采用 RAFT 一致性协议,保证系统的高可用与高可靠。写操作只能在 leader vnode 上进行,系统采用异步复制的方式将数据同步到 follower vnode,这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个 DB 的副本数为 N,系统必须有至少 N 数据节点(dnode)。—— 有点类似于kafka的主题副本数必须 <= 节点数;
计算节点(qnode):一个虚拟的逻辑单元,运行查询计算任务,也包括基于系统表来实现的 show 命令(图中 Q)。集群中可配置多个 qnode,在整个集群内部共享使用(图中 Q1,Q2,Q3)。qnode 不与具体的 DB 绑定,即一个 qnode 可以同时执行多个 DB 的查询任务。每个 dnode 上至多有一个 qnode。
流计算节点(snode):一个虚拟的逻辑单元,只运行流计算任务(图中 S)。集群中可配置多个 snode,在整个集群内部共享使用(图中 S1,S2,S3)。snode 不与具体的 stream 绑定,即一个 snode 可以同时执行多个 stream 的计算任务。每个 dnode 上至多有一个 snode。
Taosc:taosc 是 TDengine 给应用提供的驱动程序(driver),负责处理应用与集群的接口交互,应用都是通过 taosc 而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据;将插入、查询等请求转发到正确的数据节点;在把结果返回给应用时,还需要负责最后一级的聚合、排序、过滤等操作。taosc模块是在客户端节点上运行的,可以与taosAdapter交互,支持全分布式的RESTful接口。
3、TDEngine2.0一个典型的消息插入过程泳道图:
1、应用通过 JDBC 或其他 API 接口发起插入数据的请求。
2、taosc 会检查缓存,看是否保存有该表的 meta data。如果有,直接到第 4 步。如果没有,taosc 将向 mnode 发出 get meta-data 请求。
3、mnode 将该表的 meta-data 返回给 taosc。Meta-data 包含有该表的 schema,而且还有该表所属的 vgroup 信息(vnode ID 以及所在的 dnode 的 End Point,如果副本数为 N,就有 N 组 End Point)。如果 taosc 迟迟得不到 mnode 回应,而且存在多个 mnode,taosc 将向下一个 mnode 发出请求。
4、taosc 向 master vnode 发起插入请求。
5、vnode 插入数据后,给 taosc 一个应答,表示插入成功。如果 taosc 迟迟得不到 vnode 的回应,taosc 会认为该节点已经离线。这种情况下,如果被插入的数据库有多个副本,taosc 将向 vgroup 里下一个 vnode 发出插入请求。
6、taosc 通知 APP,写入成功。
4、TDEngine3.0一个典型的消息插入过程泳道图:
1、应用通过 JDBC 或其他 API 接口发起插入数据的请求。
2、taosc 会检查缓存,看是否保存有该表所在数据库的 vgroup-info 信息。如果有,直接到第 4 步。如果没有,taosc 将向 mnode 发出 get vgroup-info 请求。
3、mnode 将该表所在数据库的 vgroup-info 返回给 taosc。Vgroup-info 包含数据库的 vgroup 分布信息(vnode ID 以及所在的 dnode 的 End Point,如果副本数为 N,就有 N 组 End Point),还包含每个 vgroup 中存储数据表的 hash 范围。如果 taosc 迟迟得不到 mnode 回应,而且存在多个 mnode,taosc 将向下一个 mnode 发出请求。
4、taosc 会继续检查缓存,看是否保存有该表的 meta-data。如果有,直接到第 6 步。如果没有,taosc 将向 vnode 发出 get meta-data 请求。
5、vnode 将该表的 meta-data 返回给 taosc。Meta-data 包含有该表的 schema。
6、taosc 向 leader vnode 发起插入请求。
7、vnode 插入数据后,给 taosc 一个应答,表示插入成功。如果 taosc 迟迟得不到 vnode 的回应,taosc 会认为该节点已经离线。这种情况下,如果被插入的数据库有多个副本,taosc 将向 vgroup 里下一个 vnode 发出插入请求。
8、taosc 通知 APP,写入成功。
-
关于第二步:taosc第一次启动时,不知道哪个节点是mnode,所以就直接访问配置中的集群对外提供服务的EP,如果被访问的dnode中并没有配置mnode,那么会在返回结果中告知taosc关于mnode的列表,这样taosc就可以去访问具体的mnode节点了!
-
关于第四步和第六步:taosc由于没有meta-data的缓存,不知道哪个vnode才是leader,那么会直接向列表中的第一个vnode发起请求,如果这个vnode不是leader,那么不会成功,在返回结果中会告诉哪一个vnode才是leader,这样taosc就可以去访问具体的leader节点了!
-
上面的整个过程已经被封装在taosc中了,用户无感,另外taosc的缓存机制,可以很大程度上地减少mnode的压力,但是为了防止元数据发生改变,taosc会定时与mnode交互并更新缓存!
-
很明显,TDengine3.0与TDengine2.0的很大不同就是mnode管理节点不再存储meta-data信息,而是存储vgroup-info,meta-data改由vnode存储,可以大大滴减轻mnode管理节点的压力!
二、TDengine高可用集群的部署
1、修改三台集群机器的hostname和hosts文件:
# 其他机器对应 [root@td1 ~]# hostnamectl set-hostname td1.jiguiquan.com [root@td2 ~]# hostnamectl set-hostname td2.jiguiquan.com [root@td3 ~]# hostnamectl set-hostname td3.jiguiquan.com [root@app ~]# hostnamectl set-hostname app.jiguiquan.com [root@td1 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.1.1 td1.jiguiquan.com td1 192.168.56.31 td1.jiguiquan.com 192.168.56.32 td2.jiguiquan.com 192.168.56.33 td3.jiguiquan.com
2、下载对应版本的server和client程序:
https://docs.taosdata.com/2.6/get-started/
将server安装包拷贝到集群节点,将client安装包拷贝到应用节点上;
3、解压3台server集群上的安装包并安装:
[root@td1 ~]# mkdir /tdengine [root@td1 ~]# cd /tdengine/ [root@td1 tdengine]# tar -zxvf TDengine-server-2.6.0.30-Linux-x64.tar.gz [root@td1 tdengine]# cd TDengine-server-2.6.0.30/ [root@td1 TDengine-server-2.6.0.30]# ls driver examples install.sh release_note taos.tar.gz
直接使用 install.sh,即可完成taosd的安装:
[root@td2 TDengine-server-3.0.1.6]# ./install.sh
这地方有2种方式:
节点1时候直接回车,节点2和节点3时候,填写td1.jiguiquan.com:6030;
所有节点都直接回车安装,之后再在节点2和节点3的配置文件/etc/taos/taos.cfg中修改;(我喜欢这种,安装与配置步骤独立开)
虽然安装成功了,但是此时taosd是没有启动的,先不要着急启动!
[root@td1 TDengine-server-2.6.0.30]# systemctl status taosd ● taosd.service - TDengine server service Loaded: loaded (/etc/systemd/system/taosd.service; enabled; vendor preset: disabled) Active: inactive (dead) Nov 14 16:44:57 td1.jiguiquan.com systemd[1]: Started TDengine server service. Nov 14 16:55:04 td1.jiguiquan.com systemd[1]: Stopping TDengine server service... Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: taosd.service: main process exited, code=killed, status=6/ABRT Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: Stopped TDengine server service. Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: Unit taosd.service entered failed state. Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: taosd.service failed. Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: Starting TDengine server service... Nov 14 16:55:06 td1.jiguiquan.com systemd[1]: Started TDengine server service. Nov 14 17:35:38 td1.jiguiquan.com systemd[1]: Stopping TDengine server service... Nov 14 17:35:40 td1.jiguiquan.com systemd[1]: Stopped TDengine server service.
4、修改 /etc/taos/taos.cfg 配置文件:
-
firstEp:每个数据节点首次启动后连接的第一个数据节点,此参数每个数据节点的配置一样;
-
fqdn:必须是每个数据节点本地得FQDN;
td1节点:
firstEp td1.jiguiquan.com:6030 fqdn td1.jiguiquan.com
td2节点:
firstEp td1.jiguiquan.com:6030 fqdn td2.jiguiquan.com
td3节点:
firstEp td1.jiguiquan.com:6030 fqdn td3.jiguiquan.com
3.0的这里有个坑(网上包括官网都是按照2.0的教程来的):
在TDengine2.0时候,supportVnodes不用配置,每个dnode支持的vnode数为1024个;
但是盗了TDengine3.0后,如果不配置,默认是cpu*2数量,而我的虚拟机分配的是2个CPU,那么默认的supportVnode=4;
而默认一个数据库副本会创建2个vnode,那么我随便创建一个3副本的数据库,就需要6个vnode,这样直接就会失败,所以一定要手动设置大一点!
5、启动第一个数据节点td1:
[root@td1 TDengine-server-2.6.0.30]# systemctl start taosd [root@td1 TDengine-server-2.6.0.30]# systemctl status taosd ● taosd.service - TDengine server service Loaded: loaded (/etc/systemd/system/taosd.service; enabled; vendor preset: disabled) Active: active (running) since Mon 2022-11-14 10:48:09 UTC; 4s ago Process: 23931 ExecStartPre=/usr/local/taos/bin/startPre.sh (code=exited, status=0/SUCCESS) Main PID: 23937 (taosd) CGroup: /system.slice/taosd.service ├─23937 /usr/bin/taosd └─23948 /usr/bin/udfd -c /etc/taos/ Nov 14 10:48:09 td1.jiguiquan.com systemd[1]: Starting TDengine server service... Nov 14 10:48:09 td1.jiguiquan.com systemd[1]: Started TDengine server service.
6、同样方式,我们快速地在app.jiguiquan.com这台机器上安装client客户端:
解压安装:
[root@td1 ~]# mkdir /tdengine [root@td1 ~]# cd /tdengine/ [root@app tdengine]# tar -zxvf TDengine-client-2.6.0.30-Linux-x64.tar.gz [root@app tdengine]# cd TDengine-client-2.6.0.30/ [root@app TDengine-client-2.6.0.30]# ls driver examples install_client.sh taos.tar.gz [root@app TDengine-client-2.6.0.30]# ./install_client.sh
修改/etc/hosts文件:
[root@app TDengine-client-2.6.0.30]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.1.1 app.jiguiquan.com app 192.168.56.31 td1.jiguiquan.com 192.168.56.32 td2.jiguiquan.com 192.168.56.33 td3.jiguiquan.com
7、现在我们就可以用客户端连接我们集群的第一个节点了:
[root@app ~]# taos -h td1.jiguiquan.com Welcome to the TDengine Command Line Interface, Client Version:3.0.1.6
执行一个简单查询:
taos> show dnodes; id| end_point | vnodes | cores | status | role | create_time | offline reason | ======================================================================================================= 1 | td1.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:48:49.678 | | Query OK, 1 row(s) in set (0.005056s)
可以看到现在只有一个数据节点!(注意这个id,如果后期要移除节点,就是使用这个id进行操作!)
8、将其他节点动态加入到td1创建的集群中:
启动td2、td3节点的taosd服务:
systemctl start taosd
通过taos客户端sql方式,向集群中添加新节点:
taos> create dnode "td2.jiguiquan.com:6030"; Query OK, 0 row(s) affected in set (0.001902s) taos> create dnode "td3.jiguiquan.com:6030"; Query OK, 0 row(s) affected in set (0.001275s)
现在查看查看集群中的dnode节点数:
taos> show dnodes; id| end_point | vnodes | cores | status | role | create_time | offline reason | ======================================================================================================= 1 | td1.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:48:49.678 | | 2 | td2.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:56:12.025 | | 3 | td3.jiguiquan.com:6030 | 0 | 2 | ready | any | 2022-11-14 17:56:16.203 | | Query OK, 1 row(s) in set (0.005056s)
9、补充:集群搭建常见问题:
加入集群的节点,处于offline状态可能的原因?
-
物理节点上的taosd服务没有正常启动;
-
网络不通,检查端口,防火墙,hosts等;
-
两个独立的集群无法合并为新的集群:即当后续节点加入集群时,如果 /var/lib/taos 目录下有数据,需要先清理掉后才可以成功加入集群;
rm -rf /var/lib/taos/
10、TDengine的卸载:
rmtaos # server和client卸载命令相同;
三、TDengine集群的使用
1、动态添加节点:
上面集群搭建过程中已经描述;
2、动态删除节点:
当节点上的taosd服务stop时,dnode状态会变味offline状态;
taos> show dnodes; id| end_point |vnodes|cores| status |role| create_time | offline reason | =================================================================================================== 1 | td1.jiguiquan.com:6030 | 1 | 2 | ready |any |2022-11-14 17:48:49.678 | | 2 | td2.jiguiquan.com:6030 | 1 | 2 | offline|any |2022-11-14 17:56:12.025 |status msg timeout| 3 | td3.jiguiquan.com:6030 | 0 | 2 | ready |any |2022-11-14 17:56:16.203 | | Query OK, 1 row(s) in set (0.005056s)
然后执行移除操作:
taos> drop dnode 2; Query OK, 0 row(s) affected in set (0.002013s) taos> show dnodes; id| end_point | vnodes | cores | status | role | create_time | offline reason | ======================================================================================================= 1 | td1.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:48:49.678 | | 3 | td3.jiguiquan.com:6030 | 0 | 2 | ready | any | 2022-11-14 17:56:16.203 | | Query OK, 1 row(s) in set (0.005056s)
测试成功后,我们再把td2加回来:
taos> show dnodes; id| end_point | vnodes | cores | status | role | create_time | offline reason | ======================================================================================================= 1 | td1.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:48:49.678 | | 2 | td2.jiguiquan.com:6030 | 1 | 2 | ready | any | 2022-11-14 17:56:12.025 | | 3 | td3.jiguiquan.com:6030 | 0 | 2 | ready | any | 2022-11-14 17:56:16.203 | | Query OK, 1 row(s) in set (0.005056s)
重新加入时,要记得清楚 /var/lib/taos/ 目录下的文件,同事重启taosd服务;
3、vnode虚拟节点的高可用(多副本):
创建一个3副本的testdb数据库(vnode副本数n <= dnode节点数):
taos> create database testdb replica 3; Query OK, 0 row(s) affected(0.002795s) taos> show databases; name | created_time | ntables | vgroups | replica | quorum | days | keep |...| status | ==================================================================================================== log | 2022-11-14 17:48:50.682 | 21 | 1 | 1 | 1 | 10 | 30 |...| ready | testdb| 2022-11-14 18:05:49.103 | 0 | 0 | 3 | 1 | 10 | 3650 |...| ready | Query OK, 2 row(s) in set (0.001787s) ## 可以看到testdb的备份数为3,此时还没有vgroup,当创建具体table的时候,就会产生对应的vnode和vgroup;
使用testdb数据库,创建数据表,查看具体的vnode状态:
taos> use testdb; Database changed. taos> show vgroups; Query OK, 0 row(s) in set (0.002732s) taos> create table test_table(ts timestamp, info binary(40)); Query OK, 0 row(s) affected(0.317088s) taos> insert into test_table values (now, "Hello jiguiquan!"); Query OK, 1 row(s) affected(0.008044s) taos> select * from test_table; ts | info | =========================================================== 2022-11-14 18:18:02.035 | Hello jiguiquan! | Query OK, 1 row(s) in set (0.003478s) taos> show vgroups; vgId| tables | status |onlines|v1_dnode|v1_status|v2_dnode|v2_status|v3_dnode|v3_status| compacting | ===================================================================================================== 3 | 1 | ready | 3 | 3 | leader | 1 |follower | 2 |follower | 0 | Query OK, 1 row(s) in set (0.001750s) ## 可以看到,dnodeId=3的节点为这个vgroup的leader节点,而dnodeId=1/2的节点为follower节点;
此时,我们测试停止vnodeId=3的节点的taosd服务。看看是否重新选举:
taos> show vgroups; vgId| tables | status |onlines|v1_dnode|v1_status|v2_dnode|v2_status|v3_dnode|v3_status| compacting | ===================================================================================================== 3 | 1 | ready | 3 | 3 | offline | 1 | leader | 2 |follower | 0 | Query OK, 1 row(s) in set (0.001750s) taos> select * from test_table; ts | info | =========================================================== 2022-11-14 18:18:02.035 | Hello jiguiquan! | Query OK, 1 row(s) in set (0.005275s) ## 可以看到,重新选举了dnodeId=1的节点为leader;
当dnodeId=3的节点恢复后,会自动加入集群,成为follower!
taos> show vgroups; vgId| tables | status |onlines|v1_dnode|v1_status|v2_dnode|v2_status|v3_dnode|v3_status| compacting | ===================================================================================================== 3 | 1 | ready | 3 | 3 |follower | 1 | leader | 2 |follower | 0 | Query OK, 1 row(s) in set (0.001750s)
4、mnode管理节点的高可用:
查询mnode管理节点列表:
taos> show mnodes; id| end_point | role | role_time | create_time | ========================================================================================= 1 | td1.jiguiquan.com:6030 | leader | 2022-11-14 18:53:11.793 | 2022-11-14 17:48:49.678 | Query OK, 1 row(s) in set (0.003479s) ## 明显,现在是有单点故障风险的。
所以我们需要修改 /etc/taos/taos.cfg 配置文件,增加mnode数量:
firstEp td1.jiguiquan.com:6030 fqdn td2.jiguiquan.com numOfMnodes 3
之后再次查看mnode列表:
taos> show mnodes; id| end_point | role | role_time | create_time | ========================================================================================= 1 | td1.jiguiquan.com:6030 | leader | 2022-11-14 18:53:11.793 | 2022-11-14 17:48:49.678 | 2 | td2.jiguiquan.com:6030 |follower| 2022-11-14 19:04:37.618 | 2022-11-14 19:04:29.740 | 3 | td3.jiguiquan.com:6030 |follower| 2022-11-14 19:04:48.374 | 2022-11-14 19:04:37.618 | Query OK, 1 row(s) in set (0.003479s)
此时,我们测试将tdnodeId=1的节点服务停止,看看是否重新选举;
# 此时,由于我们通过td2.jiguiquan.com这个节点接进来: taos> show mnodes; id| end_point | role | role_time | create_time | ========================================================================================= 1 | td1.jiguiquan.com:6030 |offline | 2022-11-14 18:53:11.793 | 2022-11-14 17:48:49.678 | 2 | td2.jiguiquan.com:6030 | leader | 2022-11-14 19:04:37.618 | 2022-11-14 19:04:29.740 | 3 | td3.jiguiquan.com:6030 |follower| 2022-11-14 19:04:48.374 | 2022-11-14 19:04:37.618 | Query OK, 1 row(s) in set (0.003479s) ## 可以看到,td1节点已经offline,td2被选为新的leader!
重启td1,会自动加入集群,变成follower:
taos> show mnodes; id| end_point | role | role_time | create_time | ========================================================================================= 1 | td1.jiguiquan.com:6030 |follower | 2022-11-14 18:53:11.793 | 2022-11-14 17:48:49.678 | 2 | td2.jiguiquan.com:6030 | leader | 2022-11-14 19:04:37.618 | 2022-11-14 19:04:29.740 | 3 | td3.jiguiquan.com:6030 |follower| 2022-11-14 19:04:48.374 | 2022-11-14 19:04:37.618 | Query OK, 1 row(s) in set (0.003479s)
5、对于客户端程序中我们配置连接的端点是固定的,岂不是有单点故障?
这点,client设计中已经考虑了,我们可以配置客户端的 /etc/taos/taos.cfg 配置文件,配置2个Ep:
[root@app ~]# vim /etc/taos/taos.cfg firstEp td1.jiguiquan.com:6030 secondEp td2.jiguiquan.com:6030
之后,客户端的连接即可直接变为:
[root@app ~]# taos
官方已经考虑到了!
关于java项目中如果使用TDengine的最佳实践,我会在另一篇文章中描述: