什么是时间序列数据(Time Series Data,TSD,如下简称时序)从定义上来讲,就是一串按时间维度索引的数据。用描述性的语言来解释什么是时序数据,简单的说,就是这类数据描述了某个被测量的主体在一个时间范围内的每一个时间点上的测量值。它广泛存在于IT基础设施、运维监控系统和物联网中。
对时序数据进行建模的话,会包含三个重要部分,分别是:主体,时间点和测量值。套用这套模型,你会发现你在平常工做生活中,无时无刻不在接触着这类数据。html
时序数据从时间维度上将孤立的观测值连成一条线,从而揭示软硬件系统的状态变化。孤立的观测值不能叫时序数据,但若是把大量的观测值用时间线串起来,咱们就能够研究和分析观测值的趋势及规律。mysql
上面介绍了时序数据的基本概念,也说明了分析时序数据的意义。那么时序数据该怎样存储呢?数据的存储要考虑其数学模型和特色,时序数据固然也不例外。因此这里先介绍时序数据的数学模型和特色。linux
下图为一段时序数据,记录了一段时间内的某个集群里各机器上各端口的出入流量,每半小时记录一个观测值。这里以图中的数据为例,介绍下时序数据的数学模型(不一样的时序数据库中,基本概念的称谓有可能不一样,这里以腾讯CTSDB为准):web
measurement: 度量的数据集,相似于关系型数据库中的 table;算法
point: 一个数据点,相似于关系型数据库中的 row;sql
timestamp: 时间戳,表征采集到数据的时间点;docker
tag: 维度列,表明数据的归属、属性,代表是哪一个设备/模块产生的,通常不随着时间变化,供查询使用;shell
field: 指标列,表明数据的测量值,随时间平滑波动,不须要查询。
如上图所示,这组数据的measurement为Network,每一个point由如下部分组成:数据库
timestamp:时间戳json
两个tag:host、port,表明每一个point归属于哪台机器的哪一个端口
两个field:bytes_in、bytes_out,表明piont的测量值,半小时内出入流量的平均值
同一个host、同一个port,每半小时产生一个point,随着时间的增加,field(bytes_in、bytes_out)不断变化。如host:host4,port:51514,timestamp从02:00 到02:30的时间段内,bytes_in 从 37.937上涨到38.089,bytes_out从2897.26上涨到3009.86,说明这一段时间内该端口服务压力升高。
有了时序数据后,该存储在哪里呢?首先咱们看下传统的关系型数据库解决方案在存储时序数据时会遇到什么问题。
不少人可能认为在传统关系型数据库上加上时间戳一列就能做为时序数据库。数据量少的时候确实也没问题。但时序数据每每是由百万级甚至千万级终端设备产生的,写入并发量比较高,属于海量数据场景。
MySQL在海量的时序数据场景下存在以下问题:
另外,使用Hadoop生态(Hadoop、Spark等)存储时序数据会有如下问题:
能够看到时序数据库须要解决如下几个问题:
***时序数据库产品的发明都是为了解决传统关系型数据库在时序数据存储和分析上的不足和缺陷,这类产品被统一归类为时序数据库。***针对时序数据的特色对写入、存储、查询等流程进行了优化,这些优化与时序数据的特色息息相关:
存储成本:
利用时间递增、维度重复、指标平滑变化的特性,合理选择编码压缩算法,提升数据压缩比;
经过预降精度,对历史数据作聚合,节省存储空间。
高并发写入:
批量写入数据,下降网络开销;
数据先写入内存,再周期性的dump为不可变的文件存储。
低查询延时,高查询并发:
优化常见的查询模式,经过索引等技术下降查询延时;
经过缓存、routing等技术提升查询并发。
传统数据库存储采用的都是 B tree,这是因为其在查询和顺序插入时有利于减小寻道次数的组织形式。咱们知道磁盘寻道时间是很是慢的,通常在 10ms 左右。磁盘的随机读写慢就慢在寻道上面。对于随机写入 B tree 会消耗大量的时间在磁盘寻道上,致使速度很慢。咱们知道 SSD 具备更快的寻道时间,但并无从根本上解决这个问题。
对于 90% 以上场景都是写入的时序数据库,B tree 很明显是不合适的。
业界主流都是采用 LSM tree 替换 B tree,好比 Hbase, Cassandra 等 nosql 。这里咱们详细介绍一下。
LSM tree 包括内存里的数据结构和磁盘上的文件两部分。分别对应 Hbase 里的 MemStore 和 HLog;对应 Cassandra 里的 MemTable 和 sstable。
LSM tree 操做流程以下:
能够看到 LSM tree 核心思想就是经过内存写和后续磁盘的顺序写入得到更高的写入性能,避免了随机写入。但同时也牺牲了读取性能,由于同一个 key 的值可能存在于多个 HFile 中。为了获取更好的读取性能,能够经过 bloom filter 和 compaction 获得,这里限于篇幅就不详细展开。
###1.3.4 分布式存储
时序数据库面向的是海量数据的写入存储读取,单机是没法解决问题的。因此须要采用多机存储,也就是分布式存储。
分布式存储首先要考虑的是如何将数据分布到多台机器上面,也就是分片(sharding)问题。下面咱们就时序数据库分片问题展开介绍。分片问题由分片方法的选择和分片的设计组成。
####分片方法
时序数据库的分片方法和其余分布式系统是相通的。
分片设计简单来讲就是以什么作分片,这是很是有技巧的,会直接影响写入读取的性能。
**结合时序数据库的特色,根据 measurement+tags 分片是比较好的一种方式,由于每每会按照一个时间范围查询,这样相同 metric 和 tags 的数据会分配到一台机器上连续存放,顺序的磁盘读取是很快的。**再结合上面讲到的单机存储内容,能够作到快速查询。
进一步咱们考虑时序数据时间范围很长的状况,须要根据时间范围再分红几段,分别存储到不一样的机器上,这样对于大范围时序数据就能够支持并发查询,优化查询速度。
以下图,第一行和第三行都是一样的 tag(sensor=95D8-7913;city= 上海),因此分配到一样的分片,而第五行虽然也是一样的 tag,可是根据时间范围再分段,被分到了不一样的分片。第2、4、六行属于一样的 tag(sensor=F3CC-20F3;city= 北京)也是同样的道理。
目前行业内比较流行的开源时序数据库产品有 InfluxDB、OpenTSDB、Prometheus、Graphite等,其产品特性对好比下图所示:
InfluxDB是一个开源的时序数据库,使用GO语言开发,特别适合用于处理和分析资源监控数据这种时序相关数据。而InfluxDB自带的各类特殊函数如求标准差,随机取样数据,统计数据变化比等,使数据统计和实时分析变得十分方便。
influxdb里面有一些重要概念:database,timestamp,field key, field value, field set,tag key,tag value,tag set,measurement, retention policy ,series,point。结合下面的例子数据来讲明这几个概念:
name: census -———————————— time butterflies honeybees location scientist 2015-08-18T00:00:00Z 12 23 1 langstroth 2015-08-18T00:00:00Z 1 30 1 perpetua 2015-08-18T00:06:00Z 11 28 1 langstroth 2015-08-18T00:06:00Z 3 28 1 perpetua 2015-08-18T05:54:00Z 2 11 2 langstroth 2015-08-18T06:00:00Z 1 10 2 langstroth 2015-08-18T06:06:00Z 8 23 2 perpetua 2015-08-18T06:12:00Z 7 22 2 perpetua
timestamp
既然是时间序列数据库,influxdb的数据都有一列名为time的列,里面存储UTC时间戳。
field key,field value,field set
butterflies和honeybees两列数据称为字段(fields),influxdb的字段由field key和field value组成。其中butterflies和honeybees为field key,它们为string类型,用于存储元数据。
而butterflies这一列的数据12-7为butterflies的field value,同理,honeybees这一列的23-22为honeybees的field value。field value能够为string,float,integer或boolean类型。field value一般都是与时间关联的。
field key和field value对组成的集合称之为field set。以下:
butterflies = 12 honeybees = 23 butterflies = 1 honeybees = 30 butterflies = 11 honeybees = 28 butterflies = 3 honeybees = 28 butterflies = 2 honeybees = 11 butterflies = 1 honeybees = 10 butterflies = 8 honeybees = 23 butterflies = 7 honeybees = 22
在influxdb中,字段必须存在。注意,字段是没有索引的。若是使用字段做为查询条件,会扫描符合查询条件的全部字段值,性能不及tag。类比一下,fields至关于SQL的没有索引的列。
tag key,tag value,tag set
location和scientist这两列称为标签(tags),标签由tag key和tag value组成。location这个tag key有两个tag value:1和2,scientist有两个tag value:langstroth和perpetua。tag key和tag value对组成了tag set,示例中的tag set以下:
location = 1, scientist = langstroth location = 2, scientist = langstroth location = 1, scientist = perpetua location = 2, scientist = perpetua
tags是可选的,可是强烈建议你用上它,由于tag是有索引的,tags至关于SQL中的有索引的列。tag value只能是string类型 若是你的经常使用场景是根据butterflies和honeybees来查询,那么你能够将这两个列设置为tag,而其余两列设置为field,tag和field依据具体查询需求来定。
measurement
measurement是fields,tags以及time列的容器,measurement的名字用于描述存储在其中的字段数据,相似mysql的表名。如上面例子中的measurement为census。measurement至关于SQL中的表,本文中我在部分地方会用表来指代measurement。
retention policy
retention policy指数据保留策略,示例数据中的retention policy为默认的autogen。它表示数据一直保留永不过时,副本数量为1。你也能够指定数据的保留时间,如30天。
series
series是共享同一个retention policy,measurement以及tag set的数据集合。示例中数据有4个series,以下:
Arbitrary series number Retention policy Measurement Tag set series 1 autogen census location = 1,scientist = langstroth series 2 autogen census location = 2,scientist = langstroth series 3 autogen census location = 1,scientist = perpetua series 4 autogen census location = 2,scientist = perpetua
point
point则是同一个series中具备相同时间的field set,points至关于SQL中的数据行。以下面就是一个point:
name: census ----------------- time butterflies honeybees location scientist 2015-08-18T00:00:00Z 1 30 1 perpetua
database
上面提到的结构都存储在数据库中,示例的数据库为my_database。一个数据库能够有多个measurement,retention policy, continuous queries以及user。influxdb是一个无模式的数据库,能够很容易的添加新的measurement,tags,fields等。而它的操做却和传统的数据库同样,可使用类SQL语言查询和修改数据。
influxdb不是一个完整的CRUD数据库,它更像是一个CR-ud数据库。它优先考虑的是增长和读取数据而不是更新和删除数据的性能,并且它阻止了某些更新和删除行为使得建立和读取数据更加高效。
更多详细介绍请见:https://www.jianshu.com/p/a1344ca86e9b
yum部署:
<1> 配置YUM源
cat <<EOF| sudo tee /etc/yum.repos.d/influxdb.repo [influxdb] name = InfluxDB Repository- RHEL\$releasever baseurl = https://repos.influxdata.com/rhel/\$releasever/\$basearch/stable enabled = 1 gpgcheck = 1 gpgkey = https://repos.influxdata.com/influxdb.key EOF
<2> yum安装
yum install influxdb -y systemctl start influxdb systemctl enable influxdb
rpm部署:
wget https://dl.influxdata.com/influxdb/releases/influxdb-1.5.2.x86_64.rpm yum -y localinstall influxdb-1.5.2.x86_64.rpm
docker部署:
docker run --name=influxdb -d -p 8086:8086 -v /etc/localtime:/etc/localtime daocloud.io/liukuan73/influxdb:1.4
备注:假如是收集collectd的内容,还须要映射25826端口-p 25826:25826
##2.2 grafana部署
rpm部署:
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm yum -y localinstall grafana-5.0.4-1.x86_64.rpm systemctl enable grafana-server systemctl start grafana-server
docker部署:
docker run -d -p 3000:3000 --name=grafana -e "GF_SERVER_HTTP_PORT=3000" -e "GF_AUTH_BASIC_ENABLED=false" -e "GF_AUTH_ANONYMOUS_ENABLED=true" -e "GF_AUTH_ANONYMOUS_ORG_ROLE=Admin" -e "GF_SERVER_ROOT_URL=/" daocloud.io/liukuan73/grafana:5.0.0
有三种方法能够将数据写入InfluxDB,包括:
一、yum安装
sudo yum -y install epel-release sudo yum -y install collectd
二、数据写入 influxdb ,修改配置
vi /etc/collectd.conf LoadPlugin network <Plugin network> # # client setup: Server "10.142.232.155" "25826" # <Server "239.192.74.66" "25826"> </Plugin> systemctl enable collectd systemctl start collectd systemctl status collectd
一、建立collectd数据库
influx -host '10.142.232.155' -port '8086' Connected to http://127.0.0.1:8086 version 1.5.2 InfluxDB shell version: 1.5.2 > create database collectd > use collectd > create user "collectd" with password '123456' with all privileges
二、配置influxdb,开启对collectd数据的接收
vim /etc/influxdb/influxdb.conf [[collectd]] enabled = true port = 25826 database = "collectd" #刚建立的collectd数据库,来自collectd的数据写入这个数据库。没事先建立好的话会启动失败
点击“Add data source”配置数据源:
网络流量统计
建立graph,切换编辑模式“Toggle Edit Mode”, 而后输入自定义SQL查询
输入查询语句:
SELECT derivative("value") AS "value" FROM "interface_rx" WHERE "host" = 'k8sslave04' AND "type" = 'if_octets' AND "instance" = 'eno16777984'
备注:
函数 derivative 意为导数, 微积分中的概念. value 为传输总量(字节), derivative(“value”) 为 value 在时间上的增量.其中:
系统负载
输入查询语句:
SELECT mean("value") FROM "load_longterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null) SELECT mean("value") FROM "load_midterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null) SELECT mean("value") FROM "load_shortterm" WHERE "host" = 'k8sslave04' AND $timeFilter GROUP BY time($interval) fill(null)
内存用量
输入查询语句:
SELECT mean("value") FROM "memory_value" WHERE "type_instance" = 'used' AND $timeFilter GROUP BY time($interval) fill(null)
效果
建立数据库:
要建立数据库,请将POST请求发送到/query终结点,并将URL参数q设置为CREATE DATABASE。 下面的示例主机上运行的InfluxDB发送请求,并建立数据库test:
curl -i -XPOST http://influxdb-ip:8086/query --data-urlencode "q=CREATE DATABASE test"
写入单条数据:
经过向/write端点发送POST请求,HTTP-API是将数据写入InfluxDB的主要方式。下面的例子向test数据库写了一个点。 数据由度量cpu_load_short,标签键host和region和对应的标签值server01和us-west,字段值为0.64的字段键value和时间戳1434055562000000000组成。
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
写入点时,必须在db查询参数中指定一个现有的数据库。 若是您没有使用rp查询参数提供保留策略,则会将点写入数据库的默认保留策略。 请参阅API参考文档以获取可用查询参数的完整列表。
写入多条数据:
一次将多个点Post到不一样序列,只须要用行将多个点分隔便可。这种批量方式具备高性能。如下示例将三个点写入数据库mydb。 第一点属于拥有度量cpu_load_short及标签集host = server02且用服务器本地时间戳的序列。第二点属于拥有度量cpu_load_short及标签集host = server02,region =us-west且具备指定时间戳1422568543702900257的序列。第三个点与第二个点具备相同的指定时间戳,可是将其写入拥有度量cpu_load_short和标签集direction=in,host=server01,region=us-west的序列。
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary 'cpu_load_short,host=server02 value=0.67 cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257 cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257'
写入来自文件的数据:
经过将@filename传给curl来从文件中写入点。文件中的数据应该遵循InfluxDB的行协议语法。格式正确的文件示例(cpu_data.txt):
cpu_load_short,host=server02 value=0.67 cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257 cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257
将cpu_data.txt中数据写入mydb数据库:
curl -i -XPOST 'http://influxdb-ip:8086/write?db=test' --data-binary @cpu_data.txt
注意:若是数据文件中超过5,000个点,可能须要将该文件分红几个文件,以便将数据批量写入InfluxDB。 默认状况下,HTTP请求在五秒钟后超时。 InfluxDB在超时以后仍然会尝试写出这些点,可是不能确认它们是否成功写入。
###3.2.2 HTTP响应总结
无架构设计
InfluxDB是一个无架构的数据库。 您能够随时添加新的度量,标签和字段。请注意,若是您尝试写入与已写入数据类型不相同的数据(例如,将字符串写入以前接受整数的字段),InfluxDB将拒绝这些数据。
错误响应的例子:
将浮点数写入先前接受布尔值的字段中:
curl -i -XPOST 'https://influxdb-ip:8086/writedb=hamlet' --data-binary 'tobeornottobe booleanonly=true' curl -i -XPOST 'https://influxdb-ip:8086/writedb=hamlet' --data-binary 'tobeornottobe booleanonly=5'
返回:
HTTP/1.1 400 Bad Request Content-Type: application/json Request-Id: [...] X-Influxdb-Version: 1.4.x Date: Wed, 01 Mar 2017 19:38:01 GMT Content-Length: 150 {"error":"field type conflict: input field \"booleanonly\" on measurement \"tobeornottobe\" is type float, already exists as type boolean dropped=1"} Writing a point to a database that doesn’t exist: curl -i -XPOST 'https://localhost:8086/writedb=atlantis' --data-binary 'liters value=10' returns: HTTP/1.1 404 Not Found Content-Type: application/json Request-Id: [...] X-Influxdb-Version: 1.4.x Date: Wed, 01 Mar 2017 19:38:35 GMT Content-Length: 45 {"error":"database not found: \"atlantis\""} Next steps Now that you know how to write data with the built-in HTTP API discover how to query them with the Querying Data guide! For more information about writing data with the HTTP API, please see the API reference documentation.
将点写入不存在的数据库
curl -i -XPOST 'https://localhost:8086/writedb=atlantis' --data-binary 'liters value=10'
返回:
HTTP/1.1 404 Not Found Content-Type: application/json Request-Id: [...] X-Influxdb-Version: 1.4.x Date: Wed, 01 Mar 2017 19:38:35 GMT Content-Length: 45 {"error":"database not found: \"atlantis\""}
InfluxDB提供类SQL语法,若是熟悉SQL的话会很是容易上手。
一些操做实例请见:https://www.linuxdaxue.com/influxdb-basic-operation.html
http://www.infoq.com/cn/articles/storage-in-sequential-databases
https://zhuanlan.zhihu.com/p/32627177
https://segmentfault.com/a/1190000006868587
http://www.zhimengzhe.com/shujuku/MySQL/414763.html
http://www.javashuo.com/article/p-qjteyfvu-gw.html
https://blog.csdn.net/wudufeng/article/details/78567866
https://www.linuxdaxue.com/influxdb-basic-operation.html
https://www.jianshu.com/p/a1344ca86e9b