【转】TDengine踩坑随记(最后一次更新:2021-4-7 20:30)
原文:https://www.cnblogs.com/quchunhui/p/13731825.html
------------------------------------------------------------------------
==背景==
在搭建工業(yè)物聯(lián)網(wǎng)的數(shù)據(jù)平臺,用來完成設(shè)備連接以及數(shù)據(jù)存儲等,
以支持上層的應(yīng)用及數(shù)據(jù)分析等。目前使用的是mq→flink→influxdb的基本套路。
雖然說InfluxDB的性能和功能都非常的棒,特別是連續(xù)查詢對性能的支撐,
不過由于influxdb使用的是社區(qū)版,存在單點故障的問題,總之不是長久直接。
于是打算嘗試驗證一下陶老師的TDEngine。祝自己一切順利。
==環(huán)境==
服務(wù)器節(jié)點數(shù):3個(VMware虛擬機(jī))
操作系統(tǒng):Linux Centos8 64位
TDengine版本:2.0.4(2020年10月16日,使用版本換成了2.0.5.1)
JDK:1.8.0_77
JDBC客戶端版本建議:
tdengine:2.0.10.0,jdbc版本:2.0.15
tdengine:2.0.15.0,jdbc版本:2.0.18
==下載==
https://www.taosdata.com/cn/getting-started/
TDengine-server-2.0.4.0-Linux-x64.rpm TDengine-client-2.0.4.0-Linux-x64.tar.gz TDengine-alert-2.0.4.0-Linux-x64.tar.gz
==測試代碼==
所有程序的測試代碼放到了git上,需要的自取。
https://github.com/quchunhui/java-demo/tree/master/tdengine
==集群部署==
參考官網(wǎng):https://www.taosdata.com/cn/documentation/cluster/
PS:中文文檔是真的很爽,比看英文省心多了。
1、安裝server
上傳到服務(wù)器,并復(fù)制到各個節(jié)點,在各個節(jié)點執(zhí)行rpm安裝命令
命令:rpm -ivh TDengine-server-2.0.4.0-Linux-x64.rpm
【小插曲】
在另一個集群上安裝新的版本(2.0.7.0)的時候,發(fā)現(xiàn)如論如何也無法使新增加的節(jié)點上線,
后來看了新版本的文檔,上面提示:在增加新的節(jié)點時,先不要啟動taosd,安裝時,提示輸入是否要加入一個已經(jīng)存在的TDengine集群時,第一個物理節(jié)點直接回車創(chuàng)建新集群,后續(xù)物理節(jié)點則輸入該集群任何一個在線的物理節(jié)點的FQDN:端口號(默認(rèn)6030);
2、修改配置
配置文件路徑:/etc/taos/taos.cfg
配置文件說明:TDengine的運(yùn)營與維護(hù)
按照官網(wǎng)的提示,修改了幾個配置:firstEp、secondEp、fqdn、serverPort、logDir、dataDir、replica。
根據(jù)官網(wǎng)的說明,我羅列了配置的中文,供參考。沒有寫的是在這個版本的官網(wǎng)上沒有找到的了。
######################################################## # # # TDengine Configuration # # Any questions, please email support@taosdata.com # # # ######################################################## # first fully qualified domain name (FQDN) for TDengine system # taosd啟動時,主動連接的集群中第一個dnode的end point, 默認(rèn)值為localhost:6030。 firstEp vm1:6030 # second fully qualified domain name (FQDN) for TDengine system, for cluster only # taosd啟動時,如果first連接不上,嘗試連接集群中第二個dnode的end point, 默認(rèn)值為空。 secondEp vm2:6030 # local fully qualified domain name (FQDN) # 數(shù)據(jù)節(jié)點的FQDN,缺省為操作系統(tǒng)配置的第一個hostname。如果習(xí)慣IP地址訪問,可設(shè)置為該節(jié)點的IP地址。 fqdn vm1 # first port number for the connection (12 continuous UDP/TCP port number are used) # taosd啟動后,對外服務(wù)的端口號,默認(rèn)值為6030。 serverPort 6030 # log file's directory # 日志文件目錄,客戶端和服務(wù)器的運(yùn)行日志文件將寫入該目錄。默認(rèn)值:/var/log/taos。 logDir /home/radmin/data/tdengine/log # data file's directory # 數(shù)據(jù)文件目錄,所有的數(shù)據(jù)文件都將寫入該目錄。默認(rèn)值:/var/lib/taos。 dataDir /home/radmin/data/tdengine/data # the arbitrator's fully qualified domain name (FQDN) for TDengine system, for cluster only # 系統(tǒng)中裁決器的end point, 缺省值為空。 # arbitrator arbitrator_hostname:6042 # number of threads per CPU core # numOfThreadsPerCore 1.0 # number of management nodes in the system # 系統(tǒng)中管理節(jié)點個數(shù)。默認(rèn)值:3。 # numOfMnodes 3 # enable/disable backuping vnode directory when removing dnode # vnodeBak 1 # enable/disable load balancing # 是否啟動負(fù)載均衡。0:否,1:是。默認(rèn)值:1。 # balance 1 # role for dnode. 0 - any, 1 - mnode, 2 - dnode # dnode的可選角色。0-any; 既可作為mnode,也可分配vnode;1-mgmt;只能作為mnode,不能分配vnode;2-dnode;不能作為mnode,只能分配vnode # role 0 # max timer control blocks # maxTmrCtrl 512 # time interval of system monitor, seconds # monitorInterval 30 # number of seconds allowed for a dnode to be offline, for cluster only # dnode離線閾值,超過該時間將導(dǎo)致該dnode從集群中刪除。單位為秒,默認(rèn)值:86400*10(即10天)。 # offlineThreshold 8640000 # RPC re-try timer, millisecond # rpcTimer 300 # RPC maximum time for ack, seconds. # rpcMaxTime 600 # time interval of dnode status reporting to mnode, seconds, for cluster only # statusInterval 1 # time interval of heart beat from shell to dnode, seconds # shellActivityTimer 3 # time of keeping table meta data in cache, seconds # tableMetaKeepTimer 7200 # minimum sliding window time, milli-second # minSlidingTime 10 # minimum time window, milli-second # minIntervalTime 10 # maximum delay before launching a stream compution, milli-second # maxStreamCompDelay 20000 # maximum delay before launching a stream computation for the first time, milli-second # maxFirstStreamCompDelay 10000 # retry delay when a stream computation fails, milli-second # retryStreamCompDelay 10 # the delayed time for launching a stream computation, from 0.1(default, 10% of whole computing time window) to 0.9 # streamCompDelayRatio 0.1 # max number of vgroups per db, 0 means configured automatically # 每個數(shù)據(jù)庫中能夠使用的最大vnode個數(shù)。 # maxVgroupsPerDb 0 # max number of tables per vnode # 每個vnode中能夠創(chuàng)建的最大表個數(shù)。默認(rèn)值:1000000。 # maxTablesPerVnode 1000000 # step size of increasing table number in a vnode # tableIncStepPerVnode 1000 # cache block size (Mbyte) # cache 16 # number of cache blocks per vnode # blocks 6 # number of days per DB file # 一個數(shù)據(jù)文件存儲數(shù)據(jù)的時間跨度,單位為天,默認(rèn)值:10。 # days 10 # number of days to keep DB file # 數(shù)據(jù)庫中數(shù)據(jù)保留的天數(shù),單位為天,默認(rèn)值:3650。 # keep 3650 # minimum rows of records in file block # 文件塊中記錄的最小條數(shù),單位為條,默認(rèn)值:100。 # minRows 100 # maximum rows of records in file block # 文件塊中記錄的最大條數(shù),單位為條,默認(rèn)值:4096。 # maxRows 4096 # enable/disable compression # 文件壓縮標(biāo)志位,0:關(guān)閉,1:一階段壓縮,2:兩階段壓縮。默認(rèn)值:2。 # comp 2 # write ahead log (WAL) level, 0: no wal; 1: write wal, but no fysnc; 2: write wal, and call fsync # WAL級別。1:寫wal, 但不執(zhí)行fsync; 2:寫wal, 而且執(zhí)行fsync。默認(rèn)值:1。 # walLevel 1 # if walLevel is set to 2, the cycle of fsync being executed, if set to 0, fsync is called right away # 當(dāng)wal設(shè)置為2時,執(zhí)行fsync的周期。設(shè)置為0,表示每次寫入,立即執(zhí)行fsync。單位為毫秒,默認(rèn)值:3000。 # fsync 3000 # number of replications, for cluster only # 副本個數(shù),取值范圍:1-3。單位為個,默認(rèn)值:1 replica 3 # mqtt hostname # mqttHostName test.mosquitto.org # mqtt port # mqttPort 1883 # mqtt topic # mqttTopic /test # the compressed rpc message, option: # -1 (no compression) # 0 (all message compressed), # > 0 (rpc message body which larger than this value will be compressed) # compressMsgSize -1 # max length of an SQL # 單條SQL語句允許最長限制。默認(rèn)值:65380字節(jié)。 maxSQLLength 1048576 # the maximum number of records allowed for super table time sorting # maxNumOfOrderedRes 100000 # system time zone # 默認(rèn)值:從系統(tǒng)中動態(tài)獲取當(dāng)前的時區(qū)設(shè)置 # timezone Asia/Shanghai (CST, +0800) # system locale # 默認(rèn)值:系統(tǒng)中動態(tài)獲取,如果自動獲取失敗,需要用戶在配置文件設(shè)置或通過API設(shè)置 # locale en_US.UTF-8 # default system charset # 默認(rèn)值:系統(tǒng)中動態(tài)獲取,如果自動獲取失敗,需要用戶在配置文件設(shè)置或通過API設(shè)置 # charset UTF-8 # max number of connections allowed in dnode # maxShellConns 5000 # max numerber of connections allowed in client # maxConnections 5000 # stop writing logs when the disk size of the log folder is less than this value # minimalLogDirGB 0.1 # stop writing temporary files when the disk size of the log folder is less than this value # minimalTmpDirGB 0.1 # stop writing data when the disk size of the log folder is less than this value # minimalDataDirGB 0.1 # enbale/disable http service # http 1 # enable/disable muqq service # mqtt 0 # enable/disable system monitor # monitor 1 # enable/disable recording the SQL statements via restful interface # httpEnableRecordSql 0 # number of threads used to process http requests # httpMaxThreads 2 # maximum number of rows returned by the restful interface # restfulRowLimit 10240 # The following parameter is used to limit the maximum number of lines in log files. # max number of rows per log filters # 單個日志文件允許的最大行數(shù)。默認(rèn)值:10,000,000行。 # numOfLogLines 10000000 # time of keeping log files, days # 日志文件的最長保存時間。大于0時,日志文件會被重命名為taosdlog.xxx,其中xxx為日志文件最后修改的時間戳,單位為秒。默認(rèn)值:0天。 # logKeepDays 0 # enable/disable async log # asyncLog 1 # The following parameters are used for debug purpose only. # debugFlag 8 bits mask: FILE-SCREEN-UNUSED-HeartBeat-DUMP-TRACE_WARN-ERROR # 131: output warning and error, 135: output debug, warning and error, 143 : output trace, debug, warning and error to log. # 199: output debug, warning and error to both screen and file # 207: output trace, debug, warning and error to both screen and file # debug flag for all log type, take effect when non-zero value # debugFlag 0 # debug flag for meta management messages # mDebugFlag 135 # debug flag for dnode messages # dDebugFlag 135 # debug flag for sync module # sDebugFlag 135 # debug flag for WAL # wDebugFlag 135 # debug flag for SDB # sdbDebugFlag 135 # debug flag for RPC # rpcDebugFlag 131 # debug flag for TAOS TIMER # tmrDebugFlag 131 # debug flag for TDengine client # cDebugFlag 131 # debug flag for JNI # jniDebugflag 131 # debug flag for ODBC # odbcDebugflag 131 # debug flag for storage # uDebugflag 131 # debug flag for http server # httpDebugFlag 131 # debug flag for mqtt # mqttDebugFlag 131 # debug flag for monitor # monitorDebugFlag 131 # debug flag for query # qDebugflag 131 # debug flag for vnode # vDebugflag 131 # debug flag for http server # tsdbDebugFlag 131 # enable/disable recording the SQL in taos client # tscEnableRecordSql 0 # generate core file when service crash # enableCoreFile 1 # maximum display width of binary and nchar fields in the shell. The parts exceeding this limit will be hidden # maxBinaryDisplayWidth 30
PS:到此的感受:
總體感覺TDengine的安裝非常容易,配置文件也簡單易懂,到此體驗良好。
==啟動==
1、啟動第1個節(jié)點
命令:systemctl start taosd
2、驗證第1個節(jié)點是否啟動成功
命令:taos
命令:show dnodes;
3、啟動后續(xù)數(shù)據(jù)節(jié)點
先將后兩個節(jié)點的服務(wù)啟動起來。
在每個節(jié)點執(zhí)行:systemctl start taosd
確認(rèn)服務(wù)狀態(tài):systemctl status taosd
如下圖,第2個節(jié)點的服務(wù)正常:
第3個節(jié)點的服務(wù)正常:
【小插曲】
在啟動第2個節(jié)點的時候報錯,
[root@vm2 ~]# systemctl status taosd ● taosd.service - TDengine server service Loaded: loaded (/etc/systemd/system/taosd.service; enabled; vendor preset: disabled) Active: failed (Result: start-limit) since Tue 2020-09-29 20:38:20 UTC; 2s ago Process: 5095 ExecStart=/usr/bin/taosd (code=exited, status=1/FAILURE) Main PID: 5095 (code=exited, status=1/FAILURE) Sep 29 20:38:20 vm2 systemd[1]: taosd.service: main process exited, code=exited, status=1/FAILURE Sep 29 20:38:20 vm2 systemd[1]: Unit taosd.service entered failed state. Sep 29 20:38:20 vm2 systemd[1]: taosd.service failed. Sep 29 20:38:20 vm2 systemd[1]: taosd.service holdoff time over, scheduling restart. Sep 29 20:38:20 vm2 systemd[1]: Stopped TDengine server service. Sep 29 20:38:20 vm2 systemd[1]: start request repeated too quickly for taosd.service Sep 29 20:38:20 vm2 systemd[1]: Failed to start TDengine server service. Sep 29 20:38:20 vm2 systemd[1]: Unit taosd.service entered failed state. Sep 29 20:38:20 vm2 systemd[1]: taosd.service failed.
【原因】
沒有創(chuàng)建log和data的文件路徑,在第2個和第3個節(jié)點上分別創(chuàng)建兩個路徑
mkdir -p /home/radmin/data/tdengine/log
mkdir -p /home/radmin/data/tdengine/data
4、添加節(jié)點
在第一個數(shù)據(jù)節(jié)點,使用CLI程序taos, 登錄進(jìn)TDengine系統(tǒng), 執(zhí)行命令:
CREATE DNODE "vm2:6030"; CREATE DNODE "vm3:6030";
查看新的節(jié)點是否加入進(jìn)來。
【小插曲】
執(zhí)行show dnodes;之后,發(fā)現(xiàn)vm2這個節(jié)點處于offline狀態(tài)。按照官網(wǎng)提示的方法:
查看日志中提示如下錯誤:
09/29 20:59:55.055274 0x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent 09/29 20:59:56.060418 0x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent 09/29 20:59:57.065157 0x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent
【原因】
經(jīng)過群里的咨詢,有朋友建議排查一下時區(qū)是否一致,經(jīng)排查第2個節(jié)點的時區(qū)確實與另外兩個不一致。
修改了一下時區(qū)之后,從新啟動第2個節(jié)點,發(fā)現(xiàn)狀態(tài)恢復(fù)正常。修改時區(qū)命令:
mv /etc/localtime /etc/localtime.bak ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/locaktime
【小插曲2】
解決了上面的小插曲,非常的開心,合上筆記本電腦回家。
回家之后,重新連接上服務(wù)器,查看狀態(tài),結(jié)果發(fā)現(xiàn)第2個節(jié)點的狀態(tài)又變成offline了,真是開心不過3分鐘啊。
【原因】
發(fā)現(xiàn)時間貌似不同步。看來是時候加上NTP時間同步了。按照以下步驟嘗試了一下
1)停掉taos服務(wù)
2)配置ntp同步(參考我的另一篇博客:Linux配置ntp時間服務(wù)器)
3)重啟taos服務(wù)
重啟之后,第2個節(jié)點的狀態(tài)恢復(fù)為ready,開森。
為了以防萬一,將系統(tǒng)放置了一整夜,第2天早上起來查看集群狀態(tài),依然是正常的,這下才算放心。
【感謝道友】
5、數(shù)據(jù)節(jié)點管理命令
添加數(shù)據(jù)節(jié)點:CREATE DNODE "fqdn:port"; 刪除數(shù)據(jù)節(jié)點:DROP DNODE "fqdn:port"; 查看數(shù)據(jù)節(jié)點:SHOW DNODES;
PS:到此的感受
TDengine的集群部署也非常的簡單,比傳統(tǒng)的HBase,MongoDB之類的簡單的多,感受不錯。
唯一比較大的遺憾是,目前的社區(qū)版不支持多級存儲,我們實際項目中磁盤是插滿的,
如果要利用磁盤空間,就必須要加上lvm,但是lvm會影響讀寫速度,對已經(jīng)存在的hdfs也有一些影響。
6、集群卸載
因為是用rpm的格式安裝的,目前用的是yum remove來卸載,不清楚是否為最佳卸載方式。
systemctl stop taosd
rpm -qa | grep TD
yum removeTDengine-2.0.5.0-3.x86_64
2020年11月10日
卸載了2.0.5.0版本,重新安裝了2.0.7.0版本,和上面的步驟一樣
1、停止集群
2、卸載td
3、沖洗安裝
【小插曲】
在這次重新安裝的時候,遇到了下面的問題。在Git上提了issue:https://github.com/taosdata/TDengine/issues/4168
說是需要安裝python環(huán)境,可是我又沒有用到python,而且2.0.5.0的時候還沒有這個問題。
所以,tdengine的版本更新是不是太快了,導(dǎo)致一些問題沒能充分測試呢?
error: Failed dependencies:
/usr/bin/python is needed by tdengine-2.0.7.0-3.x86_64
解決過程:
按照提示,安裝了3.8.6版本的python,并確認(rèn)了python安裝沒有問題,嘗試重新安裝tdengine,仍然報了同樣的錯誤,
后來和官方的人員確認(rèn)過了,應(yīng)該是官網(wǎng)放的release包有點問題,他們重新更新了一個包之后就可以了,
而且不需要安裝python,不需要安裝python,不需要安裝python。
==TAOS SQL==
官網(wǎng)提供了完整的文檔,官網(wǎng)地址:https://www.taosdata.com/cn/documentation20/taos-sql/
我個人習(xí)慣了逐個嘗試驗證一遍,以加深印象,好記性不如爛筆頭。
另外,可以通過官方提供的樣例數(shù)據(jù)創(chuàng)建一些表供驗證。
命令:taosdemo(注意,需要預(yù)留大約2.1GB的存儲空間)
1、數(shù)據(jù)庫管理
#創(chuàng)建庫:
#COMP參數(shù)是指修改數(shù)據(jù)庫文件壓縮標(biāo)志位,取值范圍為[0, 2]. 0表示不壓縮,1表示一階段壓縮,2表示兩階段壓縮。
#REPLICA參數(shù)是指修改數(shù)據(jù)庫副本數(shù),取值范圍[1, 3]。在集群中使用,副本數(shù)必須小于dnode的數(shù)目。
#KEEP參數(shù)是指修改數(shù)據(jù)文件保存的天數(shù),缺省值為3650,取值范圍[days, 365000],必須大于或等于days參數(shù)值。
#QUORUM參數(shù)是指數(shù)據(jù)寫入成功所需要的確認(rèn)數(shù)。取值范圍[1, 3]。對于異步復(fù)制,quorum設(shè)為1,具有master角色的虛擬節(jié)點自己確認(rèn)即可。對于同步復(fù)制,需要至少大于等于2。原則上,Quorum >=1 并且 Quorum <= replica(副本數(shù)),這個參數(shù)在啟動一個同步模塊實例時需要提供。
#BLOCKS參數(shù)是每個VNODE (TSDB) 中有多少cache大小的內(nèi)存塊,因此一個VNODE的用的內(nèi)存大小粗略為(cache * blocks)。取值范圍[3, 1000]。
#DAYS一個數(shù)據(jù)文件存儲數(shù)據(jù)的時間跨度,單位為天,默認(rèn)值:10。
create database mydb keep 365 days 10 blocks 4; #創(chuàng)建庫(如果不存在): create database if not exists mydb keep 365 days 10 blocks 4; #使用庫: use mydb; #刪除庫: drop database mydb; #刪除庫(如果存在): drop database if exists mydb; #顯示所有數(shù)據(jù)庫: show databases; #修改數(shù)據(jù)庫文件壓縮標(biāo)志位: alter database mydb comp 2; #修改數(shù)據(jù)庫副本數(shù): alter database mydb replica 2; #修改數(shù)據(jù)文件保存的天數(shù): alter database mydb keep 365; #修改數(shù)據(jù)寫入成功所需要的確認(rèn)數(shù): alter database mydb quorum 2; #修改每個VNODE (TSDB) 中有多少cache大小的內(nèi)存塊: alter database mydb blocks 100;
2、表管理
#創(chuàng)建表(搞了個包含所有數(shù)據(jù)類型的表): create table if not exists mytable(time timestamp, intfield int, bigintfield bigint, floatfield float, doublefield double, binaryfield binary(20), smallintfield smallint, tinyintfield tinyint, boolfield bool, ncharfiel d nchar(50)); #刪除數(shù)據(jù)表 drop table if exists mytable; #顯示當(dāng)前數(shù)據(jù)庫下的所有數(shù)據(jù)表信息 show tables; #顯示當(dāng)前數(shù)據(jù)庫下的所有數(shù)據(jù)表信息 #可在like中使用通配符進(jìn)行名稱的匹配。通配符匹配:1)’%’ (百分號)匹配0到任意個字符;2)’_’下劃線匹配一個字符。 show tables like "%my%"; #獲取表的結(jié)構(gòu)信息 describe mytable; #表增加列 alter table mytable add column addfield int; #表刪除列 alter table mytable drop column addfield;
注意:表名一定不要用數(shù)字開頭,官方文檔明確提醒了。
3、超級表管理
#創(chuàng)建超級表 #創(chuàng)建STable, 與創(chuàng)建表的SQL語法相似,但需指定TAGS字段的名稱和類型。說明: #1) TAGS 列的數(shù)據(jù)類型不能是timestamp類型; #2) TAGS 列名不能與其他列名相同; #3) TAGS 列名不能為預(yù)留關(guān)鍵字; #4) TAGS 最多允許128個,可以0個,總長度不超過16k個字符 create table if not exists mysupertable (time timestamp, intfield int, bigintfield bigint, floatfield float, doublefield double, binaryfield binary(20), smallintfield smallint, tinyintfield tinyint, boolfield bool, nch arfield nchar(50)) TAGS (product nchar(50), device nchar(100)); #刪除超級表 drop table if exists mysupertable; #顯示當(dāng)前數(shù)據(jù)庫下的所有超級表信息 show stables like "%super%"; #獲取超級表的結(jié)構(gòu)信息 describe mysupertable; #超級表增加列 alter table mysupertable add column addfield int; #超級表刪除列 alter table mysupertable drop column addfield; #添加標(biāo)簽 alter table mysupertable add tag devicetype nchar(60); #刪除標(biāo)簽 alter table mysupertable drop tag devicetype; #修改標(biāo)簽名 alter table mysupertable change tag product productKey; #修改子表標(biāo)簽值 #說明:除了更新標(biāo)簽的值的操作是針對子表進(jìn)行,其他所有的標(biāo)簽操作(添加標(biāo)簽、刪除標(biāo)簽等)均只能作用于STable,不能對單個子表操作。對STable添加標(biāo)簽以后,依托于該STable建立的所有表將自動增加了一個標(biāo)簽,所有新增標(biāo)簽的默認(rèn)值都是NULL。 alter table mysupertable set tag productkey="abc";
【小插曲】
執(zhí)行了一個下面的創(chuàng)建超級表的語句(通過自己寫的程序生成的),結(jié)果報錯
SQL語句:create table if not exists AI_PICK_UDATA ( time timestamp, data double ) tags ( productKey binary(256),deviceName binary(256),pointId binary(256),name binary(256),dataType binary(256),min binary(256),max binary(256),step binary(256),unit binary(256),description binary(256) );
提示錯誤:DB error: invalid SQL: invalid tag name
【問題原因】
創(chuàng)建表的語句中有tdengine的保留字段,如min,max。
但是官方文檔上并沒有對此進(jìn)行相關(guān)介紹,吐槽一下文檔。
4、數(shù)據(jù)插入
#插入一條數(shù)據(jù) insert into mytable values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s"); #插入一條記錄,數(shù)據(jù)對應(yīng)到指定的列 insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s"); #插入多條記錄 insert into mytable values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t"); #按指定的列插入多條記錄 insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t"); #向多個表插入多條記錄(本人沒有驗證此語句) INSERT INTO tb1_name VALUES (field1_value1, ...)(field1_value2, ...) tb2_name VALUES (field1_value1, ...)(field1_value2, ...); #同時向多個表按列插入多條記錄(本人沒有驗證此語句) INSERT INTO tb1_name (tb1_field1_name, ...) VALUES (field1_value1, ...) (field1_value2, ...) tb2_name (tb2_field1_name, ...) VALUES (field1_value1, ...) (field1_value2, ...);
【小插入】
插入多條記錄的時候,語句中寫的是兩條數(shù)據(jù),實際上只插入了一條
插入語句:
insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t");
【原因】
需要使用不同的時間戳,如果兩條語句都使用now,時間戳一樣,最終只能插入一條。
【感謝道友】
5、數(shù)據(jù)查詢
查詢語法:
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file]
==查詢語句==
查詢語法:
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file]
常用查詢語句樣例:
#查詢表中的所有字段 select * from t_znsllj001; #按照時間戳查詢表中的所有字段 select * from t_znsllj001 where time > "2020-10-10 22:23:08.728"; #按照時間戳查詢超級表中的所有字段 select * from st_znsllj where time > "2020-10-10 22:23:08.728"; #查詢超級表中的指定字段 select time, forwardintegratedflow, product from st_znsllj; #按照標(biāo)簽值查詢超級表中的指定字段 select time, forwardintegratedflow, product from st_znsllj where product = "product1"; #查詢結(jié)果按照時間倒序排序 select time, forwardintegratedflow, product from st_znsllj where product = "product1" order by time desc; #結(jié)果集列名重命名 select time, forwardintegratedflow as ff, product from st_znsllj; #查詢超級表數(shù)據(jù)并附帶表名(TBNAME: 在超級表查詢中可視為一個特殊的標(biāo)簽,代表查詢涉及的子表名,不區(qū)分大小寫) select tbname, * from st_znsllj; #查詢超級表的表名及第一列 select tbname, _c0 from st_znsllj; #獲取當(dāng)前所在的數(shù)據(jù)庫 select database(); #獲取客戶端版本號 select client_version() #獲取服務(wù)器版本號 select server_version(); #服務(wù)器狀態(tài)檢測語句 select server_status() #統(tǒng)計超級表下轄子表數(shù)量 select count(tbname) from st_znsllj;
==用戶管理==
#創(chuàng)建用戶,并指定用戶名和密碼,密碼需要用單引號引起來,單引號為英文半角 create user admin pass 'admin123'; #刪除用戶,限r(nóng)oot用戶使用 drop user admin; #修改用戶密碼, 為避免被轉(zhuǎn)換為小寫,密碼需要用單引號引用,單引號為英文半角 alter user admin pass 'admin1234'; #修改用戶權(quán)限為:super/write/read。 為避免被轉(zhuǎn)換為小寫,密碼需要用單引號引用,單引號為英文半角 #語法:ALTER USER <user_name> PRIVILEGE <super|write|read>; alter user admin privilege read;
如果修改了root密碼之后,進(jìn)入命令行的命令就需要加上密碼的參數(shù)了。
可以通過taos --usage查看命令行的參數(shù)格式:
如:修改了密碼之后,可以通過以下命令來登錄命令行
taos --user=root -p'RexelRoot!@#'
==Java連接==
官網(wǎng)地址:https://www.taosdata.com/cn/documentation/connector-java/
1、maven配置
<dependency> <groupId>com.taosdata.jdbc</groupId> <artifactId>taos-jdbcdriver</artifactId> <version>2.0.4</version> </dependency>
2、JDBC連接樣例
【TdUtils.java】
單例工具類,實現(xiàn)創(chuàng)建連接等通用方法。
package com.rexel.tdengine.utils;
import com.taosdata.jdbc.TSDBDriver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* @ClassName TdUtils
* @Description TDengine共通類
* @Author: chunhui.qu
* @Date: 2020/9/30
*/
public class TdUtils {
private Connection connection = null;
/**
* 構(gòu)造函數(shù)
*/
private TdUtils() {
// do nothing
}
/**
* 單例模式
*/
private static class SingletonInstance {
private static final TdUtils INSTANCE = new TdUtils();
}
/**
* 獲取對象句柄
*/
public static TdUtils getInstance() {
return SingletonInstance.INSTANCE;
}
public Connection getConnection() {
if (connection != null) {
return connection;
}
try {
Class.forName("com.taosdata.jdbc.TSDBDriver");
String jdbcUrl = "jdbc:TAOS://rexel-ids001:6030/qch_test?user=root&password=taosdata";
Properties connProps = new Properties();
connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, "C:\TDengine\cfg");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "Asia/Shanghai");
connection = DriverManager.getConnection(jdbcUrl, connProps);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
}
【CreateDatabase.java】
創(chuàng)建數(shù)據(jù)的樣例程序。
package com.rexel.tdengine.api;
import com.rexel.tdengine.utils.TdUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @ClassName CreateDatabase
* @Description CreateDatabase
* @Author: chunhui.qu
* @Date: 2020/9/30
*/
public class CreateDatabase {
public static void main(String[] args) throws SQLException {
TdUtils tdUtils = TdUtils.getInstance();
Connection conn = tdUtils.getConnection();
if (conn == null) {
return;
}
System.out.println("get connection");
Statement stmt = conn.createStatement();
if (stmt == null) {
return;
}
stmt.executeUpdate("create database if not exists javatestdb");
System.out.println("create database");
stmt.executeUpdate("use javatestdb");
System.out.println("use database");
stmt.executeUpdate("create table if not exists javatesttable (ts timestamp, temperature int, humidity float)");
System.out.println("create table");
}
}
【小插曲1】
寫完了測試代碼,在執(zhí)行的時候報錯:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no taos in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at com.taosdata.jdbc.TSDBJNIConnector.<clinit>(TSDBJNIConnector.java:25)
at com.taosdata.jdbc.TSDBDriver.connect(TSDBDriver.java:133)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at com.rexel.tdengine.utils.TdUtils.getConnection(TdUtils.java:54)
at com.rexel.tdengine.api.CreateDatabase.main(CreateDatabase.java:17)
Disconnected from the target VM, address: '127.0.0.1:54954', transport: 'socket'
【解決過程】
重新看了一下官方文檔,懷疑是沒有安裝Window客戶端,嘗試安裝客戶端程序。
安裝文件:TDengine-client-2.0.4.0-Windows-x64.exe
重新執(zhí)行程序之后,報了另一個錯誤:
java.sql.SQLException: TDengine Error: Invalid timestamp
at com.taosdata.jdbc.TSDBJNIConnector.connect(TSDBJNIConnector.java:100)
at com.taosdata.jdbc.TSDBConnection.connect(TSDBConnection.java:64)
at com.taosdata.jdbc.TSDBConnection.<init>(TSDBConnection.java:56)
at com.taosdata.jdbc.TSDBDriver.connect(TSDBDriver.java:135)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at com.rexel.tdengine.utils.TdUtils.getConnection(TdUtils.java:54)
at com.rexel.tdengine.api.CreateDatabase.main(CreateDatabase.java:17)
網(wǎng)友說可能是因為客戶端的時間與服務(wù)器時間相差比較多的原因,
于是調(diào)整了服務(wù)器的時間。命令如下,調(diào)整之后,重啟了一下服務(wù)器
修改系統(tǒng)時間:date --set "09/30/20 14:15" 系統(tǒng)時間向硬件同步:clock --show
重新運(yùn)行程序,正確執(zhí)行。感謝網(wǎng)友的幫助。
【感謝道友】
【小插曲2】
本來運(yùn)行的好好的,debug也都沒有問題,但是下午去酒店再debug測試,就提示“Unable to establish connection”
按照官網(wǎng)的FAQ提示,一頓檢查,沒有發(fā)現(xiàn)什么問題,非常迷惑。
后來想到由于服務(wù)器用的是阿里云ECS,需要配置網(wǎng)絡(luò)安全組的IP地址白名單,
我配置的時候只配置了TCP,沒有配置UDP,配置上了UCP的權(quán)限之后,debug就恢復(fù)正常了。
3、插入數(shù)據(jù)樣例
我這里寫了一個JSON字符串轉(zhuǎn)換為SQL,并持續(xù)插入的樣例。
package com.rexel.tdengine.api;
import com.alibaba.fastjson.JSONObject;
import com.rexel.tdengine.utils.TdUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* @ClassName CreateDatabase
* @Description CreateDatabase
* @Author: chunhui.qu
* @Date: 2020/10/12
*/
public class InsertJson {
public static void main(String[] args) throws SQLException {
TdUtils tdUtils = TdUtils.getInstance();
Connection conn = tdUtils.getConnection();
if (conn == null) {
return;
}
System.out.println("get connection");
Statement stmt = conn.createStatement();
if (stmt == null) {
return;
}
List<String> aiList = new ArrayList<String>(){{
add("AI_PICK_UDATA");
add("AI_PROD_NPER");
add("AI_PROD_NPICK");
add("AI_PRODUCT_EFF");
add("AI_PRODUCT_QUANTITY");
add("AI_PRODUCT_TIME_MIN");
add("AI_PROD_NPRODING");
}};
List<String> diList = new ArrayList<String>(){{
add("DI_BELOWCLOSTS");
add("DI_BELOWOPNSTS");
add("DI_CANDY_OUTBEELINEA");
add("DI_CANDY_OUTBEELINEB");
add("DI_CANDY_OUTBEELINEC");
add("DI_CHUCKCLOSTS");
add("DI_CHUCKOPNSTS");
add("DI_COVERCLOSTS");
add("DI_COVEROPNSTS");
add("DI_CTNCLO_BSTART");
add("DI_CTNOPN_BSTART");
add("DI_DENSO_BAUTOST");
add("DI_DENSO_BERROR");
add("DI_DENSO_BMOTORONST");
add("DI_DENSO_BREADY");
add("DI_DENSO_BRUNNING");
add("DI_EPSON_BERROR");
add("DI_EPSON_BESTOPON");
add("DI_EPSON_BMOTORONST");
add("DI_EPSON_BREADY");
add("DI_EPSON_BRUNNING");
add("DI_LEFTPUSHCLOSTS");
add("DI_LEFTPUSHOPNSTS");
add("DI_PRINT_BRUNNING");
add("DI_RIGHTCLOSTS");
add("DI_RIGHTOPNSTS");
add("DI_RIGHTPUSHCLOSTS");
add("DI_RIGHTPUSHLOPN");
add("DI_RLCLOSTS");
add("DI_RLOPNSTS");
add("DI_ROBOT1_BLINKSTS");
add("DI_ROBOT1_BSTART");
add("DI_ROBOT2_BLINKSTS");
add("DI_ROBOT2TOSTOR");
add("DI_ROBOT2TOWAI");
add("DI_SYS_BRUNNING");
add("DI_TOPCLOSTS");
add("DI_TOPOPNSTS");
add("DI_UPDOWNCLOSTS");
add("DI_UPDOWNOPNSTS");
add("DI_BBELTSENSOROVT");
add("DI_BCTNCLOCOOPNOVT");
add("DI_BCTNCLORCLOOVT");
add("DI_BCTNCLOROPNOVT");
add("DI_BCTNCLOTCLOOVT");
add("DI_BCTNCLOTOPNOVT");
add("DI_BCTNOVT");
add("DI_BELOWVALCLOOVT");
add("DI_BELOWVALOPNOVT");
add("DI_BROBOT2VALCLOVT");
add("DI_BROBOT2VALOPOVT");
add("DI_BRTSUCKEROVT");
add("DI_BVALCOVERCLOOVT");
add("DI_CHUCJVALCLOOVT");
add("DI_CHUCJVALOPOVT");
add("DI_CHUCKVALOPNOVT");
add("DI_DENSOBERROR");
add("DI_EPSONBERROR");
add("DI_INSENCTNALARM");
add("DI_LEFTNEWVALCLOVT");
add("DI_RLNEWOPVALOPOVT");
add("DI_RLNEWVALCLOOVT");
add("DI_UPDOWNNVALCLOVT");
add("DI_UPDOWNNVALOPOVT");
}};
int count = 0;
while(true) {
Random intRandom = new Random();
JSONObject demoJson = new JSONObject();
demoJson.put("table", "device_data_up");
demoJson.put("time", System.currentTimeMillis());
JSONObject tagJson = new JSONObject();
tagJson.put("productKey", "a1B6t6ZG6oR");
tagJson.put("deviceName", "QCHTestDevice1");
demoJson.put("tags", tagJson);
JSONObject dataJson = new JSONObject();
aiList.forEach(field -> dataJson.put(field, intRandom.nextInt(10000)));
diList.forEach(field -> dataJson.put(field, intRandom.nextInt(2)));
demoJson.put("datas", dataJson);
String sql = jsonToSql(demoJson);
stmt.executeUpdate(sql);
count ++;
System.out.println("executeUpdate. count=" + count + ", sql=" + sql);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static String jsonToSql(JSONObject jsonObject) {
String sql = "insert into {table} ({fields}) values ({values});";
sql = sql.replace("{table}", getTable(jsonObject));
sql = sql.replace("{fields}", getFields(jsonObject));
return sql.replace("{values}", getValues(jsonObject));
}
private static String getTable(JSONObject jsonObject) {
return "t_" + jsonObject.getString("table");
}
private static String getTime(JSONObject jsonObject) {
if (jsonObject.containsKey("time")) {
return timeLongToStr(jsonObject.getLong("time"));
} else {
return timeLongToStr(System.currentTimeMillis());
}
}
private static String getFields(JSONObject jsonObject) {
JSONObject dataJson = jsonObject.getJSONObject("datas");
StringBuilder sb = new StringBuilder();
sb.append("time").append(",");
dataJson.forEach((key, value) -> sb.append(key).append(","));
return sb.substring(0, sb.length() - 1);
}
private static String getValues(JSONObject jsonObject) {
JSONObject dataJson = jsonObject.getJSONObject("datas");
StringBuilder sb = new StringBuilder();
sb.append(""").append(getTime(jsonObject)).append(""").append(",");
dataJson.forEach((key, value) -> sb.append(value).append(","));
return sb.substring(0, sb.length() - 1);
}
private static String timeLongToStr(long time) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return sdf.format(new Date(time));
}
}
【小插曲】
測試過程中,發(fā)現(xiàn)了一個問題,詳細(xì)請參考issue:https://github.com/taosdata/TDengine/issues/3818
==數(shù)據(jù)模型==
官網(wǎng)地址:https://www.taosdata.com/cn/documentation/architecture/
官網(wǎng)上面寫了TD的數(shù)據(jù)模型,不過沒有圖例進(jìn)行直觀的說明,所以介紹的多少有些抽象。希望文檔上可以提升一下逼格。
【物理量】
也叫“測點”、“點位””。就像做心電圖時,粘在身上的幾個吸盤。一吸盤就是一個測點,也就是一個物理量。
我這里以智能水流量計為例,包括以下測點。
【數(shù)據(jù)采集點】
每個數(shù)據(jù)采集點可以采集多個物理量。
我覺得實際場景中的PLC應(yīng)該算是一個數(shù)據(jù)采集點了。
【表】
一個數(shù)據(jù)采集點一張表。
【超級表】
同一類型數(shù)據(jù)采集點的集合。
我這里做了一寫想到哪里就試到哪里的嘗試。
1、先創(chuàng)建一個超級表
create table if not exists znsllj (time timestamp, ForwardIntegratedFlow double, BackwardIntegratedFlow double, InstantaneousFlow double, Velocity double, Density double, Temperature double, Pressure double, Error bool) tags(product nchar(256), device nchar(256));
2、基于超級表創(chuàng)建表
create table znsllj001 using znsllj tags("product1", "device1");
3、向表中插入一條數(shù)據(jù)
insert into znsllj001(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 10, 11, 12, 13, 14, 15, 16, 0);
4、如果修改表結(jié)構(gòu)可以嗎?
alter table znsllj001 add column AddField double;
發(fā)現(xiàn)直接修改表的結(jié)構(gòu)是失敗的,提示只能修改超級表
5、嘗試修改超級表結(jié)構(gòu)
alter table znsllj add column AddField double;
發(fā)現(xiàn)修改成功,并且表的結(jié)構(gòu)也跟著變化了。
6、分別查看一下表和超級表的結(jié)構(gòu)
describe znsllj001;
describe znsllj;
7、刪除超級表中一個列(有數(shù)據(jù)的列)
alter table znsllj drop column ForwardIntegratedFlow;
看到的是可以成功刪除,同時表結(jié)構(gòu)也發(fā)生了改變。
8、此時如果刪除超級表會如何?
drop table if exists znsllj;
看到可以正常刪除超級表,而且表也被連帶著一起刪掉了。
9、重新創(chuàng)建超級表、表及插入一條數(shù)據(jù)(修改了一下超級表和表的的前綴,便于區(qū)分)
create table if not exists st_znsllj (time timestamp, ForwardIntegratedFlow double, BackwardIntegratedFlow double, InstantaneousFlow double, Velocity double, Density double, Temperature double, Pressure double, Error bool) tags (product nchar(256), device nchar(256));
create table t_znsllj001 using st_znsllj tags("product1", "device1");
insert into t_znsllj001(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 10, 11, 12, 13, 14, 15, 16, 0);
10、繼續(xù)創(chuàng)建幾個表(同一個超級表)
兩個標(biāo)簽值重復(fù):create table t_znsllj002 using st_znsllj tags("product1", "device1");
標(biāo)簽值都不重復(fù):create table t_znsllj003 using st_znsllj tags("product3", "device3");
少一個標(biāo)簽:create table t_znsllj004 using st_znsllj tags("product4");
無標(biāo)簽:create table t_znsllj005 using st_znsllj;
多一個標(biāo)簽:create table t_znsllj006 using st_znsllj tags("product6", "device6", "type6");
一個標(biāo)簽值重復(fù):create table t_znsllj007 using st_znsllj tags("product1", "device7");
結(jié)論如下:
表的標(biāo)簽數(shù)量必須與超級表一致。
表的標(biāo)簽值可以重復(fù)。
11、分別向幾個成功的表中插入一條數(shù)據(jù)
insert into t_znsllj001(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 10, 11, 12, 13, 14, 15, 16, 0);
insert into t_znsllj002(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 20, 21, 22, 23, 24, 25, 26, 0);
insert into t_znsllj003(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 30, 31, 32, 33, 34, 35, 36, 0);
insert into t_znsllj007(time, ForwardIntegratedFlow, BackwardIntegratedFlow, InstantaneousFlow, Velocity, Density, Temperature, Pressure, Error) values(now, 70, 71, 72, 73, 74, 75, 76, 0);
12、查看一下幾個表的數(shù)據(jù)(僅時間戳,正向累計流量)
select time, forwardintegratedflow from t_znsllj001 order by time;
select time, forwardintegratedflow from t_znsllj002 order by time;
select time, forwardintegratedflow from t_znsllj003 order by time;
select time, forwardintegratedflow from t_znsllj007 order by time;
13、檢索超級表的所有數(shù)據(jù)(時間戳,一個物理量(正向累計流量)、兩個TAG(產(chǎn)品、設(shè)備))
select time, forwardintegratedflow, product, device from st_znsllj order by time;
可以看到,通過超級表的結(jié)果會帶有標(biāo)簽,普通表是么有標(biāo)簽的。另外超級表只看標(biāo)簽值,結(jié)果集中看不到具體是從哪個表中數(shù)據(jù)。
==聚合語句==
根據(jù)官方文檔進(jìn)行了一堆驗證,感覺這些函數(shù)還不錯。但是在大量數(shù)據(jù)的情況下,結(jié)果是否正確沒有驗證過。僅進(jìn)行了功能上的驗證,基本可以代替InfluxDB。
另外,對于“適用于”這一列,實際上與官方文檔有出入。至少在這個版本,我的驗證結(jié)果如下。
Excel版本的驗證結(jié)果,我共享到百度網(wǎng)盤了,有需要的自提。
鏈接:https://pan.baidu.com/s/1AOgDeGCqoOsvhGWu27Vrtg
提取碼:vxpb
==滾動升級測試==
目前版本的td尚屬于更新迭代很快的階段,所以難免會有一些bug發(fā)生,所以在實際使用中,會頻繁的進(jìn)行版本升級。
這一點也會影響td是否能夠順利落地,以及長久使用的一個考量指標(biāo)。我按照以下的方式進(jìn)行了一次嘗試。
【驗證思路】
因為目前集群版release的就這一個版本,所以沒有辦法測試版本升級,只能測試卸載之后,在重新安裝。
【驗證結(jié)論】
卸載并重新安裝之后,集群可以正常使用。
【驗證過程】
1、先備份配置文件
分別將3個節(jié)點的配置文件下載并備份。
2、停止td集群
在3個節(jié)點分別執(zhí)行命令:systemctl stop taosd
3、卸載tdengine
在3個節(jié)點分別執(zhí)行命令:
#查看tdengine rpm -qa | grep TDengine #卸載tdengine yum remove TDengine-2.0.4.0-3.x86_64
4、查看卸載后的狀態(tài)
配置文件保留,沒有被刪除。
數(shù)據(jù)文件保留,沒有被刪除。
5、重新安裝集群
在3個節(jié)點分別執(zhí)行:rpm -ivh /home/radmin/soft/TDengine-server-2.0.4.0-Linux-x64.rpm
6、觀察配置文件
配置文件沒有被覆蓋,保留了卸載之前的配置,這樣挺好的,省著重新配置了。
7、啟動集群
在3個節(jié)點分別執(zhí)行命令:systemctl start taosd
8、進(jìn)入命令行
在任意節(jié)點運(yùn)行taos,確認(rèn)可以進(jìn)入命令行。
9、查看集群狀態(tài)
show dnodes;
查看數(shù)據(jù)庫show databases;
切換數(shù)據(jù)庫,并查看超級表
查詢?nèi)我獗?/p>
2020年10月12日 13:38 追記
看到官方剛剛發(fā)布了2.0.5.0版本,按照下面的順序重新嘗試了一遍,結(jié)果一樣,順利升級成功。
2020年10月12日 14:00 追記
集群使用了一會之后,發(fā)現(xiàn)第2個節(jié)點宕掉了,
沒有辦法,由于著急測試,將tdengine卸載,然后刪除數(shù)據(jù)目錄,重新安裝之后才得以解決。
2020年10月12日 19:37 追記
服務(wù)器版本升級到2.0.5.0之后,taos-jdbcdriver的版本需要使用2.0.8,使用2.0.5的時候會報錯。感謝網(wǎng)友
2020年12月21日 9:24 追記
服務(wù)器從2.0.8.0升級到2.0.10.0,出現(xiàn)了一個問題。升級之后,通過shell查詢數(shù)據(jù)提示錯誤:DB error: Invalid message
在群里咨詢之后,最終問題得到了解決,不過不敢保證是以下哪個方式解決的,猜測是第1個原因
1、在升級taosd的時候,taos進(jìn)程一直沒有關(guān)閉,升級之后也是用的2.0.8.0版本的taos shell檢索的。所以報錯
2、java客戶端版本不正確,java客戶端版本從2.0.12升級到2.0.15之后,重新執(zhí)行程序確實解決了。
另外,從群里咨詢得到了一下幾個結(jié)論,后續(xù)升級需要注意:
濤思的版本升級規(guī)則是,前三位一致是版本兼容的,如不一致需要同步升級客戶端和服務(wù)端
==連續(xù)查詢==
在InfluxDB中有連續(xù)查詢的功能,可以按照一定的時間頻率對原始數(shù)據(jù)進(jìn)行聚合,并將聚合結(jié)果放入到新的數(shù)據(jù)庫中,
具體可以參考我InfluxDB連續(xù)查詢的另一篇博客:使用InfluxDB的連續(xù)查詢解決聚合性能問題
同樣,在TDengine中也提供了連續(xù)查詢的功能,我這里需要驗證一下TDengine的連續(xù)查詢與InfluxDB的區(qū)別,
用來評估替換InfluxDB之后,對應(yīng)用端的代碼改動的影響大小。
【語法嘗試】
1、創(chuàng)建連續(xù)查詢
create table avg_velocity as select avg(velocity) from st_znsllj interval(1m) sliding(30s);
在定義連續(xù)查詢的時候需要指定時間窗口大小(time window, 參數(shù)interval)和每次前向增量時間(forward sliding times, 參數(shù)sliding)。
2、查看連續(xù)查詢
show streams;
3、殺掉指定連續(xù)查詢
kill stream 3:1;
【小插曲】
在超級表的查詢語句中加上sliding之后,提示Redirect錯誤。Issue為:https://github.com/taosdata/TDengine/issues/3801
官方上是說在連續(xù)查詢上不建議使用sliding
4、嘗試將連續(xù)查詢的結(jié)果放入另一個庫
需要在查詢的表以及目標(biāo)表上加上數(shù)據(jù)的名字即可。
create tableqch_cq.device_data_up_sum as select sum(AI_PICK_UDATA) fromqch_test.st_device_data_up interval(1m) sliding(30s) order by time desc;
【小插曲】
配置上連續(xù)查詢,并且程序段在一直的寫入數(shù)據(jù),發(fā)現(xiàn)了幾個奇怪的現(xiàn)象
現(xiàn)象1:streamId會一直變化
==寫入性能測試==
我寫了一個單列模式的測試樣例,
1、測試服務(wù)器:3個節(jié)點(阿里云ECS服務(wù)器,8核16G內(nèi)存)
2、單client
3、單列模式
4、自動建表
5、分別測試5千,10萬,100萬測點,按照不同粒度批量寫入(每批100、1000、5000等共10個粒度)
6、1個超級表
在本地運(yùn)行環(huán)境中跑,由于服務(wù)器在阿里云上,受網(wǎng)絡(luò)的影響,速度時非常的慢的,
10萬點的數(shù)據(jù),一共跑了3次,每次都差不多要1個小時才能跑完(一共3個小時)
如果把程序打成jar包,扔到阿里云ECS服務(wù)器上跑,就快了太多太多了,
一樣的程序,每次10萬,一共3次,每次差多也就2分鐘就可以插入完成。
但是,感覺還是有一些慢,等找到一些優(yōu)化的方法,在繼續(xù)更新。。。。
2020年11月10日追記:
嘗試了批量寫入的方式,比如每次寫入500條(由于是單列模式,相當(dāng)于每次向500個表同時寫入數(shù)據(jù))
從結(jié)果上看,速度確實要快了很多很多,是一個好的結(jié)果。
【小插曲】
由于是單列模式的批量插入,所以sql語句會非常的長,大概是下面的這種感覺,
當(dāng)sql超過一定長度的時候,程序就報錯TDengine Error: Invalid SQL statement。
嘗試調(diào)整maxSQLLength參數(shù),將限制放大到10倍,也就是654800,問題解決。
注意:
maxSQLLength是客戶端參數(shù),是調(diào)用JDBC Connector的應(yīng)用程序所在機(jī)器上的配置文件,
Linux OS 上默認(rèn)值 /etc/taos/taos.cfg ,Windows OS 上默認(rèn)值 C://TDengine/cfg/taos.cfg。
【測試結(jié)論】
測試結(jié)論:
1、單client,單列模式,自動建表模式,每秒寫入性能約每秒2萬條。
2、按照我目前的機(jī)器配置,批量寫入的時候,建議每批500條。
下圖是測試的統(tǒng)計圖。
==可靠性測試==
==數(shù)據(jù)備份==
==聚合性能驗證==
==實際落地姿勢==
筆記:2021年1月19日
目前在一個項目中,準(zhǔn)備上TDengine,但是考慮到TDengine的一些實際情況
1、TD在快速的版本迭代過程中,難免會有一些問題不能第一時間解決(需要提Issue)
2、社區(qū)版的解決速度也會比預(yù)期的要慢一些 (實際上還是比較不錯的了)
3、TD本身是用C語言開發(fā)的,能獨(dú)立解決TD問題的人不多(年輕人,會C的人不是很多)
綜合考慮之后,沒有獨(dú)立的使用TDengine來支撐項目,而是采用了以下方案
1、使用InfluxDB(社區(qū)版)來支撐實時業(yè)務(wù),數(shù)據(jù)存儲時間不超過3個月。并使用連續(xù)查詢來支撐實時聚合。
2、使用TDengine(社區(qū)版)來支撐分析業(yè)務(wù),數(shù)據(jù)存儲時間為默認(rèn)的10年。使用單列模式,來支撐測點的增減場景。
這樣的好處是,可以充分使用InfluxDB的穩(wěn)定,來確保實時類業(yè)務(wù)的可靠性。
同時有可以引入TDengine的新物種,帶來聚合性能的提升,給業(yè)務(wù)帶來一些成長因素。
筆記:2021年4月7日 20:30
我們在InfluxDB和TDengine之外包裝了一層SDK,對應(yīng)用層暴露SDK,這樣應(yīng)用層就不需要關(guān)心到底用的哪個存儲技術(shù)了。
在SDK中需要解決以下問題:
1、檢查InfluxDB及TDengine的連接狀態(tài),如果其中一個宕了,使用另一個。
2、判斷查詢數(shù)據(jù)的起始時間,如果在時間范圍內(nèi)則查詢InfluxDB,如果超過一定時間則使用TDengine。
3、翻譯應(yīng)用端的查詢語句以及查詢的數(shù)據(jù)結(jié)果。統(tǒng)一到InfluxDB的數(shù)據(jù)格式。
實際場景中的數(shù)據(jù)備份方案還沒有最終確定,后續(xù)更新。
--END--
總結(jié)
以上是生活随笔為你收集整理的【转】TDengine踩坑随记(最后一次更新:2021-4-7 20:30)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 原型设计工具比较及实践
- 下一篇: IE的documentMode属性