zoukankan      html  css  js  c++  java
  • influxDB框架 & 数据存储 & TSM & 数据操作等详解

    influxdb

    Go语言标准库中文文档

    image-20201019211311408

    influxdata主目录结构

    [root@localhost influxdata]# pwd
    /root/dev/golib/src/github.com/influxdata
    [root@localhost influxdata]# tree -d -L 1
    .
    ├── influxdb
    ├── influxql
    ├── usage-client
    ├── yamux
    └── yarpc
    

    目录解析说明:

    • influxdb

    为源码的主目录

    • influxql

    实现了InfluxDB查询语言的解析器(源码主目录里面引用的是influxdata/influxdb/influxql,没有该目录的相关引用)

    • usage-client

    client lib V1版本

    • yamux

    Yet another Multiplexer(又一个多路复用器)是Golang的多路复用库

    • yarpc

    Yet Another RPC (又一个RPC)是Golang的RPC库

    源码主目录结构

    一级目录结构如下:

    [root@localhost influxdb]# pwd
    /root/dev/golib/src/github.com/influxdata/influxdb
    [root@localhost influxdb]# tree -d -L 1
    .
    ├── client
    ├── cmd
    ├── coordinator
    ├── etc
    ├── importer
    ├── influxql
    ├── internal
    ├── man
    ├── models
    ├── monitor
    ├── pkg
    ├── scripts
    ├── services
    ├── stress
    ├── tcp
    ├── tests
    ├── toml
    ├── tsdb
    └── uuid
    

    二级目录结构如下:

    [root@localhost influxdb]# tree -d -L 2
    .
    ├── client
    │   └── v2
    ├── cmd
    │   ├── influx
    │   ├── influxd
    │   ├── influx_inspect
    │   ├── influx_stress
    │   └── influx_tsm
    ├── coordinator
    ├── etc
    │   └── burn-in
    ├── importer
    │   └── v8
    ├── influxql
    │   ├── internal
    │   └── neldermead
    ├── internal
    ├── man
    ├── models
    ├── monitor
    │   └── diagnostics
    ├── pkg
    │   ├── deep
    │   ├── escape
    │   ├── limiter
    │   ├── pool
    │   └── slices
    ├── scripts
    ├── services
    │   ├── admin
    │   ├── collectd
    │   ├── continuous_querier
    │   ├── graphite
    │   ├── httpd
    │   ├── meta
    │   ├── opentsdb
    │   ├── precreator
    │   ├── retention
    │   ├── snapshotter
    │   ├── subscriber
    │   └── udp
    ├── stress
    │   ├── stress_test_server
    │   └── v2
    ├── tcp
    ├── tests
    │   ├── siege
    │   ├── tmux
    │   └── urlgen
    ├── toml
    ├── tsdb
    │   ├── engine
    │   └── internal
    └── uuid
    

    目录解析说明:

    • client

    client lib V2版本

    cmd目录

    InfluxDB相关程序所在目录

    ​ 其中:

    influxd目录为InfluxDB主程序代码;

    influx为InfluxDB自带的控制台管理工具源码;

    influx_inspect为InfluxDB数据查看工具源码;

    influx_stress为InfluxDB压力测试工具源码;

    influx_tsm为数据库转换工具(将数据库从b1或bz1格式转换为tsm1格式)源码

    其他目录

    • coordinator

    协调器,负责数据的写入和一些创建语句的执行。

    在InfluxDB的ChangeLog中显示在v1.0.0中使用coordinator替换cluster,感觉自建集群功能可以通过此模块实现。

    • etc

    存放默认配置

    • importer

    版本向后兼容相关代码,在ReadMe中已经提到:Version 0.8.9 of InfluxDB adds support to export your data to a format that can be imported into 0.9.3 and later.

    • influxql

    实现了InfluxDB查询语言的解析器

    • internal

    主要实现了MetaClient接口

    • man

    帮助手册

    • models

    基础数据类型定义

    • monitor

    InfluxDB系统监控

    • pkg

    一些通用包的集合。

    deep里面主要实现了deepValueEqual方法,用于深层次比较两个值是否相等;

    escape里面主要实现了byte和string两种数据类型转义字符的相关操作;

    limiter里面主要是一个基于channel实现的简单并发限制器Fixed;

    pool里面主要实现了Bytes和Generic两种类型的Pool,在Pool中的对象不使用时不会被垃圾回收自动清理掉;

    slices 里面主要实现了一些string数组的操作;

    • scripts

    该目录存放的是一些关于InfluxDB的脚本。

    • services

    该目录存放的是一些关于InfluxDB的服务。

    admin 为InfluxDB内置的管理服务;

    collectd 为collectd(https://collectd.org)对接服务,可以接收通过UDP发送过来的collectd格式数据;

    continuous_querier 为InfluxDB的CQ服务;

    graphite 为InfluxDB的graphite服务;

    httpd 为InfluxDB的http服务,可以通过该接口进行数据库数据的写入和查询等操作;

    meta 为InfluxDB的元数据服务,用于管理数据库的元数据相关内容;

    opentsdb 为InfluxDB的opentsdb服务,可用于替换opentsdb;

    precreator 为InfluxDB的Shard预创建服务;

    retention 为InfluxDB的数据保留策略的强制执行服务,主要用于定时删除文件;

    snapshotter 为InfluxDB的快照服务;

    subscriber 为InfluxDB的订阅服务;

    udp 为InfluxDB的udp服务,可以通过该接口进行数据库的写入和查询等操作;

    • stress

    该目录存放的是压力测试相关内容。

    • tcp

    网络连接的多路复用。

    • tests

    测试相关内容

    • toml

    toml的解析器,和另一个toml解析器(github.com/BurntSushi/toml)不同,为独立的解析模块,主要是解析时间字符串和磁盘容量数据。

    • tsdb

    tsdb目录主要是时序数据库的实现。

    • uuid

    该目录里面主要存放uuid生成的相关代码。

    数据操作

    CLI–influx命令行操作

    执行influx

    src源文件中编译执行influx:

    step1:先执行cmdinfluxdmain.go文件,启动本地influxDB实例;
    step2:执行cmdinfluxmain.go文件,将influx连接到本地的influxDB实例上;

    在cmd中运行influx.exe可执行文件,从而执行influx:

    //用cmd方式执行influx可执行文件:influx2/bin/influx.exe(前提先运行influxd.exe)
    $ influx -precision rfc3339
    Connected to http://localhost:8086 version 1.2.x
    InfluxDB shell 1.2.x
    ###说明
    #	InfluxDB的HTTP接口默认起在8086上,所以influx默认也是连的本地的8086端口,你可以通过influx --help来看怎么修改默认值。
    #	-precision参数表明了任何返回的时间戳的格式和精度,在上面的例子里,rfc3339是让InfluxDB返回RFC339格式(YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ)的时间戳。
    
    

    ​ 这样这个命令行已经准备好接收influx的查询语句了(简称InfluxQL),用exit可以退出命令行。

    ​ 第一次安装好InfluxDB之后是没有数据库的(除了系统自带的_internal),因此创建一个数据库是我们首先要做的事,通过CREATE DATABASE <db-name>这样的InfluxQL语句来创建,其中<db-name>就是数据库的名字。数据库的名字可以是被双引号引起来的任意Unicode字符。 如果名称只包含ASCII字母,数字或下划线,并且不以数字开头,那么也可以不用引起来;

    创建数据库

    ​ 创建一个mydb数据库:

    > CREATE DATABASE mydb
    
    说明:在输入上面的语句之后,并没有看到任何信息,这在CLI里,表示语句被执行并且没有错误,如果有错误信息展示,那一定是哪里出问题了,这就是所谓的没有消息就是好消息;
    

    查看数据库

    ​ 现在数据库mydb已经创建好了,我们可以用SHOW DATABASES语句来看看已存在的数据库:

    > SHOW DATABASES
    name: databases
    name
    ----
    _internal      
    mydb
    
    说明:_internal数据库是用来存储InfluxDB内部的实时监控数据的。
    

    使用数据库

    ​ 大部分InfluxQL需要作用在一个特定的数据库上。你当然可以在每一个查询语句上带上你想查的数据库的名字,但是CLI提供了一个更为方便的方式USE,这会为你后面的所以的请求设置到这个数据库上;

    > USE mydb
    Using database mydb
    

    以下的操作都作用于mydb这个数据库之上;

    数据行协议

    ​ 首先对数据存储的格式来个入门介绍;InfluxDB里存储的数据被称为时间序列数据,其包含一个数值,就像CPU的load值或是温度值;时序数据有零个或多个数据点,每一个都是一个指标值;数据点包括time(一个时间戳),measurement(例如cpu_load),至少一个k-v格式的field(也即指标的数值例如 “value=0.64”或者“temperature=21.2”),零个或多个tag,其一般是对于这个指标值的元数据(例如“host=server01”, “region=EMEA”, “dc=Frankfurt);

    ​ 在概念上,你可以将measurement类比于SQL里面的table,其主键索引总是时间戳tagfield是在table里的其他列,tag是被索引起来的,field没有;不同之处在于,在InfluxDB里,你可以有几百万的measurements,你不用事先定义数据的scheme,并且null值不会被存储;

    ​ 将数据点写入InfluxDB,只需要遵守如下的行协议:

    <measurement>[,<tag-key>=<tag-value>...] <field-key>=<field-value>[,<field2-key>=<field2-value>...] [unix-nano-timestamp]

    image-20201108170724529

    image-20201108171159030

    插入数据行

    ​ 使用CLI插入单条的时间序列数据到InfluxDB中,用INSERT后跟数据点:

    INSERT cpu,host=serverA,region=us_west value=0.64
    说明:我们在写入的时候没有包含时间戳,当没有带时间戳的时候,InfluxDB会自动添加本地的当前时间作为它的时间戳。
    

    ​ 这样一个measurement为cpu,tag是hostregionvalue值为0.64的数据点被写入了InfluxDB中;

    查看数据

    跟SQL语法类型
    > SELECT "host", "region", "value" FROM "cpu"
    name: cpu
    time                host    region  value
    ----                ----    ------  -----
    1604823941584418500 serverA us_west 0.64
    
    > select * from cpu
    name: cpu
    time                host    region  value
    ----                ----    ------  -----
    1604823941584418500 serverA us_west 0.64
    

    常用命令

    CREATE DATABASE "testDB"      --创建数据库
    show databases      --展示所有数据库
    use testDB      --使用testDB数据库
    
    SHOW MEASUREMENTS  --查询当前数据库中含有的表
    SHOW FIELD KEYS --查看当前数据库所有表的字段
    SHOW series from pay --查看key数据
    SHOW TAG KEYS FROM "pay" --查看key中tag key值
    SHOW TAG VALUES FROM "pay" WITH KEY = "merId" --查看key中tag 指定key值对应的值
    SHOW TAG VALUES FROM cpu WITH KEY IN ("region", "host") WHERE service = 'redis'
    DROP SERIES FROM <measurement_name[,measurement_name]> WHERE <tag_key>='<tag_value>' --删除key
    SHOW CONTINUOUS QUERIES   --查看连续执行命令
    SHOW QUERIES  --查看最后执行命令
    KILL QUERY <qid> --结束命令
    SHOW RETENTION POLICIES ON mydb  --查看保留数据
    
    查询数据
    SELECT * FROM /.*/ LIMIT 1  --查询当前数据库下所有表的第一行记录
    select * from pay  order by time desc limit 2
    select * from  db_name."POLICIES name".measurement_name --指定查询数据库下数据保留中的表数据 POLICIES name数据保留
    
    删除数据
    delete from "query" --删除表所有数据,则表就不存在了
    drop MEASUREMENT "query"   --删除表(注意会把数据保留删除使用delete不会)
    DELETE FROM cpu
    DELETE FROM cpu WHERE time < '2000-01-01T00:00:00Z'
    DELETE WHERE time < '2000-01-01T00:00:00Z'
    DROP DATABASE “testDB” --删除数据库
    DROP RETENTION POLICY "dbbak" ON mydb --删除保留数据为dbbak数据
    DROP SERIES from pay where tag_key='' --删除key中的tag
    
    SHOW SHARDS  --查看数据存储文件
    DROP SHARD 1
    SHOW SHARD GROUPS
    SHOW SUBSCRIPTIONS
    

    参考文字:

    influxdb语法

    使用HTTP接口操作数据库

    cmd命令行中可以通过HTTP接口连接数据库,从而进行读写操作;

    创建数据库

    ​ 使用POST方式发送到URL的/query路径,参数qCREATE DATABASE,下面的例子发送一个请求到本地运行的InfluxDB创建数据库mydb

    curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE mydb"

    写入数据

    ​ 通过HTTP接口POST数据到/write路径是我们往InfluxDB写数据的主要方式。下面的例子写了一条数据到mydb数据库。这条数据的组成部分是measurement为cpu_load_short,tag 的 key为 host 和 region,对应 tag 的 value 是server01us-west,field的key是value,对应的数值为0.64,而时间戳是1434055562000000000

    第一次尝试
    >>C:UsersLuweir>curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
    弹出以下提示:
    curl: (1) Protocol "'http" not supported or disabled in libcurl
    curl: (6) Could not resolve host: value=0.64
    curl: (6) Could not resolve host: 1434055562000000000'
    查阅后发现这个命令中 ' ' 的部分都要使用 " "
    更正后:
    >>C:UsersLuweir>curl -i -XPOST "http://localhost:8086/write?db=mydb" --data-binary "cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000"
    
    HTTP/1.1 204 No Content  
    Content-Type: application/json
    Request-Id: 410f780d-219d-11eb-800a-9c7bef3eea50
    X-Influxdb-Build: OSS
    X-Influxdb-Version: unknown
    X-Request-Id: 410f780d-219d-11eb-800a-9c7bef3eea50
    Date: Sun, 08 Nov 2020 08:34:45 GMT
    

    HTTP返回值:

    ​ 2xx:如果你写了数据后收到HTTP 204 No Content ,说明写入成功了;
    ​ 4xx:表示InfluxDB不知道你发的是什么鬼;
    ​ 5xx:系统过载或是应用受损;

    ​ 当写入这条数据点的时候,你必须明确存在一个数据库对应名字是db参数的值。如果你没有通过rp参数设置retention policy的话,那么这个数据会写到db默认的retention policy中;

    ​ POST的请求体我们称之为Line Protocol,包含了你希望存储的时间序列数据。它的组成部分有measurement,tags,fields和timestamp。measurement是InfluxDB必须的,严格地说,tags是可选的,但是对于大部分数据都会包含tags用来区分数据的来源,让查询变得容易和高效。tag的key和value都必须是字符串。fields的key也是必须的,而且是字符串**,**默认情况下field的value是float类型的。timestamp在这个请求行的最后,是一个从1/1/1970 UTC开始到现在的一个纳秒级的Unix time,它是可选的,如果不传,InfluxDB会使用服务器的本地的纳米级的timestamp来作为数据的时间戳,注意无论哪种方式,在InfluxDB中的timestamp只能是UTC时间。

    写入文件中的数据:

    把下列数据行写入一个txt文件:以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的数据写入mybd数据库:

    curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary @cpu_data.txt

    说明:如果你的数据文件的数据点大于5000时,你必须把他们拆分到多个文件再写入InfluxDB。因为默认的HTTP的timeout的值为5秒,虽然5秒之后,InfluxDB仍然会试图把这批数据写进去,但是会有数据丢失的风险;

    无模式设计

    ​ InfluxDB是一个无模式(schemaless)的数据库,你可以在任意时间添加measurement,tags和fields。注意:如果你试图写入一个和之前的类型不一样的数据(例如,filed字段之前接收的是数字类型,现在写了个字符串进去),那么InfluxDB会拒绝这个数据;

    使用HTTP接口查询数据

    采样和数据保留

    相关概念

    以下列数据为例:

    ​ 数据展示了在2015年8月18日午夜至2015年8月18日上午6时12分在两个地点location(地点1和地点2)显示两名科学家scientistslangstrothperpetua)计数的蝴蝶(butterflies)和蜜蜂(honeybees)数量;

    image-20201108194700613

    其中census是measurement,butterflies和honeybees是field key,location和scientist是tag key

    时间戳

    ​ InfluxDB是一个时间序列数据库,因此我们开始一切的根源就是——时间。在上面的数据中有一列是time,在InfluxDB中所有的数据都有这一列。time存着时间戳,这个时间戳以RFC3339格式展示了与特定数据相关联的UTC日期和时间;

    field

    ​ 接下来两个列叫作butterflieshoneybees,称为fields。fields由field key和field value组成。field key(butterflieshoneybees)都是字符串,他们存储元数据;field key butterflies告诉我们蝴蝶的计数从12到7;field key honeybees告诉我们蜜蜂的计数从23变到22;

    ​ field value就是你的数据,它们可以是字符串、浮点数、整数、布尔值,因为InfluxDB是时间序列数据库,所以field value总是和时间戳相关联;

    示例中,field value如下:

    12   23
    1    30
    11   28
    3    28
    2    11
    1    10
    8    23
    7    22
    

    ​ field是InfluxDB数据结构所必需的一部分——在InfluxDB中不能没有field;还要注意,field是没有索引的;如果使用field value作为过滤条件来查询,则必须扫描其他条件匹配后的所有值;因此,这些查询相对于tag上的查询(下文会介绍tag的查询)性能会低很多。 一般来说,字段不应包含常用来查询的元数据;

    tag

    ​ 样本数据中的最后两列(locationscientist)就是tag; tag由tag key和tag value组成。tag key和tag value都作为字符串存储,并记录在元数据中。示例数据中的 tag key是locationscientistlocation有两个tag value:12scientist还有两个tag value:langstrothperpetua

    ​ 在上面的数据中,tag set 是不同的每组 tag key 和 tag value的集合,示例数据里有四个tag set:

    location = 1, scientist = langstroth
    location = 2, scientist = langstroth
    location = 1, scientist = perpetua
    location = 2, scientist = perpetua
    

    ​ tag不是必需的字段,但是在你的数据中使用tag总是大有裨益,因为不同于field, tag是索引起来的。这意味着对tag的查询更快,tag是存储常用元数据的最佳选择;

    measurement

    ​ measurement作为tag,fields和time列的容器,measurement的名字是存储在相关fields数据的描述。 measurement的名字是字符串,对于一些SQL用户,measurement在概念上类似于表。样本数据中唯一的测量是census。 名称census告诉我们,fields值记录了butterflieshoneybees的数量,而不是不是它们的大小,方向或某种幸福指数;

    ​ 单个measurement可以有不同的retention policy。 retention policy描述了InfluxDB保存数据的时间(DURATION)以及这些存储在集群中数据的副本数量(REPLICATION)

    ​ 在样本数据中,measurement census中的所有内容都属于autogen的retention policy。 InfluxDB自动创建该存储策略; 它具有无限的持续时间和复制因子设置为1。

    series

    ​ series是共同retention policy,measurement 和 tag set 的集合;以上数据由四个series组成:

    image-20201108195315803

    point

    ​ 最后,point就是具有相同timestamp的相同series的field集合。例如,这就是一个point:

    image-20201108195510990

    ​ 例子里的series的retention policy为autogen,measurement为census,tag set为location = 1, scientist = perpetua。point的timestamp为2015-08-18T00:00:00Z

    ​ 刚刚涵盖的所有内容都存储在数据库(database)中——示例数据位于数据库my_database中。 InfluxDB数据库与传统的关系数据库类似,并作为users,retention policy,continuous以及point的逻辑上的容器。;

    ​ 数据库可以有多个users,retention policy,continuous和measurement。 InfluxDB是一个无模式数据库,意味着可以随时添加新的measurement,tag和field。 它旨在使时间序列数据的工作变得非常棒;

    专业术语

    更多见:https://jasper-zhang1.gitbooks.io/influxdb/content/Concepts/glossary.html

    duration

    ​ retention policy中的一个属性,决定InfluxDB中数据保留多长时间;在duration之前的数据会自动从database中删除掉;

    point

    ​ InfluxDB数据结构的一部分由series中的的一堆field组成。 每个点由其series和timestamp唯一标识。

    ​ 你不能在同一series中存储多个具有相同timestamp的点。 相反,当你使用与该series中现有点相同的timestamp记将新point写入同一series时,该field set将成为旧field set和新field set的并集;

    shard

    ​ shard包含实际的编码和压缩数据,并由磁盘上的TSM文件表示。 每个shard都属于唯一的一个shard group。多个shard可能存在于单个shard group中。每个shard包含一组特定的series。给定shard group中的给定series上的所有点将存储在磁盘上的相同shard(TSM文件)中;

    SQL VS InfluxDB

    形式上

    ​ 下表是一个叫foodships的SQL数据库的例子,并有没有索引的#_foodships列和有索引的park_id,planettime列;

    image-20201108195951962

    这些数据在influxdb中看起来像这样:

    image-20201108200031457

    参考上面的数据,一般可以这么说:

    • InfluxDB的measurement(foodships)和SQL数据库里的table类似;
    • InfluxDB的tag(park_idplanet)类似于SQL数据库里索引的列;
    • InfluxDB中的field(#_foodships)类似于SQL数据库里没有索引的列;
    • InfluxDB里面的数据点(例如2015-04-16T12:00:00Z 5)类似于SQL数据库的行;

    ​ 基于这些数据库术语的比较,InfluxDB的continuous query和retention policy与SQL数据库中的存储过程类似。 它们被指定一次,然后定期自动执行。

    ​ 当然,SQL数据库和InfluxDB之间存在一些重大差异。SQL中的JOIN不适用于InfluxDB中的measurement。而且,正如我们上面提到的那样,一个measurement就像一个SQL的table,其中主索引总是被预设为时间;InfluxDB的时间戳记必须在UNIX epoch(GMT)或格式化为日期时间RFC3339格式的字符串才有效。

    数据操作上

    ​ InfluxQL的select语句来自于SQL中的select形式:

    SELECT <stuff> FROM <measurement_name> WHERE <some_conditions>
    

    where是可选的,在InfluxDB里为了查询到上面数据,需要输入:

    SELECT * FROM "foodships"
    

    如果你仅仅想看planet为Saturn的数据:

    SELECT * FROM "foodships" WHERE "planet" = 'Saturn'
    

    ​ 如果你想看到planet为Saturn,并且在UTC时间为2015年4月16号12:00:01之后的数据:

    SELECT * FROM "foodships" WHERE "planet" = 'Saturn' AND time > '2015-04-16 12:00:01'
    

    ​ 如上例所示,InfluxQL允许您在WHERE子句中指定查询的时间范围。您可以使用包含单引号的日期时间字符串,格式为YYYY-MM-DD HH:MM:SS.mmm(mmm为毫秒,为可选项,您还可以指定微秒或纳秒。您还可以使用相对时间与now()来指代服务器的当前时间戳:

    SELECT * FROM "foodships" WHERE time > now() - 1h
    

    该查询输出measurement为foodships中的数据,其中时间戳比服务器当前时间减1小时(即最近一小时的数据);与now()做计算来决定时间范围的可选单位有:

    字母意思
    u或µ 微秒
    ms 毫秒
    s
    m 分钟
    h 小时
    d
    w 星期

    InfluxQL还支持正则表达式,表达式中的运算符,SHOW语句和GROUP BY语句;

    ​ InfluxDB是针对时间序列数据进行了优化的数据库;这些数据通常来自分布式传感器组,来自大型网站的点击数据或金融交易列表等。

    ​ 这个数据有一个共同之处在于它只看一个点没什么用。一个读者说,在星期二UTC时间为12:38:35时根据他的电脑CPU利用率为12%,这个很难得出什么结论。只有跟其他的series结合并可视化时,它变得更加有用。随着时间的推移开始显现的趋势,是我们从这些数据里真正想要看到的。另外,时间序列数据通常是一次写入,很少更新。

    结果是,由于优先考虑create和read数据的性能而不是update和delete,InfluxDB不是一个完整的CRUD数据库,更像是一个CR-ud。

    写入协议–行协议

    InfluxDB的行协议是一种写入数据点到InfluxDB的文本格式。必须要是这样的格式的数据点才能被Influxdb解析和写入成功;

    语法

    image-20201108201355108

    measurement

    你想要写入数据的measurement,这在行协议中是必需的,例如这里的measurement是weather

    Tag set

    ​ 你想要数据点中包含的tag,tag在行协议里是可选的。注意measurement和tag set是用不带空格的逗号分开的

    用不带空格的=来分割一组tag的键值:

    <tag_key>=<tag_value>
    

    多组tag直接用不带空格的逗号分开:

    <tag_key>=<tag_value>,<tag_key>=<tag_value>
    

    例如上面的tag set由一个tag组成location=us-midwest,现在加另一个tag(season=summer),就变成了这样:

    weather,location=us-midwest,season=summer temperature=82 1465839830100400200
    

    为了获得最佳性能,您应该在将它们发送到数据库之前按键进行排序;排序应该与Go bytes.Compare function的结果相匹配;

    空格1

    ​ 分离 measurement 和 field set,或者如果您使用数据点包含tag set,则使用空格分隔tag set和field set;行协议中空格是必需的;

    ​ 没有 tag set 的有效行协议:

    weather temperature=82 1465839830100400200
    

    Field set

    每个数据点在行协议中至少需要一个field。使用无空格的=分隔field的键值对:

    <field_key>=<field_value>
    

    多组field直接用不带空格的逗号分开:

    <field_key>=<field_value>,<field_key>=<field_value>
    

    例如上面的field set由一个field组成temperature=82,现在加另一个field(bug_concentration=98),就变成了这样:

    weather,location=us-midwest temperature=82,bug_concentration=98 1465839830100400200
    

    空格2

    使用空格分隔field set和可选的时间戳。如果你包含时间戳,则行协议中需要空格。

    Timestamp

    ​ 数据点的时间戳记以纳秒精度Unix时间。行协议中的时间戳是可选的。 如果没有为数据点指定时间戳,InfluxDB会使用服务器的本地纳秒时间戳。

    在这个例子中,时间戳记是1465839830100400200(这就是RFC6393格式的2016-06-13T17:43:50.1004002Z)。下面的行协议是相同的数据点,但没有时间戳;当InfluxDB将其写入数据库时,它将使用您的服务器的本地时间戳而不是2016-06-13T17:43:50.1004002Z

    weather,location=us-midwest temperature=82
    

    使用HTTP API来指定精度超过纳秒的时间戳,例如微秒,毫秒或秒。我们建议使用最粗糙的精度,因为这样可以显着提高压缩率

    数据类型

    Field value可以是整数、浮点数、字符串和布尔值:

    • 浮点数 —— 默认是浮点数,InfluxDB假定收到的所有field value都是浮点数。
      以浮点类型存储上面的82

      weather,location=us-midwest temperature=82 1465839830100400200
      
    • 整数 —— 添加一个i在field之后,告诉InfluxDB以整数类型存储:
      以整数类型存储上面的82

      weather,location=us-midwest temperature=82i 1465839830100400200
      
    • 字符串 —— 双引号把字段值引起来表示字符串:
      以字符串类型存储值too warm

      weather,location=us-midwest temperature="too warm" 1465839830100400200
      
    • 布尔型 —— 表示TRUE可以用t,T,true,True,TRUE;表示FALSE可以用f,F,false,False或者FALSE
      以布尔类型存储值true

    weather,location=us-midwest too_hot=true 1465839830100400200
    

    ​ 在measurement中,field value的类型在分片内不会有差异,但在分片之间可能会有所不同。例如,如果InfluxDB尝试将整数写入到与浮点数相同的分片中,则写入会失败:

    > INSERT weather,location=us-midwest temperature=82 1465839830100400200
    > INSERT weather,location=us-midwest temperature=81i 1465839830100400300
    ERR: {"error":"field type conflict: input field "temperature" on measurement "weather" is type int64, already exists as type float"}
    

    但是,如果InfluxDB将整数写入到一个新的shard中,虽然之前写的是浮点数,那依然可以写成功:

    > INSERT weather,location=us-midwest temperature=82 1465839830100400200
    > INSERT weather,location=us-midwest temperature=81i 1467154750000000000
    >
    

    引号

    • 时间戳不要双或单引号。下面这是无效的行协议;
    • field value不要单引号,即时是字符串类型。下面这是无效的行协议。 例:

      > INSERT weather,location=us-midwest temperature='too warm'
      ERR: {"error":"unable to parse 'weather,location=us-midwest temperature='too warm'': invalid boolean"}
      
    • measurement名称,tag keys,tag value和field key不用单双引号。InfluxDB会假定引号是名称的一部分;

    InfluxDB的设计见解和权衡

    ​ InfluxDB是一个时间序列数据库。针对这种用例进行优化需要进行一些权衡,主要是以牺牲功能为代价来提高性能;以下列出了一些权衡过的设计见解:

    1、对于时间序列用例,我们假设如果相同的数据被多次发送,那么认为客户端几次都是同一笔数据。

    • 优势:通过简化的冲突解决增加了写入性能
    • 劣势:不能存储重复数据;可能会在极少数情况下覆盖数据

    2、删除是罕见的事情,当它们发生时,肯定是针对大量的旧数据,这些数据对于写入来说是冷数据。

    • 优势:限制删除操作,从而增加查询和写入性能
    • 劣势:删除功能受到很大限制

    3、对现有数据的更新是罕见的事件,持续地更新永远不会发生。时间序列数据主要是永远不更新的新数据。

    • 优势:限制更新操作,从而增加查询和写入性能
    • 劣势:更新功能受到很大限制

    4、绝大多数写入都是接近当前时间戳的数据,并且数据是按时间递增的顺序添加。

    • 优势:按时间递增的顺序添加数据明显更高效些
    • 劣势:随机时间或时间不按升序写入点的性能要低得多

    5、 规模至关重要。数据库必须能够处理大量的读取和写入

    • 优势:数据库可以处理大量的读取和写入
    • 劣势:InfluxDB开发团队被迫做出权衡来提高性能

    6、能够写入和查询数据比具有强一致性更重要。

    • 优势:多个客户端可以在高负载的情况下完成查询和写入数据库操作
    • 劣势:如果数据库负载较重,查询返回结果可能不包括最近的点

    7、许多时间序列都是短暂的。经常是时间序列,只出现了几个小时,然后消失,例如一个新的主机,开机并监控数据被写入一段时间,然后被关闭。

    • 优势:InfluxDB善于管理不连续数据
    • 劣势:无模式设计意味着不支持某些数据库功能,例如没有交叉表连接

    8、没有数据点太重要了。

    • 优势:InfluxDB具有非常强大的工具来处理聚合数据和大数据集
    • 劣势:数据点没有传统意义上的ID,它们被时间戳和series区分开来

    存储引擎

    ​ influxdb的存储引擎具有wal和一组只读数据文件,它们在概念上与LSM树中的SSTables类似;TSM文件包含排序,压缩的series数据。

    ​ 存储引擎将多个组件结合在一起,并提供用于存储和查询series数据的外部接口。 它由许多组件组成,每个组件都起着特定的作用:

    • In-Memory Index —— 内存中的索引是分片上的共享索引,可以快速访问measurement,tag和series。 引擎使用该索引,但不是特指存储引擎本身。
    • WAL —— WAL是一种写优化的存储格式,允许写入持久化,但不容易查询。 对WAL的写入就是append到固定大小的段中。
    • Cache —— Cache是存储在WAL中的数据的内存中的表示。 它在运行时可以被查询,并与TSM文件中存储的数据进行合并。
    • TSM Files —— TSM Files中保存着柱状格式的压缩过的series数据。
    • FileStore —— FileStore可以访问磁盘上的所有TSM文件。 它可以确保在现有的TSM文件被替换时以及删除不再使用的TSM文件时,创建TSM文件是原子性的。
    • Compactor —— Compactor负责将不够优化的Cache和TSM数据转换为读取更为优化的格式。 它通过压缩series,去除已经删除的数据,优化索引并将较小的文件组合成较大的文件来实现。
    • Compaction Planner —— Compaction Planner决定哪个TSM文件已准备好进行压缩,并确保多个并发压缩不会彼此干扰。
    • Compression —— Compression由各种编码器和解码器对特定数据类型作处理。一些编码器是静态的,总是以相同的方式编码相同的类型; 还有一些可以根据数据的类型切换其压缩策略。
    • Writers/Readers —— 每个文件类型(WAL段,TSM文件,tombstones等)都有相应格式的Writers和Readers。

    ​ InfluxDB的0.9版本使用BoltDB作为底层存储引擎。下面要介绍的TSM,它在0.9.5中发布,是InfluxDB 0.11+中唯一支持的存储引擎,包括整个1.x系列。

    ​ BoltDB,这是一个基于内存映射B+ Tree的引擎,它是针对读取进行了优化的。最后,我们最终建立了我们自己的存储引擎,它在许多方面与LSM树类似。借助我们的新存储引擎,我们可以达到比B+ Tree实现高达45倍的磁盘空间使用量的减少,甚至比使用LevelDB及其变体有更高的写入吞吐量和压缩率。

    influxdb + 混合压缩算法

    找源代码与 gzip 压缩有关的部分

    restore

    数据的恢复restore要使用gzip压缩算法压缩,在路径influxd/restore/restore.go中;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjN0lCD9-1606126788698)(https://raw.githubusercontent.com/Luweir/picpicgo/main/img/20201123144327.png)]

    back up

    数据的备份back up要使用gzip压缩算法压缩,在路径influxd/backup/restore.go中;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJqbunkv-1606126788699)(https://raw.githubusercontent.com/Luweir/picpicgo/main/img/20201123144331.png)]

    Go语言的compress/gzip

    压缩

    func NewWriter

    func NewWriter(w io.Writer) *Writer
    

    ​ NewWriter创建并返回一个Writer;写入返回值的数据都会在压缩后写入w;调用者有责任在结束写入后调用返回值的Close方法。因为写入的数据可能保存在缓冲中没有刷新入下层;

    func (*Writer) Write

    func (z *Writer) Write(p []byte) (int, error)
    

    ​ Write将p压缩后写入下层 io.Writer 接口(NewWriter返回的Writer);压缩后的数据不一定会立刻刷新(压缩后的数据放在缓存中),除非Writer被关闭或者显式的刷新,才会将缓存中的数据刷新到下层 io.Writer 接口中;

    接下来,关闭或者刷新缓存

    func (*Writer) Flush

    func (z *Writer) Flush() error
    

    Flush将缓冲中的压缩数据刷新到下层io.Writer接口中;本方法主要用在传输压缩数据的网络连接中,以保证远端的接收者可以获得足够的数据来重构数据报。Flush会阻塞直到所有缓冲中的数据都写入下层io.Writer接口后才返回;

    所以关闭即可

    func (*Writer) Close

    func (z *Writer) Close() error
    

    调用Close会关闭z,但不会关闭下层io.Writer接口;

    func Copy

    func Copy(dst Writer, src Reader) (written int64, err error)
    

    将src的数据拷贝到dst,直到在src上到达EOF或发生错误。返回拷贝的字节数和遇到的第一个错误。

    对成功的调用,返回值err为nil而非EOF,因为Copy定义为从src读取直到EOF,它不会将读取到EOF视为应报告的错误。如果src实现了WriterTo接口,本函数会调用src.WriteTo(dst)进行拷贝;否则如果dst实现了ReaderFrom接口,本函数会调用dst.ReadFrom(src)进行拷贝。

    源代码cmd/influxd/backup/backup.go

    image-20201108212223667

    image-20201108212226263

    解压

    func NewReader

    func NewReader(r io.Reader) (*Reader, error)
    

    NewReader返回一个从 r 读取并解压数据的*Reader;其实现会缓冲输入流的数据,并可能从r中读取比需要的更多的数据;调用者有责任在读取完毕后调用返回值的Close方法;

    源代码cmd/influxd/restore/restore.go

    image-20201108214445027

    image-20201108213505480

    简化整个压缩和解压流程

    image-20201108214559532

  • 相关阅读:
    Criteria和Detachedcriteria的区别及应用(转)
    Hibernate中DetachedCriteria的使用(转)
    jQuery的dom操作
    MyEclipse6.5安装SVN插件的三种方法(转)
    hibernate反向生成实体类
    PHP写文本日志
    关于微软ADO.NET提供的组件库里的UpdateDataSet()的用法心得
    比较文件内容是否一致
    在ListView的顶部和底部加入其他View
    Android中使用shape来定义控件的显示属性
  • 原文地址:https://www.cnblogs.com/Luweir/p/14147224.html
Copyright © 2011-2022 走看看