├── .gitignore ├── Concepts ├── crosswalk.md ├── glossary.md ├── images │ ├── TSM_blocks.png │ ├── TSM_compression.png │ ├── TSM_footer.png │ ├── TSM_header.png │ ├── TSM_index.png │ └── TSM_sections.png ├── index.md ├── insights_tradeoffs.md ├── key_concepts.md ├── schema_and_data_layout.md └── storage_engine.md ├── Guide ├── downsampling_and_retention.md ├── hardware_sizing.md ├── https_setup.md ├── images │ └── series-cardinality.png ├── index.md ├── querying_data.md └── writing_data.md ├── Introduction ├── getting_start.md ├── index.md └── installation.md ├── Query_language ├── authentication_and_authorization.md ├── continuous_queries.md ├── data_exploration.md ├── database_management.md ├── functions.md ├── index.md ├── math_operators.md └── schema_exploration.md ├── README.md ├── SUMMARY.md ├── Troubleshooting ├── error_messages.md ├── faq.md ├── index.md ├── query_management.md └── system_monitor.md └── Write_protocols ├── index.md └── line_protocol.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _book/ 3 | -------------------------------------------------------------------------------- /Concepts/crosswalk.md: -------------------------------------------------------------------------------- 1 | # 与SQL比较 2 | 3 | ## database里面是什么? 4 | 该章向SQL用户介绍了InfluxDB哪里像SQL数据库以及它哪里不像。将突出讲了两者之间的一些主要区别,并提供了不同的数据库术语和查询语言。 5 | 6 | ### 一般来说 7 | InfluxDB是一个时间序列数据库,SQL数据库可以提供时序的功能,但严格说时序不是其目的。简而言之,InfluxDB用于存储大量的时间序列数据,并对这些数据进行快速的实时分析。 8 | 9 | ### 时间是一切 10 | 在InfluxDB中,timestamp标识了在任何给定数据series中的单个点。这就像一个SQL数据库表,其中主键是由系统预先设置的,并且始终是时间。 11 | 12 | InfluxDB还会认识到您的schema可能随时间而改变。在InfluxDB中,您不需要在前面定义schema。数据点可以有一个measurement的field的一个,也可以有这个measurement的所有field,或其间的任何数字。 您可以在写数据的时候为该measurement添加一个新的field。 13 | 14 | ## 术语 15 | 下表是一个叫`foodships`的SQL数据库的例子,并有没有索引的`#_foodships`列和有索引的`park_id`,`planet`和`time`列。 16 | 17 | | park_id | planet | time | #_foodships | 18 | |---------|---------|---------------------|--------------| 19 | | 1 | Earth | 1429185600000000000 | 0 | 20 | | 1 | Earth | 1429185601000000000 | 3 | 21 | | 1 | Earth | 1429185602000000000 | 15 | 22 | | 1 | Earth | 1429185603000000000 | 15 | 23 | | 2 | Saturn | 1429185600000000000 | 5 | 24 | | 2 | Saturn | 1429185601000000000 | 9 | 25 | | 2 | Saturn | 1429185602000000000 | 10 | 26 | | 2 | Saturn | 1429185603000000000 | 14 | 27 | | 3 | Jupiter | 1429185600000000000 | 20 | 28 | | 3 | Jupiter | 1429185601000000000 | 21 | 29 | | 3 | Jupiter | 1429185602000000000 | 21 | 30 | | 3 | Jupiter | 1429185603000000000 | 20 | 31 | | 4 | Saturn | 1429185600000000000 | 5 | 32 | | 4 | Saturn | 1429185601000000000 | 5 | 33 | | 4 | Saturn | 1429185602000000000 | 6 | 34 | | 4 | Saturn | 1429185603000000000 | 5 | 35 | 36 | 这些数据在InfluxDB看起来就像这样: 37 | 38 | ``` 39 | name: foodships 40 | tags: park_id=1, planet=Earth 41 | time #_foodships 42 | ---- ------------ 43 | 2015-04-16T12:00:00Z 0 44 | 2015-04-16T12:00:01Z 3 45 | 2015-04-16T12:00:02Z 15 46 | 2015-04-16T12:00:03Z 15 47 | 48 | name: foodships 49 | tags: park_id=2, planet=Saturn 50 | time #_foodships 51 | ---- ------------ 52 | 2015-04-16T12:00:00Z 5 53 | 2015-04-16T12:00:01Z 9 54 | 2015-04-16T12:00:02Z 10 55 | 2015-04-16T12:00:03Z 14 56 | 57 | name: foodships 58 | tags: park_id=3, planet=Jupiter 59 | time #_foodships 60 | ---- ------------ 61 | 2015-04-16T12:00:00Z 20 62 | 2015-04-16T12:00:01Z 21 63 | 2015-04-16T12:00:02Z 21 64 | 2015-04-16T12:00:03Z 20 65 | 66 | name: foodships 67 | tags: park_id=4, planet=Saturn 68 | time #_foodships 69 | ---- ------------ 70 | 2015-04-16T12:00:00Z 5 71 | 2015-04-16T12:00:01Z 5 72 | 2015-04-16T12:00:02Z 6 73 | 2015-04-16T12:00:03Z 5 74 | ``` 75 | 76 | 参考上面的数据,一般可以这么说: 77 | 78 | * InfluxDB的measurement(`foodships`)和SQL数据库里的table类似; 79 | * InfluxDB的tag(`park_id`和`planet`)类似于SQL数据库里索引的列; 80 | * InfluxDB中的field(`#_foodships`)类似于SQL数据库里没有索引的列; 81 | * InfluxDB里面的数据点(例如`2015-04-16T12:00:00Z 5`)类似于SQL数据库的行; 82 | 83 | 基于这些数据库术语的比较,InfluxDB的continuous query和retention policy与SQL数据库中的存储过程类似。 它们被指定一次,然后定期自动执行。 84 | 85 | 当然,SQL数据库和InfluxDB之间存在一些重大差异。SQL中的`JOIN`不适用于InfluxDB中的measurement。而且,正如我们上面提到的那样,一个measurement就像一个SQL的table,其中主索引总是被预设为时间。InfluxDB的时间戳记必须在UNIX epoch(GMT)或格式化为日期时间RFC3339格式的字符串才有效。 86 | 87 | 查看更多关于InfluxDB的术语的详细解释,请参考[专业术语](glossary.md)。 88 | 89 | ## InfluxQL和SQL 90 | 在InfluxDB中InfluxQL是一种类SQL的语言。对于来自其他SQL或类SQL环境的用户来说,它已经被精心设计,而且还提供特定于存储和分析时间序列数据的功能。 91 | 92 | InfluxQL的`select`语句来自于SQL中的`select`形式: 93 | 94 | ``` 95 | SELECT FROM WHERE 96 | ``` 97 | 98 | `where`是可选的,在InfluxDB里为了查询到上面数据,需要输入: 99 | 100 | ``` 101 | SELECT * FROM "foodships" 102 | ``` 103 | 104 | 如果你仅仅想看planet为`Saturn`的数据: 105 | 106 | ``` 107 | SELECT * FROM "foodships" WHERE "planet" = 'Saturn' 108 | ``` 109 | 110 | 如果你想看到planet为`Saturn`,并且在UTC时间为2015年4月16号12:00:01之后的数据: 111 | 112 | ``` 113 | SELECT * FROM "foodships" WHERE "planet" = 'Saturn' AND time > '2015-04-16 12:00:01' 114 | ``` 115 | 如上例所示,InfluxQL允许您在`WHERE`子句中指定查询的时间范围。您可以使用包含单引号的日期时间字符串,格式为YYYY-MM-DD HH:MM:SS.mmm(mmm为毫秒,为可选项,您还可以指定微秒或纳秒。您还可以使用相对时间与`now()`来指代服务器的当前时间戳: 116 | 117 | ``` 118 | SELECT * FROM "foodships" WHERE time > now() - 1h 119 | ``` 120 | 121 | 该查询输出measurement为`foodships`中的数据,其中时间戳比服务器当前时间减1小时。与now()做计算来决定时间范围的可选单位有: 122 | 123 | 字母|意思 124 | ----|---- 125 | u或µ|微秒 126 | ms|毫秒 127 | s|秒 128 | m|分钟 129 | h|小时 130 | d|天 131 | w|星期 132 | 133 | InfluxQL还支持正则表达式,表达式中的运算符,`SHOW`语句和`GROUP BY`语句。有关这些主题的深入讨论,请参阅我们的[数据探索]()页面。 InfluxQL功能还包括`COUNT`,`MIN`,`MAX`,`MEDIAN`,`DERIVATIVE`等。 有关完整列表,请查看[函数]()页面。 134 | 135 | ## 为什么InfluxDB不是CRUD的一个解释 136 | InfluxDB是针对时间序列数据进行了优化的数据库。这些数据通常来自分布式传感器组,来自大型网站的点击数据或金融交易列表等。 137 | 138 | 这个数据有一个共同之处在于它只看一个点没什么用。一个读者说,在星期二UTC时间为12:38:35时根据他的电脑CPU利用率为12%,这个很难得出什么结论。只有跟其他的series结合并可视化时,它变得更加有用。随着时间的推移开始显现的趋势,是我们从这些数据里真正想要看到的。另外,时间序列数据通常是一次写入,很少更新。 139 | 140 | 结果是,由于优先考虑create和read数据的性能而不是update和delete,InfluxDB不是一个完整的CRUD数据库,更像是一个CR-ud。 -------------------------------------------------------------------------------- /Concepts/glossary.md: -------------------------------------------------------------------------------- 1 | # 专业术语 2 | 3 | ## aggregation 4 | 这是一个InfluxQL的函数,可以返回一堆数据的聚合结果,可以看[InfluxQL函数]()中现有的以及即将支持的聚合函数列表。 5 | 6 | ## batch 7 | 用换行符分割的数据点的集合,这批数据可以使用HTTP请求写到数据库中。用这种HTTP接口的方式可以大幅降低HTTP的负载。尽管不同的场景下更小或更大的batch可能有更好地性能,InfluxData建议每个batch的大小在5000~10000个数据点。 8 | 9 | ## continuous query(CQ) 10 | 这个一个在数据库中自动周期运行的InfluxQL的查询。Continuous query在`select`语句里需要一个函数,并且一定会包含一个`GROUP BY time()`的语法。 11 | 12 | ## database 13 | 对于users,retention policy,continuous query以及时序数据的一个逻辑上的集合。 14 | 15 | ## duration 16 | retention policy中的一个属性,决定InfluxDB中数据保留多长时间。在duration之前的数据会自动从database中删除掉。 17 | 18 | ## field 19 | InfluxDB数据中记录metadata和真实数据的键值对。fields在InfluxDB的数据结构中是必须的且不会被索引。如果要用field做查询条件的话,那就必须遍历所选时间范围里面的所有数据点,这种方式对比与tag效率会差很多。 20 | 21 | ## field key 22 | 组成field的键值对里面的键的部分。field key是字符串且保存在metadata中。 23 | 24 | ## field set 25 | 数据点上field key和field value的集合。 26 | 27 | ## field value 28 | 组成field的键值对里面的值的部分。field value才是真正的数据,可以是字符串,浮点数,整数,布尔型数据。一个field value总是和一个timestamp相关联。 29 | 30 | field value不会被索引,如果要对field value做过滤话,那就必须遍历所选时间范围里面的所有数据点,这种方式对比与tag效率会差很多。 31 | 32 | ## function 33 | 包括InfluxQL中的聚合,查询和转换,可以在[InfluxQL函数]()中查看InfluxQL中的完整函数列表。 34 | 35 | ## identifier 36 | 涉及continuous query的名字,database名字,field keys,measurement名字,retention policy名字,subscription 名字,tag keys以及user 名字的一个标记。 37 | 38 | ## line protocol 39 | 写入InfluxDB时的数据点的文本格式。 40 | 41 | ## measurement 42 | InfluxDB数据结果中的一部分,描述了存在关联field中的数据的意义,measurement是字符串。 43 | 44 | ## metastore 45 | 包含了系统状态的内部信息。metastore包含了用户信息,database,retention policy,shard metadata,continuous query以及subscription。 46 | 47 | ## node 48 | 一个独立的`influxd`进程。 49 | 50 | ## now() 51 | 本地服务器的当前纳秒级时间戳。 52 | 53 | ## point 54 | InfluxDB数据结构的一部分由series中的的一堆field组成。 每个点由其series和timestamp唯一标识。 55 | 56 | 你不能在同一series中存储多个具有相同timestamp的点。 相反,当你使用与该series中现有点相同的timestamp记将新point写入同一series时,该field set将成为旧field set和新field set的并集。 57 | 58 | ## query 59 | 从InfluxDB里面获取数据的一个操作 60 | 61 | ## replication factor 62 | retention policy的一个参数,决定在集群模式下数据的副本的个数。InfluxDB在N个数据节点上复制数据,其中N就是replication factor。 63 | 64 | >replication factor在单节点的实例上不起作用 65 | 66 | ## retention policy(RP) 67 | InfluxDB数据结构的一部分,描述了InfluxDB保存数据的长短(duration),数据存在集群里面的副本数(replication factor),以及shard group的时间范围(shard group duration)。RPs在每个database里面是唯一的,连同measurement和tag set定义一个series。 68 | 69 | 当你创建一个database的时候,InfluxDB会自动创建一个叫做`autogen`的retention policy,其duration为永远,replication factor为1,shard group的duration设为的七天。 70 | 71 | ## schema 72 | 数据在InfluxDB里面怎么组织。InfluxDB的schema的基础是database,retention policy,series,measurement,tag key,tag value以及field keys。 73 | 74 | ## selector 75 | 一个InfluxQL的函数,从特定范围的数据点中返回一个点。可以看[InfluxQL函数]()中现有的以及即将支持的selector函数列表。 76 | 77 | ## series 78 | InfluxDB数据结构的集合,一个特定的series由measurement,tag set和retention policy组成。 79 | 80 | >注意:field set不是series的一部分 81 | 82 | ## series cardinality 83 | 在InfluxDB实例上唯一database,measurement和tag set组合的数量。 84 | 85 | 例如,假设一个InfluxDB实例有一个单独的database,一个measurement。这个measurement有两个tag key:`email`和`status`。如果有三个不同的email,并且每个email的地址关联两个不同的`status`,那么这个measurement的series cardinality就是6(3*2=6): 86 | 87 | email|status 88 | -----|----- 89 | lorr@influxdata.com|start 90 | lorr@influxdata.com|finish 91 | marv@influxdata.com|start 92 | marv@influxdata.com|finish 93 | cliff@influxdata.com|start 94 | cliff@influxdata.com|finish 95 | 96 | 注意到,因为所依赖的tag的存在,在某些情况下,简单地执行该乘法可能会高估series cardinality。 依赖的tag是由另一个tag限定的tag并不增加series cardinality。 如果我们将tag`firstname`添加到上面的示例中,则系列基数不会是18(3 * 2 * 3 = 18)。 它将保持不变为6,因为`firstname`已经由`email`覆盖了: 97 | 98 | email|status|firstname 99 | -----|-----|----- 100 | lorr@influxdata.com|start|lorraine 101 | lorr@influxdata.com|finish|lorraine 102 | marv@influxdata.com|start|marvin 103 | marv@influxdata.com|finish|marvin 104 | cliff@influxdata.com|start|clifford 105 | cliff@influxdata.com|finish|clifford 106 | 107 | 在[常见问题]()中可以看到怎么根据series cardinality来查询InfluxDB。 108 | 109 | ## server 110 | 一个运行InfluxDB的服务器,可以使虚拟机也可以是物理机。每个server上应该只有一个InfluxDB的进程。 111 | 112 | ## shard 113 | shard包含实际的编码和压缩数据,并由磁盘上的TSM文件表示。 每个shard都属于唯一的一个shard group。多个shard可能存在于单个shard group中。每个shard包含一组特定的series。给定shard group中的给定series上的所有点将存储在磁盘上的相同shard(TSM文件)中。 114 | 115 | ## shard duration 116 | shard duration决定了每个shard group跨越多少时间。具体间隔由retention policy中的`SHARD DURATION`决定。 117 | 118 | 例如,如果retention policy的`SHARD DURATION`设置为1w,则每个shard group将跨越一周,并包含时间戳在该周内的所有点。 119 | 120 | ## shard group 121 | shard group是shard的逻辑组合。shard group由时间和retention policy组织。包含数据的每个retention policy至少包含一个关联的shard group。给定的shard group包含shard group覆盖的间隔的数据的所有shard。每个shard group跨越的间隔是shard的持续时间。 122 | 123 | ## subscription 124 | subscription允许[Kapacitor](https://docs.influxdata.com/kapacitor/latest/)在push model中接收来自InfluxDB的数据,而不是基于查询数据的pull model。当Kapacitor配置为使用InfluxDB时,subscription将自动将订阅的数据库的每个写入从InfluxDB推送到Kapacitor。subscription可以使用TCP或UDP传输写入。 125 | 126 | ## tag 127 | InfluxDB数据结构中的键值对,tags在InfluxDB的数据中是可选的,但是它们可用于存储常用的metadata; tags会被索引,因此tag上的查询是很高效的。 128 | 129 | ## tag key 130 | 组成tag的键值对中的键部分,tag key是字符串,存在metadata中。 131 | 132 | ## tag set 133 | 数据点上tag key和tag value的集合。 134 | 135 | ## tag value 136 | 组成tag的键值对中的值部分,tag value是字符串,存在metadata中。 137 | 138 | ## timestamp 139 | 数据点关联的日期和时间,在InfluxDB里的所有时间都是UTC的。 140 | 141 | ## transformation 142 | 一个InfluxQL的函数,返回一个值或是从特定数据点计算后的一组值。但是不是返回这些数据的聚合值。 143 | 144 | ## tsm(Time Structured Merge tree) 145 | InfluxDB的专用数据存储格式。 TSM可以比现有的B+或LSM树实现更大的压缩和更高的写入和读取吞吐量。 146 | 147 | ## user 148 | 在InfluxDB里有两种类型的用户: 149 | 150 | * admin用户对所有数据库都有读写权限,并且有管理查询和管理用户的全部权限。 151 | * 非admin用户有针对database的可读,可写或者二者兼有的权限。 152 | 153 | 当认证开启之后,InfluxDB只执行使用有效的用户名和密码发送的HTTP请求。 154 | 155 | ## values per second 156 | 对数据持续到InfluxDB的速率的度量,写入速度通常以values per second表示。 157 | 158 | 要计算每秒速率的值,将每秒写入的点数乘以每点存储的值数。 例如,如果这些点各有四个field,并且每秒写入batch是5000个点,那么values per second是每点4个fieldx每batch 5000个点x10个batch/秒=每秒200,000个值。 159 | 160 | ## wal(Write Ahead Log) 161 | 最近写的点数的临时缓存。为了减少访问永久存储文件的频率,InfluxDB将最新的数据点缓冲进WAL中,直到其总大小或时间触发然后flush到长久的存储空间。这样可以有效地将写入batch处理到TSM中。 162 | 163 | 可以查询WAL中的点,并且系统重启后仍然保留。在进程开始时,在系统接受新的写入之前,WAL中的所有点都必须flushed。 164 | 165 | -------------------------------------------------------------------------------- /Concepts/images/TSM_blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_blocks.png -------------------------------------------------------------------------------- /Concepts/images/TSM_compression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_compression.png -------------------------------------------------------------------------------- /Concepts/images/TSM_footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_footer.png -------------------------------------------------------------------------------- /Concepts/images/TSM_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_header.png -------------------------------------------------------------------------------- /Concepts/images/TSM_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_index.png -------------------------------------------------------------------------------- /Concepts/images/TSM_sections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Concepts/images/TSM_sections.png -------------------------------------------------------------------------------- /Concepts/index.md: -------------------------------------------------------------------------------- 1 | # 概念介绍 2 | 3 | 理解下面的概念,会让你更加充分利用InfluxDB。 4 | 5 | ## [关键概念](key_concepts.md) 6 | 对InfluxDB核心架构的关键概念作简要说明,对于初学者来说很重要。 7 | 8 | ## [专业术语](glossary.md) 9 | 列出InfluxDB的术语及其定义。 10 | 11 | 12 | ## [与SQL比较](crosswalk.md) 13 | 14 | 15 | ## [InfluxDB的设计见解和权衡](insights_tradeoffs.md) 16 | 简要介绍了在设计InfluxDB的时候对性能做的一些权衡。 17 | 18 | ## [schema设计](schema_and_data_layout.md) 19 | InfluxDB时间序列数据结构的概述及其如何影响性能。 20 | 21 | 22 | ## [存储引擎](storage_engine.md) 23 | 概述下InfluxDB是如何将数据存储在磁盘上。 24 | -------------------------------------------------------------------------------- /Concepts/insights_tradeoffs.md: -------------------------------------------------------------------------------- 1 | # InfluxDB的设计见解和权衡 2 | 3 | InfluxDB是一个时间序列数据库。针对这种用例进行优化需要进行一些权衡,主要是以牺牲功能为代价来提高性能。以下列出了一些权衡过的设计见解: 4 | 5 | 1、对于时间序列用例,我们假设如果相同的数据被多次发送,那么认为客户端几次都是同一笔数据。 6 | 7 | * 优势:通过简化的冲突解决增加了写入性能 8 | * 劣势:不能存储重复数据;可能会在极少数情况下覆盖数据 9 | 10 | 2、删除是罕见的事情。当它们发生时,肯定是针对大量的旧数据,这些数据对于写入来说是冷数据。 11 | 12 | * 优势:限制删除操作,从而增加查询和写入性能 13 | * 劣势:删除功能受到很大限制 14 | 15 | 3、对现有数据的更新是罕见的事件,持续地更新永远不会发生。时间序列数据主要是永远不更新的新数据。 16 | 17 | * 优势:限制更新操作,从而增加查询和写入性能 18 | * 劣势:更新功能受到很大限制 19 | 20 | 4、绝大多数写入都是接近当前时间戳的数据,并且数据是按时间递增的顺序添加。 21 | 22 | * 优势:按时间递增的顺序添加数据明显更高效些 23 | * 劣势:随机时间或时间不按升序写入点的性能要低得多 24 | 25 | 5、 规模至关重要。数据库必须能够处理大量的读取和写入。 26 | 27 | * 优势:数据库可以处理大量的读取和写入 28 | * 劣势:InfluxDB开发团队被迫做出权衡来提高性能 29 | 30 | 6、能够写入和查询数据比具有强一致性更重要。 31 | 32 | * 优势:多个客户端可以在高负载的情况下完成查询和写入数据库操作 33 | * 劣势:如果数据库负载较重,查询返回结果可能不包括最近的点 34 | 35 | 7、许多时间序列都是短暂的。经常是时间序列,只出现了几个小时,然后消失,例如一个新的主机,开机并监控数据被写入一段时间,然后被关闭。 36 | 37 | * 优势:InfluxDB善于管理不连续数据 38 | * 劣势:无模式设计意味着不支持某些数据库功能,例如没有交叉表连接 39 | 40 | 8、没有数据点太重要了。 41 | 42 | * 优势:InfluxDB具有非常强大的工具来处理聚合数据和大数据集 43 | * 劣势:数据点没有传统意义上的ID,它们被时间戳和series区分开来 44 | -------------------------------------------------------------------------------- /Concepts/key_concepts.md: -------------------------------------------------------------------------------- 1 | # 关键概念 2 | 3 | 在深入InfluxDB之前,最好是了解数据库的一些关键概念。 本文档简要介绍了这些概念和常用的InfluxDB术语。 我们在下面列出了所有涵盖的术语,但是我们建议您从头到尾阅读本文档,以获得对我们最喜爱的时间序列数据库的更全面了解。 4 | 5 | |**database**|**field key**|**field set**| 6 | |:--:| :--:|:--: | 7 | |**field value**|**measurement**|**point**| 8 | |**retention policy**|**series**|**tag key**| 9 | |**tag set**|**tag value**| **timestamp**| 10 | 11 | ## 示例数据 12 | 下一节将参考下面列出的数据。 虽然数据是伪造的,但在InfluxDB中是一个很通用的场景。 数据展示了在2015年8月18日午夜至2015年8月18日上午6时12分在两个地点`location`(地点`1`和地点`2`)显示两名科学家`scientists`(`langstroth`和`perpetua`)计数的蝴蝶(`butterflies`)和蜜蜂(`honeybees`)数量。 假设数据存在名为`my_database`的数据库中,而且存储策略是`autogen`。 13 | 14 | ``` 15 | name: census 16 | -———————————— 17 | time butterflies honeybees location scientist 18 | 2015-08-18T00:00:00Z 12 23 1 langstroth 19 | 2015-08-18T00:00:00Z 1 30 1 perpetua 20 | 2015-08-18T00:06:00Z 11 28 1 langstroth 21 | 2015-08-18T00:06:00Z 3 28 1 perpetua 22 | 2015-08-18T05:54:00Z 2 11 2 langstroth 23 | 2015-08-18T06:00:00Z 1 10 2 langstroth 24 | 2015-08-18T06:06:00Z 8 23 2 perpetua 25 | 2015-08-18T06:12:00Z 7 22 2 perpetua 26 | ``` 27 | 28 | 其中census是`measurement`,butterflies和honeybees是`field key`,location和scientist是`tag key`。 29 | 30 | ## 讨论 31 | 现在您已经在InfluxDB中看到了一些示例数据,本节将详细分析这些数据。 32 | 33 | InfluxDB是一个时间序列数据库,因此我们开始一切的根源就是——时间。在上面的数据中有一列是`time`,在InfluxDB中所有的数据都有这一列。`time`存着时间戳,这个时间戳以[RFC3339](https://www.ietf.org/rfc/rfc3339.txt)格式展示了与特定数据相关联的UTC日期和时间。 34 | 35 | 接下来两个列叫作`butterflies`和`honeybees`,称为fields。fields由field key和field value组成。field key(`butterflies`和`honeybees`)都是字符串,他们存储元数据;field key `butterflies`告诉我们蝴蝶的计数从12到7;field key `honeybees`告诉我们蜜蜂的计数从23变到22。 36 | 37 | field value就是你的数据,它们可以是字符串、浮点数、整数、布尔值,因为InfluxDB是时间序列数据库,所以field value总是和时间戳相关联。 38 | 39 | 在示例中,field value如下: 40 | 41 | ``` 42 | 12 23 43 | 1 30 44 | 11 28 45 | 3 28 46 | 2 11 47 | 1 10 48 | 8 23 49 | 7 22 50 | ``` 51 | 52 | 在上面的数据中,每组field key和field value的集合组成了`field set`,在示例数据中,有八个`field set`: 53 | 54 | ``` 55 | butterflies = 12 honeybees = 23 56 | butterflies = 1 honeybees = 30 57 | butterflies = 11 honeybees = 28 58 | butterflies = 3 honeybees = 28 59 | butterflies = 2 honeybees = 11 60 | butterflies = 1 honeybees = 10 61 | butterflies = 8 honeybees = 23 62 | butterflies = 7 honeybees = 22 63 | ``` 64 | 65 | field是InfluxDB数据结构所必需的一部分——在InfluxDB中不能没有field。还要注意,field是没有索引的。如果使用field value作为过滤条件来查询,则必须扫描其他条件匹配后的所有值。因此,这些查询相对于tag上的查询(下文会介绍tag的查询)性能会低很多。 一般来说,字段不应包含常用来查询的元数据。 66 | 67 | 样本数据中的最后两列(`location`和`scientist`)就是tag。 tag由tag key和tag value组成。tag key和tag value都作为字符串存储,并记录在元数据中。示例数据中的tag key是`location`和`scientist`。 `location`有两个tag value:`1`和`2`。`scientist`还有两个tag value:`langstroth`和`perpetua`。 68 | 69 | 在上面的数据中,tag set是不同的每组tag key和tag value的集合,示例数据里有四个tag set: 70 | 71 | ``` 72 | location = 1, scientist = langstroth 73 | location = 2, scientist = langstroth 74 | location = 1, scientist = perpetua 75 | location = 2, scientist = perpetua 76 | ``` 77 | 78 | tag不是必需的字段,但是在你的数据中使用tag总是大有裨益,因为不同于field, tag是索引起来的。这意味着对tag的查询更快,tag是存储常用元数据的最佳选择。 79 | 80 | >#### 不同场景下的数据结构设计 81 | >如果你说你的大部分的查询集中在字段`honeybees`和`butterflies`上: 82 | > 83 | ``` 84 | SELECT * FROM "census" WHERE "butterflies" = 1 85 | SELECT * FROM "census" WHERE "honeybees" = 23 86 | ``` 87 | > 88 | >因为field是没有索引的,在第一个查询里面InfluxDB会扫描所有的`butterflies`的值,第二个查询会扫描所有`honeybees`的值。这样会使请求时间很长,特别在规模很大时。为了优化你的查询,你应该重新设计你的数据结果,把field(`butterflies`和`honeybees`)改为tag,而将tag(`location`和`scientist`)改为field。 89 | > 90 | ``` 91 | name: census 92 | -———————————— 93 | time location scientist butterflies honeybees 94 | 2015-08-18T00:00:00Z 1 langstroth 12 23 95 | 2015-08-18T00:00:00Z 1 perpetua 1 30 96 | 2015-08-18T00:06:00Z 1 langstroth 11 28 97 | 2015-08-18T00:06:00Z 1 perpetua 3 28 98 | 2015-08-18T05:54:00Z 2 langstroth 2 11 99 | 2015-08-18T06:00:00Z 2 langstroth 1 10 100 | 2015-08-18T06:06:00Z 2 perpetua 8 23 101 | 2015-08-18T06:12:00Z 2 perpetua 7 22 102 | ``` 103 | >现在`butterflies`和`honeybees`是tag了,当你再用上面的查询语句时,就不会扫描所有的值了,这也意味着查询更快了。 104 | 105 | measurement作为tag,fields和time列的容器,measurement的名字是存储在相关fields数据的描述。 measurement的名字是字符串,对于一些SQL用户,measurement在概念上类似于表。样本数据中唯一的测量是`census`。 名称`census`告诉我们,fields值记录了`butterflies`和`honeybees`的数量,而不是不是它们的大小,方向或某种幸福指数。 106 | 107 | 单个measurement可以有不同的retention policy。 retention policy描述了InfluxDB保存数据的时间(DURATION)以及这些存储在集群中数据的副本数量(REPLICATION)。 如果您有兴趣阅读有关retention policy的更多信息,请查看[数据库管理]()章节。 108 | 109 | >注意:在单节点的实例下,Replication系数不管用。 110 | 111 | 在样本数据中,measurement `census`中的所有内容都属于`autogen`的retention policy。 InfluxDB自动创建该存储策略; 它具有无限的持续时间和复制因子设置为1。 112 | 113 | 现在你已经熟悉了measurement,tag set和retention policy,那么现在是讨论series的时候了。 在InfluxDB中,series是共同retention policy,measurement和tag set的集合。 以上数据由四个series组成: 114 | 115 | 任意series编号|retention policy|measurement|tag set 116 | ------|------|-----|---- 117 | series 1| `autogen`|`census`|`location = 1,scientist = langstroth` 118 | series 2| `autogen`|`census`|`location = 2,scientist = langstroth` 119 | series 3| `autogen`|`census`|`location = 1,scientist = perpetua` 120 | series 4| `autogen`|`census`|`location = 2,scientist = perpetua` 121 | 122 | 理解series对于设计数据schema以及对于处理InfluxDB里面的数据都是很有必要的。 123 | 124 | 最后,point就是具有相同timestamp的相同series的field集合。例如,这就是一个point: 125 | 126 | ``` 127 | name: census 128 | ----------------- 129 | time butterflies honeybees location scientist 130 | 2015-08-18T00:00:00Z 1 30 1 perpetua 131 | ``` 132 | 133 | 例子里的series的retention policy为`autogen`,measurement为`census`,tag set为`location = 1, scientist = perpetua`。point的timestamp为`2015-08-18T00:00:00Z`。 134 | 135 | 我们刚刚涵盖的所有内容都存储在数据库(database)中——示例数据位于数据库`my_database`中。 InfluxDB数据库与传统的关系数据库类似,并作为users,retention policy,continuous以及point的逻辑上的容器。 有关这些主题的更多信息,请参阅[身份验证和授权]()和[连续查询(continuous query)]()。 136 | 137 | 数据库可以有多个users,retention policy,continuous和measurement。 InfluxDB是一个无模式数据库,意味着可以随时添加新的measurement,tag和field。 它旨在使时间序列数据的工作变得非常棒。 138 | 139 | 你做到了!你已经知道了InfluxDB中的基本概念和术语。如果你是初学者,我们建议您查看[入门指南](/Introduction/getting_start.md)和[写入数据](/Guide/writing_data.md)和[查询数据](/Guide/querying_data.md)指南。 愿我们的时间序列数据库可以为您服务🕔。 140 | 141 | -------------------------------------------------------------------------------- /Concepts/schema_and_data_layout.md: -------------------------------------------------------------------------------- 1 | # schema设计 2 | 3 | 每个InfluxDB用例都可能是不一样的,schema将反映出这种独特性。 但是,在设计schema时,有一些遵循的一般准和可以避免的陷阱。 4 | 5 | ## 一般建议 6 | 7 | ### 推崇的schema设计 8 | 9 | 没有特定的顺序,我们有如下建议: 10 | 11 | #### 哪些情况下使用tag 12 | 一般来说,你的查询可以指引你哪些数据放在tag中,哪些放在field中。 13 | 14 | * 把你经常查询的字段作为tag 15 | * 如果你要对其使用`GROUP BY()`,也要放在tag中 16 | * 如果你要对其使用InfluxQL函数,则将其放到field中 17 | * 如果你需要存储的值不是字符串,则需要放到field中,因为tag value只能是字符串 18 | 19 | #### 避免InfluxQL中关键字作为标识符名称 20 | 这不是必需的,但它简化了写查询; 您不必将这些标识符包装在双引号中。 标识符有database名称,retention policy名称,user名,measurement名称,tag key和field key。请参阅[InfluxQL关键词]()看下哪些单词需要被避免。 21 | 22 | 请注意,如果查询中包含除[A-z,_]以外的字符,则还需要将它们用双引号括起来。 23 | 24 | ### 避免的schema设计 25 | 26 | 没有特定的顺序,我们有如下建议: 27 | 28 | #### 不要有太多的series 29 | tags包含高度可变的信息,如UUID,哈希值和随机字符串,这将导致数据库中的大量measurement,通俗地说是高series cardinality。series cardinality高是许多数据库高内存使用的主要原因。 30 | 31 | 请参阅[硬件指南](/Guide/hardware_sizing.md)中基于你的硬件的series cardinality的建议。如果系统有内存限制,请考虑将高cardinality数据存储为field而不是tag。 32 | 33 | #### 如何设计measurement 34 | 一般来说,谈论这一步可以简化你的查询。InfluxDB的查询会合并属于同一measurement范围内的数据; 用tag区分数据比使用详细的measurement名字更好。 35 | 36 | 例如:考虑如下的schema: 37 | 38 | ``` 39 | Schema 1 - Data encoded in the measurement name 40 | ------------- 41 | blueberries.plot-1.north temp=50.1 1472515200000000000 42 | blueberries.plot-2.midwest temp=49.8 1472515200000000000 43 | ``` 44 | 45 | 这个没有tag的长长的measurement名字(`blueberries.plot-1.north`)有些类似于Graphite的metric。像`plot``region`这样的信息放在measurement名字里面将会使数据很难去查询。 46 | 47 | 例如,使用schema 1计算两个图1和2的平均`temp`是不可能的。将其与如下schema进行比较: 48 | 49 | ``` 50 | Schema 2 - Data encoded in tags 51 | ------------- 52 | weather_sensor,crop=blueberries,plot=1,region=north temp=50.1 1472515200000000000 53 | weather_sensor,crop=blueberries,plot=2,region=midwest temp=49.8 1472515200000000000 54 | ``` 55 | 56 | 以下查询计算了落在北部地区的蓝莓的平均`temp`。 虽然这两个查询都比较简单,但使用正则表达式使得某些查询更加复杂或根本不可能实现。 57 | 58 | ``` 59 | # Schema 1 - Query for data encoded in the measurement name 60 | > SELECT mean("temp") FROM /\.north$/ 61 | 62 | # Schema 2 - Query for data encoded in tags 63 | > SELECT mean("temp") FROM "weather_sensor" WHERE "region" = 'north' 64 | ``` 65 | 66 | #### 不要把多条信息放到一个tag里面 67 | 与上述相似,将具有多条信息的单个tag拆分为多个单独的tag将简化查询并减少对正则表达式的需求。 68 | 69 | 例如,考虑如下的schema: 70 | 71 | ``` 72 | Schema 1 - Multiple data encoded in a single tag 73 | ------------- 74 | weather_sensor,crop=blueberries,location=plot-1.north temp=50.1 1472515200000000000 75 | weather_sensor,crop=blueberries,location=plot-2.midwest temp=49.8 1472515200000000000 76 | ``` 77 | 78 | 上述数据将多个单独的参数`plot``region`放到了一个长tag value里面(`plot-1.north`)。 将其与如下schema进行比较: 79 | 80 | ``` 81 | Schema 2 - Data encoded in multiple tags 82 | ------------- 83 | weather_sensor,crop=blueberries,plot=1,region=north temp=50.1 1472515200000000000 84 | weather_sensor,crop=blueberries,plot=2,region=midwest temp=49.8 1472515200000000000 85 | ``` 86 | 87 | 以下查询计算了落在`north`地区的蓝莓的平均`temp`。 虽然这两个查询都是相似的,但在Schema 2中使用多个tag避免了使用正则表达式。 88 | 89 | ``` 90 | # Schema 1 - Query for multiple data encoded in a single tag 91 | > SELECT mean("temp") FROM "weather_sensor" WHERE location =~ /\.north$/ 92 | 93 | # Schema 2 - Query for data encoded in multiple tags 94 | > SELECT mean("temp") FROM "weather_sensor" WHERE region = 'north' 95 | ``` 96 | 97 | ## shard group的保留时间(duration)的管理 98 | ### shard group的保留时间(duration)预览 99 | InfluxDB将数据存储在shard group中。shard group由存储策略(RP)管理,并存储具有特定时间间隔内的时间戳的数据。 该时间间隔的长度称为shard group的duration。 100 | 101 | 默认情况下,shard group的duration是由RP的duration决定: 102 | 103 | RP duration|shard group duration 104 | ---------|------- 105 | < 2 days | a hour 106 | >= 2 days and <= 6 months | 1 day 107 | > 6 months | 7 days 108 | 109 | 在每个RP上shard group的duration也是可以配置的,可以看[Retention Policy管理]()看如何配置shard group的duration。 110 | 111 | ### shard group的duration的建议 112 | 通常,较短的shard group的duration允许系统有效地丢弃数据。 当InfluxDB强制执行RP时,它会丢弃整个shard group,而不是单个数据点。 例如,如果您的RP有一天的持续时间,一个shard group持续时间为一小时; 则InfluxDB每小时将丢弃一小时的数据。 113 | 114 | 如果您的RP的持续时间大于6个月,则不需要具有较短的shard group持续时间。 事实上,将shard group的持续时间提高到默认的七天值以上可以改善压缩,提高写入速度,并减少每个shard group的固定迭代器开销。 例如,50年及以上的shard group持续时间是可接受的配置。 115 | 116 | >说明:当配置shard group的duration的时候,`INF`(infinite)是一个不合理的配置。在实际工作中,特定的duration`1000w`就足够达到非常长的shard group持续时间。 117 | 118 | 我们建议shard group的配置如下: 119 | 120 | * 是你一般查询时间范围的两倍 121 | * 每个shard group里至少有100000个数据点 122 | * 每个shard group里面的每个series至少有1000个数据点 -------------------------------------------------------------------------------- /Concepts/storage_engine.md: -------------------------------------------------------------------------------- 1 | # 存储引擎 2 | 3 | ## InfluxDB的存储引擎和TSM 4 | 5 | 新的InfluxDB的存储引擎看起来和LSM树很像。它具有wal和一组只读数据文件,它们在概念上与LSM树中的SSTables类似。 TSM文件包含排序,压缩的series数据。 6 | 7 | InfluxDB将为每个时间段创建一个分片。例如,如果您有一个持续时间无限制的存储策略,则会为每7天的时间段创建一个分片。 这些每一个分片都映射到底层存储引擎数据库。 每一个这些数据库都有自己的WAL和TSM文件。 8 | 9 | 下面我们来深入存储引擎的这些部分。 10 | 11 | ### 存储引擎 12 | 存储引擎将多个组件结合在一起,并提供用于存储和查询series数据的外部接口。 它由许多组件组成,每个组件都起着特定的作用: 13 | 14 | * In-Memory Index —— 内存中的索引是分片上的共享索引,可以快速访问measurement,tag和series。 引擎使用该索引,但不是特指存储引擎本身。 15 | * WAL —— WAL是一种写优化的存储格式,允许写入持久化,但不容易查询。 对WAL的写入就是append到固定大小的段中。 16 | * Cache —— Cache是存储在WAL中的数据的内存中的表示。 它在运行时可以被查询,并与TSM文件中存储的数据进行合并。 17 | * TSM Files —— TSM Files中保存着柱状格式的压缩过的series数据。 18 | * FileStore —— FileStore可以访问磁盘上的所有TSM文件。 它可以确保在现有的TSM文件被替换时以及删除不再使用的TSM文件时,创建TSM文件是原子性的。 19 | * Compactor —— Compactor负责将不够优化的Cache和TSM数据转换为读取更为优化的格式。 它通过压缩series,去除已经删除的数据,优化索引并将较小的文件组合成较大的文件来实现。 20 | * Compaction Planner —— Compaction Planner决定哪个TSM文件已准备好进行压缩,并确保多个并发压缩不会彼此干扰。 21 | * Compression —— Compression由各种编码器和解码器对特定数据类型作处理。一些编码器是静态的,总是以相同的方式编码相同的类型; 还有一些可以根据数据的类型切换其压缩策略。 22 | * Writers/Readers —— 每个文件类型(WAL段,TSM文件,tombstones等)都有相应格式的Writers和Readers。 23 | 24 | #### Write Ahead Log(WAL) 25 | WAL被组织成一堆看起来像`_000001.wal`这样的文件。 文件编号单调增,并称为WAL段。 当分段达到10MB的大小时,该段将被关闭并且打开一个新的分段。每个WAL段存储多个压缩过的写入和删除块。 26 | 27 | 当一个新写入的点被序列化时,使用Snappy进行压缩,并写入WAL文件。 该文件是`fsync'd`,并且在返回成功之前将数据添加到内存中的索引。 这意味着批量的数据点写入可以实现更高的性能。(在大多数情况下,最佳批量大小似乎是每批5,000-10,000点。) 28 | 29 | WAL中的每个条目都遵循[TLV标准](https://en.wikipedia.org/wiki/Type-length-value),以一个单字节表示条目类型(写入或删除),然后压缩块长度的4字节`uint32`,最后是压缩块。 30 | 31 | #### Cache 32 | 缓存是对存储在WAL中的所有数据点的内存拷贝。这些点由这些key组成,他们是measurement,tag set和唯一field组成。每个field都按照自己的有序时间范围保存。缓存数据在内存中不被压缩。 33 | 34 | 对存储引擎的查询将会把Cache中的数据与TSM文件中的数据进行合并。在查询运行时间内,对数据副本的查询都是从缓存中获取的。这样在查询进行时写入的数据不会被查询出来。 35 | 36 | 发送到缓存的删除指令,将清除给定键或给定键的特定时间范围的数据。 37 | 38 | 缓存提供了一些控制器用于快照。两个最重要的控制器是内存限制。 有一个下限,`cache-snapshot-memory-size`,超出时会触发快照到TSM文件,并删除相应的WAL段。 还有一个上限,`cache-max-memory-size`,当超出时会导致Cache拒绝新的写入。 这些配置有助于防止内存不足的情况,并让客户端写数据比实例可承受的更快。 39 | 40 | 内存阈值的检查发生在每次写入时。 41 | 42 | 还有快照控制器是基于时间的。`cache-snapshot-write-cold-duration`,如果在指定的时间间隔内没有收到写入,则强制缓存到TSM文件的快照。 43 | 44 | 通过重新读取磁盘上的WAL文件,可以重新创建内存中缓存。 45 | 46 | #### TSM Files 47 | TSM files是内存映射的只读文件的集合。 这些文件的结构看起来与LevelDB中的SSTable或其他LSM Tree变体非常相似。 48 | 49 | 一个TSMfile由四部分组成:header,blocks,index和footer: 50 | 51 | ![](images/TSM_sections.png) 52 | 53 | Header是识别文件类型和版本号的一个魔法数字: 54 | 55 | ![](images/TSM_header.png) 56 | 57 | blocks是一组CRC32校验和数据对的序列。 58 | block数据对文件是不透明的。 59 | CRC32用于块级错误检测。 60 | block的长度存储在索引中。 61 | 62 | ![](images/TSM_blocks.png) 63 | 64 | blocks之后是文件中blocks的索引。索引由先按key顺序,如果key相同则按时间顺序排列的索引条目序列组成。key包括measurement名称,tag set和一个field。如果一个点有多个field则在TSM文件中创建多个索引条目。每个索引条目以密钥长度和密钥开始,后跟block类型(float,int,bool,string)以及该密钥后面的索引block条目数的计数。 然后是每个索引block条目,其由block的最小和最大时间组成,之后是block所在的文件的偏移量以及block的大小。 包含该key的TSM文件中每个block都有一个索引block条目。 65 | 66 | 索引结构可以提供对所有block的有效访问,以及能够确定访问给定key相关联数据需要多大代价。给定一个key和时间戳,我们可以确定文件是否包含该时间戳的block。我们还可以确定该block所在的位置,以及取出该block必须读取多少数据。了解了block的大小,我们可以有效地提供IO语句。 67 | 68 | ![](images/TSM_index.png) 69 | 70 | 最后一部分是footer,它存储了索引开头的offset。 71 | 72 | ![](images/TSM_footer.png) 73 | 74 | #### Compression 75 | 每个block都被压缩,以便减少存储空间和查询时磁盘IO。block包含时间戳和给定seris和field的值。每个block都有一个字节的header,之后跟着压缩过的时间戳,然后是压缩后的值。 76 | 77 | ![](images/TSM_compression.png) 78 | 79 | 时间戳和值都会被压缩,并使用依赖于数据类型及其形状的编码分开存储。独立存储允许时间戳编码用于所有时间戳,同时允许不同字段类型的不同编码。例如,一些点可能能够使用游程长度编码,而其他点可能不能。 80 | 81 | 每个值类型还包含一个1byte的header,表示剩余字节的压缩类型。 四个高位存储压缩类型,如果需要,四个低位由编码器使用。 82 | 83 | ##### Timestamps 84 | 时间戳编码是自适应的,并且基于被编码的时间戳的结构。它使用delta编码,缩放和使用simple8b游程编码压缩的组合,当然如果需要,可以回退到无压缩。 85 | 86 | 时间戳分辨率是可变的,可以像纳秒一样粒度,最多需要8个字节来存储未压缩的时间戳。在编码期间,这些值首先进行delta编码。第一个值是起始时间戳,后续值是与先前值的差值。这通常将值转换成更小的整数,更容易压缩。许多时间戳也是单调增加,并且在每10秒的时间的均匀边界上落下。当时间戳具有这种结构时,它们由也是10的因子的最大公约数来缩放。这具有将非常大的整数增量转换成更小的压缩更好的效果。 87 | 88 | 使用这些调整值,如果所有delta都相同,则使用游程编码来存储时间范围。如果游程长度编码是不可能的,并且纳秒分辨率的所有值都小于(1 << 60)-1([〜36.5年](https://www.wolframalpha.com/input/?i=\(1+%3C%3C+60)+ - + 1 +纳秒+至+年)),则使用[simple8b编码](https://github.com/jwilder/encoding/tree/master/simple8b)对时间戳进行编码。 Simple8b编码是一个64位字对齐的整数编码,将多个整数打包成一个64位字。如果任何值超过最大值,则使用每个块的8个字节对未压缩的三进制进行存储。未来的编码可能使用修补方案,如“Patched Frame-Of-Reference (PFOR)”来更有效地处理异常值。 89 | 90 | ##### Floats 91 | 使用[Facebook Gorilla paper](http://www.vldb.org/pvldb/vol8/p1816-teller.pdf)实现对浮点数的编码。当值靠近在一起时,编码将连续值XORs连在一起让结果集变得更小。然后使用控制位存储增量,以指示XOR值中有多少前导零和尾随零。我们的实现会删除paper中描述的时间戳编码,并且仅对浮点值进行编码。 92 | 93 | ##### Integers 94 | 整数编码使用两种不同的策略,具体取决于未压缩数据中的值的范围。编码值首先使用[ZigZag编码](https://developers.google.com/protocol-buffers/docs/encoding?hl=en#signed-integers)进行编码。这样在正整数范围内交错正整数和负整数。 95 | 96 | 例如,[-2,-1,0,1]变成[3,1,0,2]。 有关详细信息,请参阅Google的[Protocol Buffers文档](https://developers.google.com/protocol-buffers/docs/encoding?hl=en#signed-integers)。 97 | 98 | 如果所有ZigZag编码值都小于(1 << 60)-1,则使用simple8b编码进行压缩。如果有值大于最大值,则所有值都将在未压缩的块中存储。如果所有值相同,则使用游程长度编码。这对于频繁不变的值非常有效。 99 | 100 | ##### Booleans 101 | 布尔值使用简单的位打包策略进行编码,其中每个布尔值使用1位。使用可变字节编码在块的开始处存储编码的布尔值的数量。 102 | 103 | ##### Strings 104 | 字符串使用[Snappy](http://google.github.io/snappy/)压缩进行编码。每个字符串连续打包,然后被压缩为一个较大的块。 105 | 106 | #### Compactions 107 | Compactions是将以写优化格式存储的数据迁移到更加读取优化的格式的循环过程。在分片写入时,会发生Compactions的许多阶段: 108 | 109 | * Snapshots —— Cache和WAL中的数据必须转换为TSM文件以释放WAL段使用的内存和磁盘空间。这些Compactions基于高速缓存和时间阈值进行。 110 | * Level Compactions —— Level Compactions(分为1-4级)随TSM文件增长而发生。TSM文件从snapshot压缩到1级文件。多个1级文件被压缩以产生2级文件。该过程继续,直到文件达到级别4和TSM文件的最大大小。除非需要运行删除,index optimization compactions或者full compactions,否则它们会进一步压缩。较低级别的压缩使用避免CPU密集型活动(如解压缩和组合块)的策略。 较高的水平(因此较不频繁)的压缩将重新组合块来完全彻底压缩它们并增加压缩比。 111 | * Index Optimization —— 当许多4级TSM文件累积时,内部索引变大,访问成本更高。Index Optimization compaction通过一组新的TSM文件分割series和index,将给定series的所有点排序到一个TSM文件中。 在Index Optimization之前,每个TSM文件包含大多数或全部series的点,因此每个TSM文件包含相同的series索引。Index Optimization后,每个TSM文件都包含从最小的series中得到的点,文件之间几乎没有series重叠。因此,每个TSM文件具有较小的唯一series索引,而不是完整series列表的副本。此外,特定series的所有点在TSM文件中是连续的,而不是分布在多个TSM文件中。 112 | * Full Compaction —— 当分片数据已经写入很长时间(也就是冷数据),或者在分片上发生删除时,Full Compaction就会运行。Full Compaction产生最佳的TSM文件集,并包括来自Level和Index Optimization的所有优化。一旦一个shard上运行了Full Compaction,除非存储有新的写入或删除,否则不会在其上运行其他压缩。 113 | 114 | #### Writes(写) 115 | 写入是同时写到WAL的segment和Cache中。每个WAL segment都有最大尺寸。一旦当前文件填满,将写入一个新文件。Cache也有大小限制,当Cache满了之后,会产生snapshot并且启动WAL的compaction。如果在一定时间内,写入速率超过了WAL的compaction速率,则Cache可能变得过满,在这种情况下,新的写入将失败直到snapshot进程追赶上。 116 | 117 | 当WAL segment填满并关闭时,Compactor会将Cache并将数据写入新的TSM文件。当TSM文件成功写入和`fsync`'d时,它将会被FileStore加载和引用。 118 | 119 | #### Updates(更新) 120 | 正常写入会发生更新(为已存在的点写入较新的值),由于缓存值覆盖现有值,因此较新的写入优先。如果写入将覆盖先前TSM文件中的一个点,则这些点在查询运行时会合并,较新的写入优先。 121 | 122 | #### Deletes(删除) 123 | 通过向measurement或series的WAL写入删除条目然后更新Cache和FileStore来进行删除。这时Cache会去掉所有相关条目,FileStore为包含相关数据的每个TSM文件写入一个tombstone文件。这些tombstone文件被用于在启动时忽略相应的block,以及在compaction期间移除已删除的条目。 124 | 125 | 在compaction完全从TSM文件中删除数据之前,部分删除的series在查询时处理。 126 | 127 | #### Queries(查询) 128 | 当存储引擎执行查询时,它本质上是寻找给定时间相关的特定series key和field。首先,我们对数据文件进行搜索,以查找包含与查询匹配的时间范围以及包含匹配series的文件。 129 | 130 | 一旦我们选择了数据文件,我们接下来需要找到series key索引条目的文件中的位置。我们针对每个TSM索引运行二进制搜索,以查找其索引块的位置。 131 | 132 | 在通常的情况下,这些块不会跨多个TSM文件重叠,我们可以线性搜索索引条目以找到要读取的起始块。如果存在重叠的时间块,则索引条目将被排序,以确保较新的写入将优先,并且可以在查询执行期间按顺序处理该块。 133 | 134 | 当迭代索引条目时,块将从其位置顺序地被读取。该块被解压缩,以便我们寻求具体的数据点。 135 | 136 | ## 新的InfluxDB存储引擎:从LSM树到B+树,然后重新创建TSM 137 | 写一个新的存储引擎应该是最后的手段。那么InfluxData最终如何写我们自己的引擎的呢?InfluxData已经尝试了许多存储格式,发现每个在某一方面都有一些缺点。InfluxDB的性能要求非常高,当然最终压倒了其他存储系统。InfluxDB的0.8版本允许多个存储引擎,包括LevelDB,RocksDB,HyperLevelDB和LMDB。 InfluxDB的0.9版本使用BoltDB作为底层存储引擎。下面要介绍的TSM,它在0.9.5中发布,是InfluxDB 0.11+中唯一支持的存储引擎,包括整个1.x系列。 138 | 139 | 时间序列数据用例的特性使许多现有存储引擎很有挑战性。在InfluxDB开发过程中,我们尝试了一些更受欢迎的选项。我们从LevelDB开始,这是一种基于LSM树的引擎,针对写入吞吐量进行了优化。之后,我们尝试了BoltDB,这是一个基于内存映射B+ Tree的引擎,它是针对读取进行了优化的。最后,我们最终建立了我们自己的存储引擎,它在许多方面与LSM树类似。 140 | 141 | 借助我们的新存储引擎,我们可以达到比B+ Tree实现高达45倍的磁盘空间使用量的减少,甚至比使用LevelDB及其变体有更高的写入吞吐量和压缩率。这篇文章将介绍整个演变的细节,并深入了解我们的新存储引擎及其内部工作。 142 | 143 | ### 时序数据的特性 144 | 时间序列数据与正常的数据库工作负载有很大的不同。有许多因素使得它难以提高和保持性能: 145 | 146 | * 数十亿个数据点 147 | * 高吞吐量的写入 148 | * 高吞吐量的读取 149 | * 大量删除(数据到期) 150 | * 大部分数据是插入/追加,很少更新 151 | 152 | 第一个也是最明显的问题是规模。在DevOps,IoT或APM中,每天很容易收集数亿或数十亿的数据点。 153 | 154 | 例如,假设我们有200个VM或服务器运行,每个服务器平均有100个measurement每10秒收集一次。鉴于一天中有86,400秒,单个measurement每个服务器将在一天内产生8,640点。这样我们每天总共200 * 100 * 8,640 = 172,800,000个数据点。我们在传感器数据用例中还可以找到类似或更大的数字。 155 | 156 | 数据量大意味着写入吞吐量可能非常高。一些较大的公司一般需要每秒处理数百万次写入的系统。 157 | 158 | 同时,时间序列数据也可能是需要高吞吐量读取的。的确,如果您正在跟踪70万个metric或时间序列,那么你肯定不希望将其全部可视化。这导致许多人认为您实际上并没有读取大量数据的需求。然而,除了人们在屏幕上的仪表板之外,还有自动化系统用于监视或组合大量时间序列数据与其他类型的数据。 159 | 160 | 在InfluxDB内部,实时计算的聚合函数可将数万个不同时间series组合成单个视图。这些查询中的每一个都必须读取每个聚合数据点,因此对于InfluxDB,读取吞吐量通常比写入吞吐量高许多倍。 161 | 162 | 鉴于时间序列大多是顺序插入,你可能会认为可以在B+树上获得出色的性能,因为顺序插入是高效的,您可以达到每秒100,000以上。但是,我们有这些数据的写入发生在不同的时间序列。因此,插入最终看起来更像是随机插入,而不仅仅是顺序插入。 163 | 164 | 使用时间序列数据发现的最大问题之一是,在超过一定时间后需要删除所有数据。这里的常见模式是用户拥有高精度的数据,保存在短时间内,如几天或几个月。然后用户将数据采样并将其汇总到保存较长时间的较低精度数据。 165 | 166 | 最容易的实现将是简单地删除每个记录一旦超过其过期时间。然而,这意味着一旦写入的第一个点到达其到期日期,系统正在处理与写入一样多的删除,大多数存储引擎都不会这样去设计的。 167 | 168 | 我们来看看我们尝试过的两种存储引擎的细节,以及这些特性对我们性能的重大的影响。 169 | 170 | ### LevelDB和LSM树 171 | 当InfluxDB项目开始时,我们选择了LevelDB作为存储引擎,因为我们将其用于作为InfluxDB前身的产品中的时间序列数据存储。我们知道它具有很好的写入吞吐量,但一切似乎都“just work”。 172 | 173 | LevelDB是在Google构建为开源项目的Log Structured Merge Tree(或LSM树)的实现。 它暴露了键/值存储的API,其中key space是经过排序的。这最后一部分对于时间序列数据很重要,只要把时间戳放在key中,就允许我们快速扫描时间范围。 174 | 175 | LSM树基于采用写入和两个称为Mem Tables和SSTables的结构的日志。 这些tables代表了排序的keyspace。SSTables是只读文件,只能被其插入和更新的其他SSTables所替换。 176 | 177 | LevelDB为我们带来的两大优势是写入吞吐量高,内置压缩。 然而,当我们从时间序列数据中了解到人们需要什么时,我们遇到了一些不可逾越的挑战。 178 | 179 | 我们遇到的第一个问题是LevelDB不支持热备份。如果要对数据库进行安全备份,则必须将其关闭,然后将其复制。 LevelDB变体RocksDB和HyperLevelDB解决了这个问题,但还有另一个更紧迫的问题,我们认为他们解决不了。 180 | 181 | 我们的用户需要一种自动管理数据保留的方法。这意味着我们需要大量的删除。在LSM树中,删除与写入一样甚至更加昂贵。删除需要写入一个称为tombstone的新纪录。之后,查询会将结果集与任何tombstone合并,以从查询返回中清除已删除的数据。之后,将执行一个compaction操作,删除SSTable文件中的tombstone和底层删除的记录。 182 | 183 | 为了避免删除操作,我们将数据分割成我们称之为shard的数据,这些数据是连续的时间块。shard通常会持有一天或七天的数据。每个shard映射到底层的LevelDB。这意味着我们可以通过关闭数据库并删除底层文件来删除一整天的数据。 184 | 185 | RocksDB的用户现在可以提出一个名为ColumnFamilies的功能。当将时间序列数据放入Rocks时,通常将时间块分成列族,然后在时间到达时删除它们。这是一个一般的想法:创建一个单独的区域,您可以在删除大量数据时只删除文件而不是更新索引。 删除列族是一个非常有效的操作。然而,列族是一个相当新的功能,我们还有另一个shard的用例。 186 | 187 | 将数据组织成shard意味着它可以在集群内移动,而不必检查数十亿个key。在撰写本文时,不可能将RocksDB中的列族移动到另一个。旧的碎片通常是冷写的,所以移动它们将会很便宜而且代价很小。我们将获得额外的好处是在keyspace中存在一个写冷的地方,所以之后进行的一致性检查会更容易。 188 | 189 | 将数据组织到shard中运行了一段时间,直到大量的数据进入InfluxDB。 LevelDB将数据分解成许多小文件。在单个进程中打开数十个数百个这些数据库,最终造成了一个大问题。有六个月或一年数据的用户将用尽文件句柄。这不是我们与大多数用户发现的,任何将数据库推到极限的人都会遇到这个问题,我们没有解决。打开的文件柄实在太多了。 190 | 191 | ### BoltDB和mmap B+树 192 | 在与LevelDB及其变体一起挣扎了一年之后,我们决定转移到BoltDB,BoltDB是一个纯粹的Golang数据库,它受到LMDB的高度启发,这是一个用C编写的mmap B+ Tree数据库。它具有与LevelDB相同的API语义:keyspace有序地存储。我们的许多用户感到惊讶,我们自己发布的LevelDB变体与LMDB(mmap B+ Tree)的测试显示,RocksDB是表现最好的。 193 | 194 | 然而,在纯粹的写的表现之外,还有其他因素需要考虑进来。 在这一点上,我们最重要的目标是获得可以在生产和备份中运行的稳定的东西。BoltDB还具有以纯Go编写的优势,它极大地简化了我们的构建链,并使其易于构建在其他操作系统和平台上。 195 | 196 | 对我们来说,最大的好处是BoltDB使用单个文件作为数据库。在这一点上,我们之前最常见的bug报告来源是用户用尽了文件句柄。Bolt还同时解决了热备份问题和文件限制问题。 197 | 198 | 如果这意味着我们可以建立一个更可靠和稳定的系统,我们愿意对写入吞吐量上作出妥协。 我们的理由是,对于任何人想要真正大的写入负载,他们将会运行一个集群。我们根据BoltDB发布了0.9.0到0.9.2版本。从发展的角度来看,这是令人愉快的。 简洁的API,快速轻松地构建在我们的Go项目中,并且可靠。 然而,运行一段时间后,我们发现了写入吞吐量的一大问题。在数据库超过几GB之后,IOPS开始成为瓶颈。 199 | 200 | 有些用户可以通过将InfluxDB放在具有接近无限制IOPS的大硬件上,从而达到这个目标。但是,大多数用户都是云端资源有限的虚拟机。 我们必须找出一种方法来减少同时将一堆数据写入到成百上千个series的影响。 201 | 202 | 随着0.9.3和0.9.4版本的发布,我们的计划是在Bolt面前写一个WAL,这样我们可以减少随机插入到keyspace的数量。相反,我们会缓冲彼此相邻的多个写入,然后一次flush它们 但是,这仅仅是为了延缓了这个问题。高IOPS仍然成为一个问题,对于任何在适度工作负荷的场景下,它都会很快出现。 203 | 204 | 然而,我们在Bolt面前建立一个WAL实施的经验使我们有信心可以解决写入问题。WAL本身的表现太棒了,索引根本无法跟上。在这一点上,我们再次开始思考如何创建类似于LSM Tree的东西,使之可以跟上我们的写入负载。 205 | 206 | 这就是TSM Tree的诞生过程。 -------------------------------------------------------------------------------- /Guide/downsampling_and_retention.md: -------------------------------------------------------------------------------- 1 | # 采样和数据保留 2 | 3 | InfluxDB每秒可以处理数十万的数据点。如果要长时间地存储大量的数据,对于存储会是很大的压力。一个很自然的方式就是对数据进行采样,对于高精度的裸数据存储较短的时间,而对于低精度的的数据可以保存得久一些甚至永久保存。 4 | 5 | InfluxDB提供了两个特性——连续查询(Continuous Queries简称CQ)和保留策略(Retention Policies简称RP),分别用来处理数据采样和管理老数据的。这一章将会展示CQs和RPs的例子,看下在InfluxDB中怎么使用这两个特性。 6 | 7 | ## 定义 8 | **Continuous Query (CQ)**是在数据库内部自动周期性跑着的一个InfluxQL的查询,CQs需要在`SELECT`语句中使用一个函数,并且一定包括一个`GROUP BY time()`语句。 9 | 10 | **Retention Policy (RP)**是InfluxDB数据架构的一部分,它描述了InfluxDB保存数据的时间。InfluxDB会比较服务器本地的时间戳和请求数据里的时间戳,并删除比你在RPs里面用`DURATION`设置的更老的数据。一个数据库中可以有多个RPs但是每个数据库的RPs是唯一的。 11 | 12 | 这一章不会详细地介绍创建和管理CQs和RPs的语法,如果你对这两个概念还是很陌生的话,建议查看[CQ文档]()和[RP文档]()。 13 | 14 | ## 数据采样 15 | 本节使用虚构的实时数据,以10秒的间隔,来追踪餐厅通过电话和网站订购食品的订单数量。我们会把这些数据存在`food_data`数据库里,其measurement为`orders`,fields分别为`phone`和`website`。 16 | 17 | 就像这样: 18 | 19 | ``` 20 | name: orders 21 | ------------ 22 | time phone website 23 | 2016-05-10T23:18:00Z 10 30 24 | 2016-05-10T23:18:10Z 12 39 25 | 2016-05-10T23:18:20Z 11 56 26 | ``` 27 | 28 | ## 目标 29 | 假定在长时间的运行中,我们只关心每三十分钟通过手机和网站订购的平均数量,我们希望用RPs和CQs实现下面的需求: 30 | 31 | * 自动将十秒间隔数据聚合到30分钟的间隔数据 32 | * 自动删除两个小时以上的原始10秒间隔数据 33 | * 自动删除超过52周的30分钟间隔数据 34 | 35 | ## 数据库准备 36 | 在写入数据到数据库`food_data`之前,我们先做如下的准备工作,在写入之前设置CQs是因为CQ只对最近的数据有效; 即数据的时间戳不会比`now()`减去CQ的`FOR`子句的时间早,或是如果没有`FOR`子句的话比`now()`减去`GROUP BY time()`间隔早。 37 | 38 | ### 1. 创建数据库 39 | 40 | ``` 41 | > CREATE DATABASE "food_data" 42 | ``` 43 | 44 | ### 2. 创建一个两个小时的默认RP 45 | 如果我们写数据的时候没有指定RP的话,InfluxDB会使用默认的RP,我们设置默认的RP是两个小时。使用`CREATE RETENTION POLICY`语句来创建一个默认RP: 46 | 47 | ``` 48 | > CREATE RETENTION POLICY "two_hours" ON "food_data" DURATION 2h REPLICATION 1 DEFAULT 49 | ``` 50 | 51 | 这个RP的名字叫`two_hours`作用于`food_data`数据库上,`two_hours`保存数据的周期是两个小时,并作为`food_data`的默认RP。 52 | 53 | *复制片参数(REPLICATION 1)是必须的,但是对于单个节点的InfluxDB实例,复制片只能设为1* 54 | 55 | >说明:在步骤1里面创建数据库时,InfluxDB会自动生成一个叫做`autogen`的RP,并作为数据库的默认RP,`autogen`这个RP会永远保留数据。在输入上面的命令之后,`two_hours`会取代`autogen`作为`food_data`的默认RP。 56 | 57 | ### 3. 创建一个保留52周数据的RP 58 | 接下来我们创建另一个RP保留数据52周,但不是数据库的默认RP。最终30分钟间隔的数据会保存在这个RP里面。 59 | 60 | 使用`CREATE RETENTION POLICY`语句来创建一个非默认的RP: 61 | 62 | ``` 63 | > CREATE RETENTION POLICY "a_year" ON "food_data" DURATION 52w REPLICATION 1 64 | ``` 65 | 66 | 这个语句对数据库`food_data`创建了一个叫做`a_year`的RP,`a_year`保存数据的周期是52周。去掉`DEFAULT`参数可以保证`a_year`不是数据库`food_data`的默认RP。这样在读写的时候如果没有指定,仍然是使用`two_hours`这个默认RP。 67 | 68 | ### 4. 创建CQ 69 | 现在我们已经创建了RPs,现在我们要创建一个CQ,去将10秒间隔的数据采样到30分钟的间隔,并把它们安装不同存储策略把它们存在不同的measurement里。 70 | 71 | 使用`CREATE CONTINUOUS QUERY`来生成一个CQ: 72 | 73 | ``` 74 | > CREATE CONTINUOUS QUERY "cq_30m" ON "food_data" BEGIN 75 | SELECT mean("website") AS "mean_website",mean("phone") AS "mean_phone" 76 | INTO "a_year"."downsampled_orders" 77 | FROM "orders" 78 | GROUP BY time(30m) 79 | END 80 | ``` 81 | 82 | 上面创建了一个叫做`cq_30m`的CQ作用于`food_data`数据库上。`cq_30m`告诉InfluxDB每30分钟计算一次measurement为`orders`并使用默认RP`tow_hours`的字段`website`和`phone`的平均值,然后把结果写入到RP为`a_year`,两个字段分别是`mean_website`和`mean_phone`的measurement名为`downsampled_orders`的数据中。InfluxDB会每隔30分钟跑对之前30分钟的数据跑一次这个查询。 83 | 84 | >说明:注意到我们在`INTO`语句中使用了`"".""`这样的语句,当要写入到非默认的RP时,就需要这样的写法。 85 | 86 | ## 结果 87 | 使用新的CQ和两个新的RPs,`food_data`已经开始接收数据了。之后我们向数据库里写数据,并且持续一段时间之后,我们可以看到两个measurement分别是`orders`和`downsampled_orders`。 88 | 89 | ``` 90 | > SELECT * FROM "orders" LIMIT 5 91 | name: orders 92 | --------- 93 | time phone website 94 | 2016-05-13T23:00:00Z 10 30 95 | 2016-05-13T23:00:10Z 12 39 96 | 2016-05-13T23:00:20Z 11 56 97 | 2016-05-13T23:00:30Z 8 34 98 | 2016-05-13T23:00:40Z 17 32 99 | 100 | > SELECT * FROM "a_year"."downsampled_orders" LIMIT 5 101 | name: downsampled_orders 102 | --------------------- 103 | time mean_phone mean_website 104 | 2016-05-13T15:00:00Z 12 23 105 | 2016-05-13T15:30:00Z 13 32 106 | 2016-05-13T16:00:00Z 19 21 107 | 2016-05-13T16:30:00Z 3 26 108 | 2016-05-13T17:00:00Z 4 23 109 | ``` 110 | 111 | 在`orders`里面是10秒钟间隔的裸数据,保存时间为2小时。在`downsampled_orders`里面是30分钟的聚合数据,保存时间为52周。 112 | 113 | 注意到`downsampled_orders`返回的第一个时间戳比`orders`返回的第一个时间戳要早,这是因为InfluxDB已经删除了`orders`中时间比本地早两个小时的数据。InfluxDB会在52周之后开始删除`downsampled_orders`中的数据。 114 | 115 | >说明:注意这里我们在第二个语句中使用了` "".""`来查询`downsampled_orders`,因为只要不是使用默认的RP我们就需要指定RP。 116 | > 117 | 默认InfluxDB是每隔三十分钟check一次RP,在两次check之间,`orders`中可能有超过两个小时的数据,这个check的间隔可以在InfluxDB的配置文件中更改。 118 | 119 | 使用RPs和CQs的组合,我们已经成功地创建的数据库并保存高精度的裸数据较短的时间,而保存高精度的数据更长时间。现在我们对这些特性的工作有了大概的了解,我们推荐到[CQs]()和[RPs]()去看更详细的文档。 120 | -------------------------------------------------------------------------------- /Guide/hardware_sizing.md: -------------------------------------------------------------------------------- 1 | # 硬件指南 2 | 3 | 这一章会提供一些InfluxDB的硬件推荐,并会回答一些问的最多的关于硬件的问题。下面的推荐都是基于InfluxDB 1.2中的`TSM`存储引擎。 4 | 5 | 将要探讨的问题: 6 | 7 | * 是用单节点还是集群? 8 | * 对于单节点的一般硬件指南 9 | * 对于集群的硬件指南 10 | * 什么时候需要更多的内存? 11 | * 需要那种类型的磁盘? 12 | * 需要多大的存储空间? 13 | * 该怎么配置硬件? 14 | 15 | 好现在我们来一一看看这些问题: 16 | 17 | ## 是用单节点还是集群? 18 | InfluxDB的单节点是完全开源的,InfluxDB的集群版本是闭源的商业版。单节点的实例没有冗余,如果服务不可用,写入和读取数据都会马上失败。集群提供了高可用和冗余,多个数据副本分布在多台服务器上,任何一台服务器的丢失都不会对集群造成重大的影响。 19 | 20 | 如果您的性能要求仅仅是中等或低负载范围,那么使用单节点的InfluxDB实例就够了。如果你对性能要求相当高,那么你需要集群将负载分担到多台机器上。 21 | 22 | ## 对于单节点的一般硬件指南 23 | 我们这里定义的InfluxDB的负载是基于每秒的写入的数据量、每秒查询的次数以及唯一series的数目。基于你的负载,我们给出CPU、内存以及IOPS的推荐。 24 | 25 | InfluxDB应该跑在SSD上,任何其他存储配置将具有较低的性能特征,并且在正常处理中可能甚至无法从小的中断中恢复。 26 | 27 | 负载|每秒写入的字段数|每秒中等查询数|series数量 28 | ---- | ---|---- | --- 29 | 低|< 5千|<5|<10万 30 | 中等|<25万|<25|<1百万 31 | 高|>25万|>25|>1百万 32 | 相当高|>75万|>100|>1千万 33 | 34 | >说明:查询对于系统性能的影响很大 35 | >简单查询: 36 | > 37 | * 几乎没有函数和正则表达式 38 | * 时间限制在几分钟,或是几个小时,又或者到一天 39 | * 通常在几毫秒到几十毫秒内执行 40 | 41 | >中等查询: 42 | > 43 | * 有多个函数或者一两个正则表达式 44 | * 有复杂点的`GROUP BY`语句或是时间有几个星期的数据 45 | * 通常在几百毫秒到几千毫秒内执行 46 | 47 | >复杂查询: 48 | > 49 | * 有多个聚合函数、转换函数或者多个正则表达式 50 | * 时间跨度很大有几个月或是几年 51 | * 通常执行时间需要几秒 52 | 53 | ### 低负载推荐 54 | * CPU:2~4核 55 | * 内存:2~4GB 56 | * IOPS:500 57 | 58 | ### 中等负载推荐 59 | * CPU:4~6核 60 | * 内存:8~32GB 61 | * IOPS:500~1000 62 | 63 | ### 高负载推荐 64 | * CPU:8+核 65 | * 内存:32+GB 66 | * IOPS:1000+ 67 | 68 | ### 超高负载 69 | 要达到这个范围挑战很大,甚至可能不能完成;联系我们的`t sales@influxdb.com`寻求专业帮助吧。 70 | 71 | ## 对于集群的硬件指南 72 | ### 元节点 73 | 一个集群至少要有三个独立的元节点才能允许一个节点的丢失,如果要容忍`n`个节点的丢失则需要`2n+1`个元节点。集群的元节点的数目应该为奇数。不要是偶数元节点,因为这样在特定的配置下会导致故障。 74 | 75 | 元节点不需要多大的计算压力,忽略掉集群的负载,我们建议元节点的配置: 76 | 77 | * CPU:1~2核 78 | * 内存:512MB~1GB 79 | * IOPS:50 80 | 81 | ### 数据节点 82 | 一个集群运行只有一个数据节点,但这样数据就没有冗余了。这里的冗余通过写数据的RP中的`副本个数`来设置。一个集群在丢失`n-1`个数据节点后仍然能返回完整的数据,其中`n`是副本个数。为了在集群内实现最佳数据分配,我们建议数据节点的个数为偶数。 83 | 84 | 对于集群的数据节点硬件的推荐和单节点的类似,数据节点应该至少有两个核的CPU,因为必须处理正常的读取和写入压力,以及集群内的数据的读写。由于集群通信开销,集群中的数据节点处理的吞吐量比同一硬件配置上的单实例的要少。 85 | 86 | 负载|每秒写入的字段数|每秒中等查询数|series数量 87 | ---- | ---|---- | --- 88 | 低|< 5千|<5|<10万 89 | 中等|<10万|<25|<1百万 90 | 高|>10万|>25|>1百万 91 | 相当高|>50万|>100|>1千万 92 | 93 | >说明:查询对于系统性能的影响很大 94 | >简单查询: 95 | > 96 | * 几乎没有函数和正则表达式 97 | * 时间限制在几分钟,或是几个小时,又或者到一天 98 | * 通常在几毫秒到几十毫秒内执行 99 | 100 | >中等查询: 101 | > 102 | * 有多个函数或者一两个正则表达式 103 | * 有复杂点的`GROUP BY`语句或是时间有几个星期的数据 104 | * 通常在几百毫秒到几千毫秒内执行 105 | 106 | >复杂查询: 107 | > 108 | * 有多个聚合函数、转换函数或者多个正则表达式 109 | * 时间跨度很大有几个月或是几年 110 | * 通常执行时间需要几秒 111 | 112 | ### 低负载推荐 113 | * CPU:2~4核 114 | * 内存:2~4GB 115 | * IOPS:1000 116 | 117 | ### 中等负载推荐 118 | * CPU:4~6核 119 | * 内存:8~32GB 120 | * IOPS:1000+ 121 | 122 | ### 高负载推荐 123 | * CPU:8+核 124 | * 内存:32+GB 125 | * IOPS:1000+ 126 | 127 | ### 企业Web节点 128 | 企业Web服务器主要充当具有类似负载要求的HTTP服务器。 对于大多数应用程序,它不需要性能很强。 一般集群将仅使用一个Web服务器,但是考虑到冗余,可以将多个Web服务器连接到单个后端Postgres数据库。 129 | 130 | >注意:生产集群不应该使用SQLite数据库,因为它不被冗余的Web服务器允许,也不能像Postgres一样处理高负载。 131 | 132 | 推荐配置: 133 | 134 | * CPU:1~4核 135 | * 内存:1~2GB 136 | * IOPS:50 137 | 138 | 139 | ## 什么时候需要更多的内存? 140 | 一般来讲,内存越多,查询的速度越快,增加更多的内存总没有坏处。 141 | 142 | 影响内存的最主要的因素是series基数,series的基数大约或是超过千万时,就算有更多的内存也可能导致OOM,所以在设计数据的格式的时候需要考虑到这一点。 143 | 144 | 内存的增长和series的基数存在一个指数级的关系: 145 | 146 | ![](images/series-cardinality.png) 147 | 148 | ## 需要哪种类型的磁盘? 149 | InfluxDB被设计运行在SSD上,InfluxData团队不会在HDD和网络存储上测试InfluxDB,所以不太建议在生产上这么去使用。在机械磁盘上性能会下降一个数量级甚至在中等负载下系统都可能死掉。为了最好的结果,InfluxDB至少需要磁盘提供1000 IOPS的性能。 150 | 151 | 注意集群的数据节点在做故障恢复的时候需要更高的IOPS,所以考虑到可能的数据恢复,我们建议磁盘至少有2000的IOPS,低于1000的IOPS,集群可能无法即时从短暂的中断中恢复。 152 | 153 | ## 需要多大的存储空间? 154 | 数据库的名字、measurement、tag keys、field keys和tag values只被存储一次且只能是字符串。只有field values和timestamp在每个数据点上都有存储。 155 | 156 | 非字符串类型的值大约需要3字节,字符串类型的值需要的空间由字符串的压缩来决定。 157 | 158 | ## 该怎么配置硬件? 159 | 当在生产上运行InfluxDB时,`wal`和`data`文件夹需要在存储设备上分开。当系统处于大量写入负载下时,此优化可显着减少磁盘争用。 如果写入负载高度变化,这是一个重要的考虑因素。 如果写入负载不超过15%,则可能不需要优化。 -------------------------------------------------------------------------------- /Guide/https_setup.md: -------------------------------------------------------------------------------- 1 | # HTTPS设置 2 | 3 | 这篇描述了怎样在InfluxDB中开启HTTPS。设置HTTPS可以保护客户端和InfluxDB服务器之间的通信,在某些情况下,HTTPS可以用来验证InfluxDB服务器对客户端的真实性。 4 | 5 | 如果你计划通过网络来发送请求到InfluxDB,我们强烈建议你开启HTTPS。 6 | 7 | ## 准备 8 | 为了给InfluxDB上设置HTTPS,你需要一个已有的或是新建的InfluxDB实例,还需要TLS证书也可以说SSL证书。InfluxDB支持三种类型的TLS/SSL证书: 9 | 10 | * **由证书颁发机构签名的单域证书** 11 | 这些证书为HTTPS请求提供加密安全性,并允许客户端验证InfluxDB服务器的身份。 如果使用此证书,每个InfluxDB实例都需要一个唯一的单域证书。 12 | 13 | * **证书颁发机构签发的通配证书** 14 | 这些证书为HTTPS请求提供加密安全性,并允许客户端验证InfluxDB服务器的身份。 可以在不同服务器上的多个InfluxDB实例中使用通配符证书。 15 | 16 | * **自签证书** 17 | 自签名证书不由CA签名,您可以在自己的机器上生成。 与CA签署的证书不同,自签名证书仅为HTTPS请求提供加密安全性。 他们不允许客户端验证InfluxDB服务器的身份。 如果您无法获得CA签发的证书,我们建议使用自签名证书。 如果使用此证书,每个InfluxDB实例都需要一个唯一的自签名证书。 18 | 19 | 无论您的证书类型如何,InfluxDB都支持由私钥文件(.key)和签名证书文件(.crt)文件对组成的证书,以及将私钥文件和签名的证书文件组合成一个捆绑的证书文件(.pem)。 20 | 21 | 以下两部分将介绍在Ubuntu 16.04上如何使用CA签发的证书和自签名证书给InfluxDB设置HTTPS。其他操作系统的具体步骤可能不同。 22 | 23 | ## 使用CA签发的证书设置HTTPS 24 | 25 | ### 第一步:安装SSL / TLS证书 26 | 将私钥文件(.key)和签名的证书文件(.crt)或单个捆绑文件(.pem)放在`/etc/ssl`目录中。 27 | 28 | ### 第二步:确保文件权限 29 | 证书文件需要root用户的读写权限。通过运行以下命令确保您具有正确的文件权限: 30 | 31 | ``` 32 | sudo chown root:root /etc/ssl/ 33 | sudo chmod 644 /etc/ssl/ 34 | sudo chmod 600 /etc/ssl/ 35 | ``` 36 | 37 | ### 第三步:在InfluxDB的配置文件中开启HTTPS 38 | 默认HTTPS是关闭的,在InfluxDB的配置文件`/etc/influxdb/influxdb.conf`的`[http]`部分通过如下设置开启HTTPS: 39 | 40 | * `https-enabled`设为`true` 41 | * `http-certificate`设为`/etc/ssl/.crt`(或者`/etc/ssl/.pem`) 42 | * `http-private-key`设为`/etc/ssl/.key`(或者`/etc/ssl/.pem`) 43 | 44 | ``` 45 | [http] 46 | 47 | [...] 48 | 49 | # Determines whether HTTPS is enabled. 50 | https-enabled = true 51 | 52 | [...] 53 | 54 | # The SSL certificate to use when HTTPS is enabled. 55 | https-certificate = ".pem" 56 | 57 | # Use a separate private key location. 58 | https-private-key = ".pem" 59 | ``` 60 | 61 | ### 第四步:重启InfluxDB 62 | 重启InfluxDB使配置生效: 63 | 64 | ``` 65 | sudo systemctl restart influxdb 66 | ``` 67 | 68 | ### 第五步:验证HTTPS安装 69 | 可以通过InfluxDB的CLI来验证HTTPS是否工作: 70 | 71 | ``` 72 | influx -ssl -host .com 73 | ``` 74 | 如果连接成功会返回: 75 | 76 | ``` 77 | Connected to https://.com:8086 version 1.x.x 78 | InfluxDB shell version: 1.x.x 79 | > 80 | ``` 81 | 82 | 这样你就成功开启了InfluxDB的HTTPS了。 83 | 84 | ## 使用自签名证书设置HTTPS 85 | ### 第一步:生成自签名证书 86 | 以下命令生成私有密钥文件(.key)和自签名证书文件(.crt),该文件对于指定`NUMBER_OF_DAYS`情况下仍然有效。 它将这些文件输出到InfluxDB的默认证书文件路径,并向他们提供所需的权限。 87 | 88 | ``` 89 | sudo openssl req -x509 -nodes -newkey rsa:2048 -keyout /etc/ssl/influxdb-selfsigned.key -out /etc/ssl/influxdb-selfsigned.crt -days 90 | ``` 91 | 92 | 当执行该命令时,将提示您提供更多信息。 您可以选择填写该信息或将其留空; 这两个操作都会生成有效的证书文件。 93 | 94 | ### 第二步:在InfluxDB的配置文件中开启HTTPS 95 | 96 | 默认HTTPS是关闭的,在InfluxDB的配置文件`/etc/influxdb/influxdb.conf`的`[http]`部分通过如下设置开启HTTPS: 97 | 98 | * `https-enabled`设为`true` 99 | * `http-certificate`设为`/etc/ssl/influxdb-selfsigned.crt` 100 | * `http-private-key`设为`/etc/ssl/influxdb-selfsigned.key` 101 | 102 | ``` 103 | [http] 104 | 105 | [...] 106 | 107 | # Determines whether HTTPS is enabled. 108 | https-enabled = true 109 | 110 | [...] 111 | 112 | # The SSL certificate to use when HTTPS is enabled. 113 | https-certificate = "/etc/ssl/influxdb-selfsigned.crt" 114 | 115 | # Use a separate private key location. 116 | https-private-key = "/etc/ssl/influxdb-selfsigned.key" 117 | ``` 118 | 119 | ### 第三步:重启InfluxDB 120 | 重启InfluxDB使配置生效: 121 | 122 | ``` 123 | sudo systemctl restart influxdb 124 | ``` 125 | 126 | ### 第四步:验证HTTPS安装 127 | 可以通过InfluxDB的CLI来验证HTTPS是否工作: 128 | 129 | ``` 130 | influx -ssl -unsafeSsl -host .com 131 | ``` 132 | 如果连接成功会返回: 133 | 134 | ``` 135 | Connected to https://.com:8086 version 1.x.x 136 | InfluxDB shell version: 1.x.x 137 | > 138 | ``` 139 | 140 | >#### 将Telegraf连接到一个安全的InfluxDB实例 141 | 将Telegraf连接到使用HTTPS的InfluxDB实例需要一些额外的步骤。 142 | > 143 | 在Telegraf的配置文件(`/etc/telegraf/telegraf.conf`)中,编辑`urls`设置以指定`https`而不是`http`,并将`localhost`更改为相关域名。 如果您使用自签名证书,请取消`insecure_skip_verify`的注释设置并将其设置为true。 144 | 145 | ``` 146 | ############################################################################### 147 | # OUTPUT PLUGINS # 148 | ############################################################################### 149 | 150 | # Configuration for influxdb server to send metrics to 151 | [[outputs.influxdb]] 152 | ## The full HTTP or UDP endpoint URL for your InfluxDB instance. 153 | ## Multiple urls can be specified as part of the same cluster, 154 | ## this means that only ONE of the urls will be written to each interval. 155 | # urls = ["udp://localhost:8089"] # UDP endpoint example 156 | urls = ["https://.com:8086"] 157 | 158 | [...] 159 | 160 | ## Optional SSL Config 161 | [...] 162 | insecure_skip_verify = true # <-- Update only if you're using a self-signed certificate 163 | ``` 164 | >然后重启Telegraf就可以啦! -------------------------------------------------------------------------------- /Guide/images/series-cardinality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasper-zhang/influxdb-document-cn/a6d7fb9ec341fb4a66c3e81877685c340c4f1094/Guide/images/series-cardinality.png -------------------------------------------------------------------------------- /Guide/index.md: -------------------------------------------------------------------------------- 1 | # 使用指南 2 | 3 | ### [写入数据](writing_data.md) 4 | 5 | ### [查询数据](querying_data.md) 6 | 7 | ### [采样和数据保留](downsampling_and_retention.md) 8 | 9 | ### [硬件指南](hardware_sizing.md) 10 | 11 | ### [HTTPS设置](https_setup.md) 12 | -------------------------------------------------------------------------------- /Guide/querying_data.md: -------------------------------------------------------------------------------- 1 | # 查询数据 2 | 3 | ## 使用HTTP接口查询数据 4 | HTTP接口是InfluxDB查询数据的主要方式。通过发送一个`GET`请求到`/query`路径,并设置URL的`db`参数为目标数据库,设置URL参数`q`为查询语句。下面的例子是查询在[写数据](writing_data.md)里写入的数据点。 5 | 6 | ``` 7 | curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'" 8 | ``` 9 | 10 | InfluxDB返回一个json值,你查询的结果在`result`列表中,如果有错误发送,InfluxDB会在`error`这个key里解释错误发生的原因。 11 | 12 | ``` 13 | { 14 | "results": [ 15 | { 16 | "statement_id": 0, 17 | "series": [ 18 | { 19 | "name": "cpu_load_short", 20 | "columns": [ 21 | "time", 22 | "value" 23 | ], 24 | "values": [ 25 | [ 26 | "2015-01-29T21:55:43.702900257Z", 27 | 2 28 | ], 29 | [ 30 | "2015-01-29T21:55:43.702900257Z", 31 | 0.55 32 | ], 33 | [ 34 | "2015-06-11T20:46:02Z", 35 | 0.64 36 | ] 37 | ] 38 | } 39 | ] 40 | } 41 | ] 42 | } 43 | ``` 44 | 45 | >说明:添加`pretty=ture`参数在URL里面,是为了让返回的json格式化。这在调试或者是直接用`curl`的时候很有用,但在生产上不建议使用,因为这样会消耗不必要的网络带宽。 46 | 47 | ### 多个查询 48 | 在一次API调用中发送多个InfluxDB的查询语句,可以简单地使用分号分隔每个查询,例如: 49 | 50 | ``` 51 | curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west';SELECT count(\"value\") FROM \"cpu_load_short\" WHERE \"region\"='us-west'" 52 | ``` 53 | 54 | 返回: 55 | 56 | ``` 57 | { 58 | "results": [ 59 | { 60 | "statement_id": 0, 61 | "series": [ 62 | { 63 | "name": "cpu_load_short", 64 | "columns": [ 65 | "time", 66 | "value" 67 | ], 68 | "values": [ 69 | [ 70 | "2015-01-29T21:55:43.702900257Z", 71 | 2 72 | ], 73 | [ 74 | "2015-01-29T21:55:43.702900257Z", 75 | 0.55 76 | ], 77 | [ 78 | "2015-06-11T20:46:02Z", 79 | 0.64 80 | ] 81 | ] 82 | } 83 | ] 84 | }, 85 | { 86 | "statement_id": 1, 87 | "series": [ 88 | { 89 | "name": "cpu_load_short", 90 | "columns": [ 91 | "time", 92 | "count" 93 | ], 94 | "values": [ 95 | [ 96 | "1970-01-01T00:00:00Z", 97 | 3 98 | ] 99 | ] 100 | } 101 | ] 102 | } 103 | ] 104 | } 105 | ``` 106 | 107 | ### 查询数据时的其他可选参数 108 | #### 时间戳格式 109 | 在InfluxDB中的所有数据都是存的UTC时间,时间戳默认返回RFC3339格式的纳米级的UTC时间,例如`2015-08-04T19:05:14.318570484Z`,如果你想要返回Unix格式的时间,可以在请求参数里设置`epoch`参数,其中epoch可以是`[h,m,s,ms,u,ns]`之一。例如返回一个秒级的epoch: 110 | 111 | ``` 112 | curl -G 'http://localhost:8086/query' --data-urlencode "db=mydb" --data-urlencode "epoch=s" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'" 113 | ``` 114 | 115 | #### 认证 116 | InfluxDB里面的认证默认是关闭的,查看[认证和鉴权]()章节了解如何开启认证。 117 | 118 | #### 最大行限制 119 | 可选参数`max-row-limit`允许使用者限制返回结果的数目,以保护InfluxDB不会在聚合结果的时候导致的内存耗尽。 120 | 121 | 在1.2.0和1.2.1版本中,InfluxDB默认会把返回的数目截断为10000条,如果有超过10000条返回,那么返回体里面会包含一个`"partial":true`的标记。该默认设置可能会导致Grafana面板出现意外行为,如果返回值大于10000时,这个面板就会看到[截断/部分数据](https://github.com/influxdata/influxdb/issues/8050)。 122 | 123 | 在1.2.2版本中,`max-row-limit`参数默认被设置为了0,这表示说对于返回值没有限制。 124 | 125 | 这个最大行的限制仅仅作用于非分块(non-chunked)的请求中,分块(chunked)的请求还是返回无限制的数据。 126 | 127 | #### 分块(chunking) 128 | 可以设置参数`chunked=true`开启分块,使返回的数据是流式的batch,而不是单个的返回。返回结果可以按10000数据点被分块,为了改变这个返回最大的分块的大小,可以在查询的时候加上`chunk_size`参数,例如返回数据点是每20000为一个批次。 129 | 130 | ``` 131 | curl -G 'http://localhost:8086/query' --data-urlencode "db=deluge" --data-urlencode "chunked=true" --data-urlencode "chunk_size=20000" --data-urlencode "q=SELECT * FROM liters" 132 | ``` 133 | 134 | #### InfluxQL 135 | 现在你已经知道了如何查询数据,查看[数据探索页面]()可以熟悉InfluxQL的用法。想要获取更多关于数据查询的HTTP接口的用法,情况[API参考文档]()。 136 | 137 | 138 | -------------------------------------------------------------------------------- /Guide/writing_data.md: -------------------------------------------------------------------------------- 1 | # 写入数据 2 | 3 | 有很多可以向InfluxDB写数据的方式,包括命令行、客户端还有一些像`Graphite`有一样数据格式的插件。这篇文章将会展示怎样创建数据库,并使用內建的HTTP接口写入数据。 4 | 5 | ## 使用HTTP接口创建数据库 6 | 使用`POST`方式发送到URL的`/query`路径,参数`q`为`CREATE DATABASE `,下面的例子发送一个请求到本地运行的InfluxDB创建数据库`mydb`: 7 | 8 | ``` 9 | curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE mydb" 10 | ``` 11 | 12 | ## 使用HTTP接口写数据 13 | 通过HTTP接口`POST`数据到`/write`路径是我们往InfluxDB写数据的主要方式。下面的例子写了一条数据到`mydb`数据库。这条数据的组成部分是measurement为`cpu_load_short`,tag的key为host和region,对应tag的value是`server01`和`us-west`,field的key是`value`,对应的数值为`0.64`,而时间戳是`1434055562000000000`。 14 | 15 | ``` 16 | curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000' 17 | ``` 18 | 19 | 当写入这条数据点的时候,你必须明确存在一个数据库对应名字是`db`参数的值。如果你没有通过`rp`参数设置retention policy的话,那么这个数据会写到`db`默认的retention policy中。想要获取更多参数的完整信息,请移步到`API参考`章节。 20 | 21 | 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时间。 22 | 23 | ### 同时写入多个点 24 | 要想同时发送多个数据点到多个series(在InfluxDB中measurement加tags组成了一个series),可以用新的行来分开这些数据点。这种批量发送的方式可以获得更高的性能。 25 | 26 | 下面的例子就是写了三个数据点到`mydb`数据库中。第一个点所属series的measurement为`cpu_load_short`,tag是`host=server02`,timestamp是server本地的时间戳;第二个点同样是measurement为`cpu_load_short`,但是tag为`host=server02,region=us-west`,且有明确timestamp为`1422568543702900257`的series;第三个数据点和第二个的timestamp是一样的,但是series不一样,其measurement为`cpu_load_short`,tag为`direction=in,host=server01,region=us-west`。 27 | 28 | ``` 29 | curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary 'cpu_load_short,host=server02 value=0.67 30 | cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257 31 | cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257' 32 | ``` 33 | 34 | ### 写入文件中的数据 35 | 可以通过`curl`的`@filename`来写入文件中的数据,且这个文件里的数据的格式需要满足InfluxDB那种行的语法。 36 | 37 | 给一个正确的文件(cpu_data.txt)的例子: 38 | 39 | ``` 40 | cpu_load_short,host=server02 value=0.67 41 | cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257 42 | cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257 43 | ``` 44 | 看我们如何把`cpu_data.txt`里的数据写入`mydb`数据库: 45 | 46 | ``` 47 | curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary @cpu_data.txt 48 | ``` 49 | 50 | >说明:如果你的数据文件的数据点大于5000时,你必须把他们拆分到多个文件再写入InfluxDB。因为默认的HTTP的timeout的值为5秒,虽然5秒之后,InfluxDB仍然会试图把这批数据写进去,但是会有数据丢失的风险。 51 | 52 | ### 无模式设计 53 | InfluxDB是一个无模式(schemaless)的数据库,你可以在任意时间添加measurement,tags和fields。注意:如果你试图写入一个和之前的类型不一样的数据(例如,filed字段之前接收的是数字类型,现在写了个字符串进去),那么InfluxDB会拒绝这个数据。 54 | 55 | ### 对于REST的一个说明 56 | InfluxDB使用HTTP作为方便和广泛支持的数据传输协议。 57 | 58 | 现代web的APIs都基于REST的设计,因为这样解决了一个共同的需求。因为随着终端数量的增长,组织系统的需求变得越来越迫切。REST是为了组织大量终端的一个业内认可的标准。这种一致性对于开发者和API的消费者都是一件好事:所有的参与者都知道期望的是什么。 59 | 60 | REST的确是很方便的,而InfluxDB也只提供了三个API,这使得InfluxQL在翻译为HTTP请求的时候很简单便捷。 所以InfluxDB API并不是RESTful的。 61 | 62 | ### HTTP返回值概要 63 | * 2xx:如果你写了数据后收到`HTTP 204 No Content`,说明写入成功了! 64 | * 4xx:表示InfluxDB不知道你发的是什么鬼。 65 | * 5xx:系统过载或是应用受损。 66 | 67 | 举几个返回错误的例子: 68 | 69 | * 之前接收的是布尔值,现在你写入一个浮点值: 70 | 71 | ``` 72 | curl -i -XPOST 'http://localhost:8086/write?db=hamlet' --data-binary 'tobeornottobe booleanonly=true' 73 | 74 | curl -i -XPOST 'http://localhost:8086/write?db=hamlet' --data-binary 'tobeornottobe booleanonly=5' 75 | ``` 76 | 这时系统返回: 77 | 78 | ``` 79 | HTTP/1.1 400 Bad Request 80 | Content-Type: application/json 81 | Request-Id: [...] 82 | X-Influxdb-Version: 1.2.x 83 | Date: Wed, 01 Mar 2017 19:38:01 GMT 84 | Content-Length: 150 85 | 86 | {"error":"field type conflict: input field \"booleanonly\" on measurement \"tobeornottobe\" is type float, already exists as type boolean dropped=1"} 87 | ``` 88 | 89 | * 写入数据到一个不存在的数据库中: 90 | 91 | ``` 92 | curl -i -XPOST 'http://localhost:8086/write?db=atlantis' --data-binary 'liters value=10' 93 | ``` 94 | 95 | 返回值: 96 | 97 | ``` 98 | HTTP/1.1 404 Not Found 99 | Content-Type: application/json 100 | Request-Id: [...] 101 | X-Influxdb-Version: 1.2.x 102 | Date: Wed, 01 Mar 2017 19:38:35 GMT 103 | Content-Length: 45 104 | 105 | {"error":"database not found: \"atlantis\""} 106 | ``` 107 | 108 | ### 下一步 109 | 现在你已经知道了如何通过内置HTTP API写入数据了,下面我们来看看怎么通过[读数据](querying_data.md)指南来读出它们。想要了解更多关于如何使用HTTP API写数据,请参考[API参考文档]()。 110 | -------------------------------------------------------------------------------- /Introduction/getting_start.md: -------------------------------------------------------------------------------- 1 | # 入门指南 2 | 3 | InfluxDB安装完成之后,我们开始来做一些有意思的事。在这一章里面我们将会用到`influx`这个命令行工具,这个工具包含在InfluxDB的安装包里,是一个操作数据库的轻量级工具。它直接通过InfluxDB的HTTP接口(如果没有修改,默认是8086)来和InfluxDB通信。 4 | 5 | >说明:也可以直接发送裸的HTTP请求来操作数据库,例如`curl` 6 | 7 | 8 | ## 创建数据库 9 | 如果你已经在本地安装运行了InfluxDB,你就可以直接使用`influx`命令行,执行`influx`连接到本地的InfluxDB实例上。输出就像下面这样: 10 | 11 | ``` 12 | $ influx -precision rfc3339 13 | Connected to http://localhost:8086 version 1.2.x 14 | InfluxDB shell 1.2.x 15 | > 16 | ``` 17 | 18 | >说明: 19 | * InfluxDB的HTTP接口默认起在`8086`上,所以`influx`默认也是连的本地的`8086`端口,你可以通过`influx --help`来看怎么修改默认值。 20 | * `-precision`参数表明了任何返回的时间戳的格式和精度,在上面的例子里,`rfc3339`是让InfluxDB返回[RFC339](https://www.ietf.org/rfc/rfc3339.txt)格式(YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ)的时间戳。 21 | 22 | 这样这个命令行已经准备好接收influx的查询语句了(简称InfluxQL),用`exit`可以退出命令行。 23 | 24 | 第一次安装好InfluxDB之后是没有数据库的(除了系统自带的`_internal`),因此创建一个数据库是我们首先要做的事,通过`CREATE DATABASE `这样的InfluxQL语句来创建,其中``就是数据库的名字。数据库的名字可以是被双引号引起来的任意Unicode字符。 如果名称只包含ASCII字母,数字或下划线,并且不以数字开头,那么也可以不用引起来。 25 | 26 | 我们来创建一个`mydb`数据库: 27 | 28 | ``` 29 | > CREATE DATABASE mydb 30 | > 31 | ``` 32 | 33 | >说明:在输入上面的语句之后,并没有看到任何信息,这在CLI里,表示语句被执行并且没有错误,如果有错误信息展示,那一定是哪里出问题了,这就是所谓的`没有消息就是好消息`。 34 | 35 | 现在数据库`mydb`已经创建好了,我们可以用`SHOW DATABASES`语句来看看已存在的数据库: 36 | 37 | ``` 38 | > SHOW DATABASES 39 | name: databases 40 | --------------- 41 | name 42 | _internal 43 | mydb 44 | 45 | > 46 | ``` 47 | 48 | >说明:`_internal`数据库是用来存储InfluxDB内部的实时监控数据的。 49 | 50 | 不像`SHOW DATABASES`,大部分InfluxQL需要作用在一个特定的数据库上。你当然可以在每一个查询语句上带上你想查的数据库的名字,但是CLI提供了一个更为方便的方式`USE `,这会为你后面的所以的请求设置到这个数据库上。例如: 51 | 52 | ``` 53 | > USE mydb 54 | Using database mydb 55 | > 56 | ``` 57 | 以下的操作都作用于`mydb`这个数据库之上。 58 | 59 | ## 读写数据 60 | 现在我们已经有了一个数据库,那么InfluxDB就可以开始接收读写了。 61 | 62 | 首先对数据存储的格式来个入门介绍。InfluxDB里存储的数据被称为`时间序列数据`,其包含一个数值,就像CPU的load值或是温度值类似的。时序数据有零个或多个数据点,每一个都是一个指标值。数据点包括`time`(一个时间戳),`measurement`(例如cpu_load),至少一个k-v格式的`field`(也即指标的数值例如 “value=0.64”或者“temperature=21.2”),零个或多个`tag`,其一般是对于这个指标值的元数据(例如“host=server01”, “region=EMEA”, “dc=Frankfurt)。 63 | 64 | 在概念上,你可以将`measurement`类比于SQL里面的table,其主键索引总是时间戳。`tag`和`field`是在table里的其他列,`tag`是被索引起来的,`field`没有。不同之处在于,在InfluxDB里,你可以有几百万的measurements,你不用事先定义数据的scheme,并且null值不会被存储。 65 | 66 | 将数据点写入InfluxDB,只需要遵守如下的行协议: 67 | 68 | ``` 69 | [,=...] =[,=...] [unix-nano-timestamp] 70 | ``` 71 | 72 | 下面是数据写入InfluxDB的格式示例: 73 | 74 | ``` 75 | cpu,host=serverA,region=us_west value=0.64 76 | payment,device=mobile,product=Notepad,method=credit billed=33,licenses=3i 1434067467100293230 77 | stock,symbol=AAPL bid=127.46,ask=127.48 78 | temperature,machine=unit42,type=assembly external=25,internal=37 1434067467000000000 79 | ``` 80 | 81 | >说明:关于写入格式的更多语法,请参考[写入语法]()这一章。 82 | 83 | 使用CLI插入单条的时间序列数据到InfluxDB中,用`INSERT`后跟数据点: 84 | 85 | ``` 86 | > INSERT cpu,host=serverA,region=us_west value=0.64 87 | > 88 | ``` 89 | 这样一个measurement为`cpu`,tag是`host`和`region`,`value`值为`0.64`的数据点被写入了InfluxDB中。 90 | 91 | 现在我们查出写入的这笔数据: 92 | 93 | ``` 94 | > SELECT "host", "region", "value" FROM "cpu" 95 | name: cpu 96 | --------- 97 | time host region value 98 | 2015-10-21T19:28:07.580664347Z serverA us_west 0.64 99 | 100 | > 101 | ``` 102 | 103 | >说明:我们在写入的时候没有包含时间戳,当没有带时间戳的时候,InfluxDB会自动添加本地的当前时间作为它的时间戳。 104 | 105 | 让我们来写入另一笔数据,它包含有两个字段: 106 | 107 | ``` 108 | > INSERT temperature,machine=unit42,type=assembly external=25,internal=37 109 | > 110 | ``` 111 | 查询的时候想要返回所有的字段和tag,可以用`*`: 112 | 113 | ``` 114 | 115 | > SELECT * FROM "temperature" 116 | name: temperature 117 | ----------------- 118 | time external internal machine type 119 | 2015-10-21T19:28:08.385013942Z 25 37 unit42 assembly 120 | 121 | > 122 | ``` 123 | 124 | InfluxQL还有很多特性和用法没有被提及,包括支持golang样式的正则,例如: 125 | 126 | ``` 127 | > SELECT * FROM /.*/ LIMIT 1 128 | -- 129 | > SELECT * FROM "cpu_load_short" 130 | -- 131 | > SELECT * FROM "cpu_load_short" WHERE "value" > 0.9 132 | ``` 133 | 134 | 这就是你需要知道的读写InfluxDB的方法,想要学习更多的写的知识请移步[写数据]()章节,读的知识请到[读数据]()章节。要获取更多InfluxDB的概念的信息,请查看[关键概念]()章节。 135 | -------------------------------------------------------------------------------- /Introduction/index.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | 这篇介绍文档包括获取、运行InfluxDB的信息。 4 | 5 | ## [下载](https://influxdata.com/downloads/#influxdb) 6 | 提供了最新稳定版和其他版本的InfluxDB下载地址。 7 | 8 | ## [安装](installation.html) 9 | 10 | 介绍在Ubuntu、Debian、Redhat、Centos和OS X上如何安装InfluxDB。 11 | 12 | ## [入门指南](getting_start.html) 13 | 14 | 介绍利用InfluxDB怎样读写时序数据。 15 | 16 | 17 | -------------------------------------------------------------------------------- /Introduction/installation.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | 这篇将会介绍怎么安装、运行和配置InfluxDB。 4 | 5 | ## 准备 6 | 安装InfluxDB包需要`root`或是有管理员权限才可以。 7 | 8 | ### 网络 9 | InfluxDB默认使用下面的网络端口: 10 | 11 | * TCP端口`8086`用作InfluxDB的客户端和服务端的http api通信 12 | * TCP端口`8088`给备份和恢复数据的RPC服务使用 13 | 14 | 另外,InfluxDB也提供了多个可能需要自定义端口的插件,所以的端口映射都可以通过配置文件修改,对于默认安装的InfluxDB,这个配置文件位于`/etc/influxdb/influxdb.conf`。 15 | 16 | ### NTP 17 | InfluxDB使用服务器本地时间给数据加时间戳,而且是UTC时区的。并使用NTP来同步服务器之间的时间,如果服务器的时钟没有通过NTP同步,那么写入InfluxDB的数据的时间戳就可能不准确。 18 | 19 | ## 安装 20 | 对于不想安装的用户,可以使用inluxdata公司提供的云产品(帮忙给他们打个广告吧,毕竟开源不易)。 21 | ### Debain & Ubuntu 22 | Debian和Ubuntu用户可以直接用`apt-get`包管理来安装最新版本的InfluxDB。 23 | 24 | 对于Ubuntu用户,可以用下面的命令添加InfluxDB的仓库 25 | 26 | ``` 27 | curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add - 28 | source /etc/lsb-release 29 | echo "deb https://repos.influxdata.com/${DISTRIB_ID,,} ${DISTRIB_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/influxdb.list 30 | ``` 31 | 32 | Debian用户用下面的命令: 33 | 34 | ``` 35 | curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add - 36 | source /etc/os-release 37 | test $VERSION_ID = "7" && echo "deb https://repos.influxdata.com/debian wheezy stable" | sudo tee /etc/apt/sources.list.d/influxdb.list 38 | test $VERSION_ID = "8" && echo "deb https://repos.influxdata.com/debian jessie stable" | sudo tee /etc/apt/sources.list.d/influxdb.list 39 | ``` 40 | 41 | 然后安装、运行InfluxDB服务: 42 | 43 | ``` 44 | sudo apt-get update && sudo apt-get install influxdb 45 | sudo service influxdb start 46 | ``` 47 | 48 | 如果你的系统可以使用Systemd(比如Ubuntu 15.04+, Debian 8+),也可以这样启动: 49 | 50 | ``` 51 | sudo apt-get update && sudo apt-get install influxdb 52 | sudo systemctl start influxdb 53 | ``` 54 | 55 | ### RedHat & CentOS 56 | RedHat和CentOS用户可以直接用`yum`包管理来安装最新版本的InfluxDB。 57 | 58 | ``` 59 | cat <注意:认证只发生在HTTP请求范围内。插件目前不具备认证请求的能力,(例如Graphite、collectd等)是没有认证的。 7 | 8 | ### 创建认证 9 | #### 1. 至少创建一个admin用户 10 | 11 | >如果你开启了认证但是没有用户,那么InfluxDB将不会开启认证,而且只有在创建了一个admin用户之后才会接受外部请求。 12 | 13 | 当创建一个admin用户后,InfluxDB才能开启认证。 14 | 15 | #### 2. 在配置文件中,认证默认是不开启的 16 | 将`[http]`区域的配置`auth-enabled`设为`true`,可以开启认证: 17 | 18 | ``` 19 | [http] 20 | enabled = true 21 | bind-address = ":8086" 22 | auth-enabled = true # ✨ 23 | log-enabled = true 24 | write-tracing = false 25 | pprof-enabled = false 26 | https-enabled = false 27 | https-certificate = "/etc/ssl/influxdb.pem" 28 | ``` 29 | 30 | #### 3. 重启进程 31 | 现在InfluxDB会核对每个请求中的用户信息,只会处理已有用户而认证通过的请求。 32 | 33 | ### 认证请求 34 | #### HTTP API中的认证 35 | 有两个HTTP API进行验证的方式。 36 | 37 | 如果使用基本身份验证和URL查询参数进行身份验证,则以查询参数中指定的用户优先。下面的示例中的查询假定用户是admin用户。 38 | 39 | ##### 用[RFC 2617](http://tools.ietf.org/html/rfc2617)中所描述的基本身份验证 40 | 41 | 这是提供用户的首选方法。例: 42 | 43 | ``` 44 | curl -G http://localhost:8086/query -u todd:influxdb4ever --data-urlencode "q=SHOW DATABASES" 45 | ``` 46 | 47 | ##### 在URL的参数或是请求体里面提供认证 48 | 设置`u`和`p`参数, 例: 49 | 50 | ``` 51 | curl -G "http://localhost:8086/query?u=todd&p=influxdb4ever" --data-urlencode "q=SHOW DATABASES" 52 | ``` 53 | 54 | 认证在请求体中的例子: 55 | 56 | ``` 57 | curl -G http://localhost:8086/query --data-urlencode "u=todd" --data-urlencode "p=influxdb4ever" --data-urlencode "q=SHOW DATABASES" 58 | ``` 59 | 60 | #### CLI中的认证 61 | 在CLI中有三种认证方式。 62 | 63 | ##### 设置`INFLUX_USERNAME`和`INFLUX_PASSWORD`环境变量 64 | 例如: 65 | 66 | ``` 67 | export INFLUX_USERNAME todd 68 | export INFLUX_PASSWORD influxdb4ever 69 | echo $INFLUX_USERNAME $INFLUX_PASSWORD 70 | todd influxdb4ever 71 | 72 | influx 73 | Connected to http://localhost:8086 version 1.3.x 74 | InfluxDB shell 1.3.x 75 | ``` 76 | 77 | ##### 开启CLI时设置`username`和`password` 78 | 例如: 79 | 80 | ``` 81 | influx -username todd -password influxdb4ever 82 | Connected to http://localhost:8086 version 1.3.x 83 | InfluxDB shell 1.3.x 84 | ``` 85 | 86 | ##### 开启CLI后使用`auth ` 87 | 例如: 88 | 89 | ``` 90 | influx 91 | Connected to http://localhost:8086 version 1.3.x 92 | InfluxDB shell 1.3.x 93 | > auth 94 | username: todd 95 | password: 96 | > 97 | ``` 98 | 99 | ## 授权 100 | 当开启认证之后,授权也就开启了。默认情况下,所有的用户都有所有的权限。 101 | 102 | ### 用户类型和权限 103 | #### admin用户 104 | admin用户有所有数据库的读写权限,这些所有的权限包括如下: 105 | 106 | 数据库管理: 107 | 108 | * `CREATE DATABASE`, `DROP DATABASE` 109 | * `DROP SERIES`, `DROP MEASUREMENT` 110 | * `CREATE RETENTION POLICY`,` ALTER RETENTION POLICY`, 和 `DROP RETENTION POLICY` 111 | * `CREATE CONTINUOUS QUERY`和`DROP CONTINUOUS QUERY` 112 | 113 | 用户管理: 114 | 115 | * admin用户管理: 116 | `CREATE USER`, `GRANT ALL PRIVILEGES`, `REVOKE ALL PRIVILEGES`,和`SHOW USERS` 117 | 118 | * 非admin用户管理: 119 | `CREATE USER`, `GRANT [READ,WRITE,ALL]`, `REVOKE [READ,WRITE,ALL]`,和`SHOW GRANTS` 120 | 121 | * 一般admin用户管理: 122 | `SET PASSWORD`和`DROP USER` 123 | 124 | #### 非admin用户 125 | 非admin用户对于每个数据库,有如下三个权限: 126 | 127 | * `READ` 128 | * `WRITE` 129 | * `ALL`(包括`READ`和`WRITE`) 130 | 131 | `READ`,`WRITE`和`ALL`控制到每个数据库每个用户上。一个新的非admin用户对任何数据库都没有权限,除非被admin用户指定一个数据库权限。非admin用户可以在他们有`READ`或/和`WRITE`权限的机器上运行`SHOW`命令。 132 | 133 | ### 用户管理命令 134 | #### admin用户管理 135 | 当开启HTTP认证之后,在你操作系统之前,InfluxDB要求你至少创建一个admin用户。 136 | 137 | ``` 138 | CREATE USER admin WITH PASSWORD '' WITH ALL PRIVILEGES 139 | ``` 140 | 141 | ##### `CREATE`另一个admin用户 142 | 143 | ``` 144 | CREATE USER WITH PASSWORD '' WITH ALL PRIVILEGES 145 | ``` 146 | 147 | CLI例子: 148 | 149 | ``` 150 | > CREATE USER paul WITH PASSWORD 'timeseries4days' WITH ALL PRIVILEGES 151 | > 152 | ``` 153 | 154 | >注意:重复创建确切的用户语句是幂等的。如果有值发生变化,数据库将返回一个重复的用户错误。 155 | >CLI例子: 156 | > 157 | >``` 158 | > CREATE USER todd WITH PASSWORD '123456' WITH ALL PRIVILEGES 159 | > CREATE USER todd WITH PASSWORD '123456' WITH ALL PRIVILEGES 160 | > CREATE USER todd WITH PASSWORD '123' WITH ALL PRIVILEGES 161 | ERR: user already exists 162 | > CREATE USER todd WITH PASSWORD '123456' 163 | ERR: user already exists 164 | > CREATE USER todd WITH PASSWORD '123456' WITH ALL PRIVILEGES 165 | > 166 | >``` 167 | 168 | ##### 给一个存在的用户`GRANT`权限 169 | 170 | ``` 171 | GRANT ALL PRIVILEGES TO 172 | ``` 173 | 174 | CLI例子: 175 | 176 | ``` 177 | > GRANT ALL PRIVILEGES TO "todd" 178 | > 179 | ``` 180 | 181 | ##### 给一个admin用户`REVOKE`权限 182 | ``` 183 | REVOKE ALL PRIVILEGES FROM 184 | ``` 185 | 186 | CLI例子: 187 | 188 | ``` 189 | > REVOKE ALL PRIVILEGES FROM "todd" 190 | > 191 | ``` 192 | 193 | ##### `SHOW`所有存在的用户以及其admin状态 194 | ``` 195 | SHOW USERS 196 | ``` 197 | 198 | CLI例子: 199 | 200 | ``` 201 | > SHOW USERS 202 | user admin 203 | todd false 204 | paul true 205 | hermione false 206 | dobby false 207 | ``` 208 | 209 | #### 非admin用户管理 210 | ##### `CREATE`一个非admin用户: 211 | 212 | ``` 213 | CREATE USER WITH PASSWORD '' 214 | ``` 215 | 216 | CLI例子: 217 | 218 | ``` 219 | > CREATE USER todd WITH PASSWORD 'influxdb41yf3' 220 | > CREATE USER alice WITH PASSWORD 'wonder\'land' 221 | > CREATE USER "rachel_smith" WITH PASSWORD 'asdf1234!' 222 | > CREATE USER "monitoring-robot" WITH PASSWORD 'XXXXX' 223 | > CREATE USER "$savyadmin" WITH PASSWORD 'm3tr1cL0v3r' 224 | > 225 | ``` 226 | 227 | >注意: 228 | > 229 | >* 用户名如果用一个数字的开始,或者是一个influxql关键字,又或者包含任何特殊字符,例如:`!@#$%^&*()-`, 则必须用双引号引起来 230 | >* 密码字符串必须用单引号引起来。 231 | >* 在验证请求时不包含单引号。 232 | > 233 | >如果密码包含单引号或换行符,当提交认证请求时,应该用反斜杠转义。 234 | 235 | ##### `GRANT READ, WRITE`或者`ALL`数据库权限给一个存在的用户 236 | 237 | ``` 238 | GRANT [READ,WRITE,ALL] ON TO 239 | ``` 240 | 241 | CLI例子: 给用户`todd``GRANT`数据库`NOAA_water_database`的`READ`的权限: 242 | 243 | ``` 244 | > GRANT READ ON "NOAA_water_database" TO "todd" 245 | > 246 | ``` 247 | 248 | 给用户`todd``GRANT`数据库`NOAA_water_database`的`ALL`的权限: 249 | 250 | ``` 251 | > GRANT ALL ON "NOAA_water_database" TO "todd" 252 | > 253 | ``` 254 | 255 | ##### `REVOKE READ, WRITE`或者`ALL` 数据库权限给一个存在的用户 256 | 257 | ``` 258 | REVOKE [READ,WRITE,ALL] ON FROM 259 | ``` 260 | 261 | CLI例子: 给用户`todd``REVOKE`数据库`NOAA_water_database`的`ALL`的权限: 262 | 263 | ``` 264 | > REVOKE ALL ON "NOAA_water_database" FROM "todd" 265 | > 266 | ``` 267 | 268 | 给用户`todd``REVOKE`数据库`NOAA_water_database`的`WRITE`的权限: 269 | 270 | ``` 271 | > REVOKE WRITE ON "NOAA_water_database" FROM "todd" 272 | > 273 | ``` 274 | 275 | ##### `SHOW`一个用户的数据库权限 276 | 277 | ``` 278 | SHOW GRANTS FOR 279 | 280 | ``` 281 | 282 | CLI例子: 283 | 284 | ``` 285 | > SHOW GRANTS FOR "todd" 286 | database privilege 287 | NOAA_water_database WRITE 288 | another_database_name READ 289 | yet_another_database_name ALL PRIVILEGES 290 | ``` 291 | 292 | #### 普通admin和非admin用户管理 293 | ##### 重新设置一个用户的密码 294 | 295 | ``` 296 | SET PASSWORD FOR = '' 297 | ``` 298 | 299 | CLI例子: 300 | 301 | ``` 302 | > SET PASSWORD FOR "todd" = 'influxdb4ever' 303 | > 304 | ``` 305 | 306 | ``` 307 | > **Note:** The password [string](/influxdb/v1.3/query_language/spec/#strings) must be wrapped in single quotes. 308 | ``` 309 | 310 | ##### `DROP`一个用户 311 | ``` 312 | DROP USER 313 | ``` 314 | 315 | CLI例子: 316 | 317 | ``` 318 | > DROP USER "todd" 319 | > 320 | ``` 321 | 322 | ## 认证和授权的HTTP错误 323 | 没有认证或者是带有不正确认证信息的请求发到InfluxDB,将会返回一个`HTTP 401 Unauthorized`的错误。 324 | 325 | 没有授权的用户的请求发到InfluxDB,将会返回一个`HTTP 403 Forbidden`的错误。 -------------------------------------------------------------------------------- /Query_language/continuous_queries.md: -------------------------------------------------------------------------------- 1 | # 连续查询 2 | ## 介绍 3 | 连续查询(Continuous Queries下文统一简称CQ)是InfluxQL对实时数据自动周期运行的查询,然后把查询结果写入到指定的measurement中。 4 | 5 | ## 语法 6 | ### 基本语法 7 | ``` 8 | CREATE CONTINUOUS QUERY ON 9 | BEGIN 10 | 11 | END 12 | ``` 13 | 14 | #### 语法描述 15 | ##### cq_query 16 | `cq_query`需要一个函数,一个`INTO`子句和一个`GROUP BY time()`子句: 17 | 18 | ``` 19 | SELECT INTO FROM [WHERE ] GROUP BY time()[,] 20 | ``` 21 | 22 | >注意:请注意,在`WHERE`子句中,`cq_query`不需要时间范围。 InfluxDB在执行CQ时自动生成`cq_query`的时间范围。`cq_query`的`WHERE`子句中的任何用户指定的时间范围将被系统忽略。 23 | 24 | ##### 运行时间点以及覆盖的时间范围 25 | 26 | CQ对实时数据进行操作。他们使用本地服务器的时间戳,`GROUP BY time()`间隔和InfluxDB的预设时间边界来确定何时执行以及查询中涵盖的时间范围。 27 | 28 | CQs以与`cq_query`的`GROUP BY time()`间隔相同的间隔执行,并且它们在InfluxDB的预设时间边界开始时运行。如果`GROUP BY time()`间隔为1小时,则CQ每小时开始执行一次。 29 | 30 | 当CQ执行时,它对于`now()`和`now()`减去`GROUP BY time()`间隔的时间范围运行单个查询。 如果`GROUP BY time()`间隔为1小时,当前时间为17:00,查询的时间范围为16:00至16:59999999999。 31 | 32 | #### 基本语法的例子 33 | 以下例子使用数据库`transportation`中的示例数据。measurement`bus_data`数据存储有关公共汽车乘客数量和投诉数量的15分钟数据: 34 | 35 | ``` 36 | name: bus_data 37 | -------------- 38 | time passengers complaints 39 | 2016-08-28T07:00:00Z 5 9 40 | 2016-08-28T07:15:00Z 8 9 41 | 2016-08-28T07:30:00Z 8 9 42 | 2016-08-28T07:45:00Z 7 9 43 | 2016-08-28T08:00:00Z 8 9 44 | 2016-08-28T08:15:00Z 15 7 45 | 2016-08-28T08:30:00Z 15 7 46 | 2016-08-28T08:45:00Z 17 7 47 | 2016-08-28T09:00:00Z 20 7 48 | ``` 49 | 50 | ##### 例一:自动采样数据 51 | 使用简单的CQ自动从单个字段中下采样数据,并将结果写入同一数据库中的另一个measurement。 52 | 53 | ``` 54 | CREATE CONTINUOUS QUERY "cq_basic" ON "transportation" 55 | BEGIN 56 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h) 57 | END 58 | ``` 59 | 60 | `cq_basic`从`bus_data`中计算乘客的平均小时数,并将结果存储在数据库`transportation`中的`average_passengers`中。 61 | 62 | `cq_basic`以一小时的间隔执行,与`GROUP BY time()`间隔相同的间隔。 每个小时,`cq_basic`运行一个单一的查询,覆盖了`now()`和`now()`减去`GROUP BY time()`间隔之间的时间范围,即`now()`和`now()`之前的一个小时之间的时间范围。 63 | 64 | 下面是2016年8月28日上午的日志输出: 65 | 66 | >在8点时,`cq_basic`执行时间范围为`time => '7:00' AND time <'08:00'`的查询。 67 | `cq_basic`向`average_passengers`写入一个点: 68 | > 69 | ``` 70 | name: average_passengers 71 | ------------------------ 72 | time mean 73 | 2016-08-28T07:00:00Z 7 74 | ``` 75 | >在9点时,`cq_basic`执行时间范围为`time => '8:00' AND time <'09:00'`的查询。 76 | `cq_basic`向`average_passengers`写入一个点: 77 | > 78 | ``` 79 | name: average_passengers 80 | ------------------------ 81 | time mean 82 | 2016-08-28T08:00:00Z 13.75 83 | ``` 84 | 85 | 结果: 86 | 87 | ``` 88 | > SELECT * FROM "average_passengers" 89 | name: average_passengers 90 | ------------------------ 91 | time mean 92 | 2016-08-28T07:00:00Z 7 93 | 2016-08-28T08:00:00Z 13.75 94 | ``` 95 | 96 | ##### 例二:自动采样数据到另一个保留策略里 97 | 从默认的的保留策略里面采样数据到完全指定的目标measurement中: 98 | 99 | ``` 100 | CREATE CONTINUOUS QUERY "cq_basic_rp" ON "transportation" 101 | BEGIN 102 | SELECT mean("passengers") INTO "transportation"."three_weeks"."average_passengers" FROM "bus_data" GROUP BY time(1h) 103 | END 104 | ``` 105 | 106 | `cq_basic_rp`从`bus_data`中计算乘客的平均小时数,并将结果存储在数据库`tansportation`的RP为`three_weeks`的measurement`average_passengers`中。 107 | 108 | `cq_basic_rp`以一小时的间隔执行,与`GROUP BY time()`间隔相同的间隔。每个小时,`cq_basic_rp`运行一个单一的查询,覆盖了`now()`和`now()`减去`GROUP BY time()`间隔之间的时间段,即`now()`和`now()`之前的一个小时之间的时间范围。 109 | 110 | 下面是2016年8月28日上午的日志输出: 111 | 112 | >在8:00`cq_basic_rp`执行时间范围为` time >='7:00' AND time <'8:00'`的查询。`cq_basic_rp`向RP为`three_weeks`的measurement`average_passengers`写入一个点: 113 | > 114 | ``` 115 | name: average_passengers 116 | ------------------------ 117 | time mean 118 | 2016-08-28T07:00:00Z 7 119 | ``` 120 | >在9:00`cq_basic_rp`执行时间范围为` time >='8:00' AND time <'9:00'`的查询。`cq_basic_rp`向RP为`three_weeks`的measurement`average_passengers`写入一个点: 121 | > 122 | ``` 123 | name: average_passengers 124 | ------------------------ 125 | time mean 126 | 2016-08-28T08:00:00Z 13.75 127 | ``` 128 | 129 | 结果: 130 | 131 | ``` 132 | > SELECT * FROM "transportation"."three_weeks"."average_passengers" 133 | name: average_passengers 134 | ------------------------ 135 | time mean 136 | 2016-08-28T07:00:00Z 7 137 | 2016-08-28T08:00:00Z 13.75 138 | ``` 139 | 140 | `cq_basic_rp`使用CQ和保留策略自动降低样本数据,并将这些采样数据保留在不同的时间长度上。 141 | 142 | ##### 例三:使用逆向引用自动采样数据 143 | 使用带有通配符(`*`)和`INTO`查询的反向引用语法的函数可自动对数据库中所有measurement和数值字段中的数据进行采样。 144 | 145 | ``` 146 | CREATE CONTINUOUS QUERY "cq_basic_br" ON "transportation" 147 | BEGIN 148 | SELECT mean(*) INTO "downsampled_transportation"."autogen".:MEASUREMENT FROM /.*/ GROUP BY time(30m),* 149 | END 150 | ``` 151 | 152 | `cq_basic_br`计算数据库`transportation`中每个measurement的30分钟平均乘客和投诉。它将结果存储在数据库`downsampled_transportation`中。 153 | 154 | `cq_basic_br`以30分钟的间隔执行,与`GROUP BY time()`间隔相同的间隔。每30分钟一次,`cq_basic_br`运行一个查询,覆盖了`now()`和`now()`减去`GROUP BY time()`间隔之间的时间段,即`now()`到`now()`之前的30分钟之间的时间范围。 155 | 156 | 下面是2016年8月28日上午的日志输出: 157 | 158 | >在7:30,`cq_basic_br`执行查询,时间间隔 `time >='7:00' AND time <'7:30'`。`cq_basic_br`向`downsampled_transportation`数据库中的measurement为`bus_data`写入两个点: 159 | > 160 | ``` 161 | name: bus_data 162 | -------------- 163 | time mean_complaints mean_passengers 164 | 2016-08-28T07:00:00Z 9 6.5 165 | ``` 166 | >8点时,`cq_basic_br`执行时间范围为 `time >='7:30' AND time <'8:00'`的查询。`cq_basic_br`向`downsampled_transportation`数据库中measurement为`bus_data`写入两个点: 167 | > 168 | ``` 169 | name: bus_data 170 | -------------- 171 | time mean_complaints mean_passengers 172 | 2016-08-28T07:30:00Z 9 7.5 173 | ``` 174 | > 175 | >[…] 176 | > 177 | >9点时,`cq_basic_br`执行时间范围为 `time >='8:30' AND time <'9:00'`的查询。`cq_basic_br`向`downsampled_transportation`数据库中measurement为`bus_data`写入两个点: 178 | > 179 | ``` 180 | name: bus_data 181 | -------------- 182 | time mean_complaints mean_passengers 183 | 2016-08-28T08:30:00Z 7 16 184 | ``` 185 | 186 | 结果为: 187 | 188 | ``` 189 | > SELECT * FROM "downsampled_transportation."autogen"."bus_data" 190 | name: bus_data 191 | -------------- 192 | time mean_complaints mean_passengers 193 | 2016-08-28T07:00:00Z 9 6.5 194 | 2016-08-28T07:30:00Z 9 7.5 195 | 2016-08-28T08:00:00Z 8 11.5 196 | 2016-08-28T08:30:00Z 7 16 197 | ``` 198 | 199 | ##### 例四:自动采样数据并配置CQ的时间边界 200 | 使用`GROUP BY time()`子句的偏移间隔来改变CQ的默认执行时间和呈现的时间边界: 201 | 202 | ``` 203 | CREATE CONTINUOUS QUERY "cq_basic_offset" ON "transportation" 204 | BEGIN 205 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h,15m) 206 | END 207 | ``` 208 | 209 | `cq_basic_offset`从`bus_data`中计算乘客的平均小时数,并将结果存储在`average_passengers`中。 210 | 211 | `cq_basic_offset`以一小时的间隔执行,与`GROUP BY time()`间隔相同的间隔。15分钟偏移间隔迫使CQ在默认执行时间后15分钟执行; `cq_basic_offset`在8:15而不是8:00执行。 212 | 213 | 每个小时,`cq_basic_offset`运行一个单一的查询,覆盖了`now()`和`now()`减去`GROUP BY time()`间隔之间的时间段,即`now()`和`now()`之前的一个小时之间的时间范围。 15分钟偏移间隔在CQ的`WHERE`子句中向前移动生成的预设时间边界; `cq_basic_offset`在7:15和8:14.999999999而不是7:00和7:59.999999999之间进行查询。 214 | 215 | 下面是2016年8月28日上午的日志输出: 216 | 217 | >在8:15`cq_basic_offset`执行时间范围`time> ='7:15'AND time <'8:15'`的查询。 218 | `cq_basic_offset`向`average_passengers`写入一个点: 219 | > 220 | ``` 221 | name: average_passengers 222 | ------------------------ 223 | time mean 224 | 2016-08-28T07:15:00Z 7.75 225 | ``` 226 | >在9:15`cq_basic_offset`执行时间范围`time> ='8:15'AND time <'9:15'`的查询。 227 | `cq_basic_offset`向`average_passengers`写入一个点: 228 | > 229 | ``` 230 | name: average_passengers 231 | ------------------------ 232 | time mean 233 | 2016-08-28T08:15:00Z 16.75 234 | ``` 235 | 236 | 结果为: 237 | 238 | ``` 239 | > SELECT * FROM "average_passengers" 240 | name: average_passengers 241 | ------------------------ 242 | time mean 243 | 2016-08-28T07:15:00Z 7.75 244 | 2016-08-28T08:15:00Z 16.75 245 | ``` 246 | 247 | 请注意,时间戳为7:15和8:15而不是7:00和8:00。 248 | 249 | #### 基本语法的常见问题 250 | ##### 问题一:无数据处理时间间隔 251 | 如果没有数据落在该时间范围内,则CQ不会在时间间隔内写入任何结果。请注意,基本语法不支持使用`fill()`更改不含数据的间隔报告的值。如果基本语法CQs包括了`fill()`,则会忽略`fill()`。一个解决办法是使用下面的高级语法。 252 | 253 | ##### 问题二:重新采样以前的时间间隔 254 | 基本的CQ运行一个查询,覆盖了`now()`和`now()`减去`GROUP BY time()`间隔之间的时间段。有关如何配置查询的时间范围,请参阅高级语法。 255 | 256 | ##### 问题三:旧数据的回填结果 257 | CQ对实时数据进行操作,即具有相对于`now()`发生的时间戳的数据。使用基本的`INTO`查询来回填具有较旧时间戳的数据的结果。 258 | 259 | ##### 问题四:CQ结果中缺少tag 260 | 默认情况下,所有`INTO`查询将源measurement中的任何tag转换为目标measurement中的field。 261 | 262 | 在CQ中包含`GROUP BY *`,以保留目的measurement中的tag。 263 | 264 | ### 高级语法 265 | ``` 266 | CREATE CONTINUOUS QUERY ON 267 | RESAMPLE EVERY FOR 268 | BEGIN 269 | 270 | END 271 | ``` 272 | #### 高级语法描述 273 | ##### cq_query 274 | 同上面基本语法里面的`cq_query`。 275 | ##### 运行时间点以及覆盖的时间范围 276 | CQs对实时数据进行操作。使用高级语法,CQ使用本地服务器的时间戳以及`RESAMPLE`子句中的信息和InfluxDB的预设时间边界来确定执行时间和查询中涵盖的时间范围。 277 | 278 | CQs以与`RESAMPLE`子句中的`EVERY`间隔相同的间隔执行,并且它们在InfluxDB的预设时间边界开始时运行。如果`EVERY`间隔是两个小时,InfluxDB将在每两小时的开始执行CQ。 279 | 280 | 当CQ执行时,它运行一个单一的查询,在`now()`和`now()`减去`RESAMPLE`子句中的`FOR`间隔之间的时间范围。如果`FOR`间隔为两个小时,当前时间为17:00,查询的时间间隔为15:00至16:59999999999。 281 | 282 | `EVERY`间隔和`FOR`间隔都接受时间字符串。`RESAMPLE`子句适用于同时配置`EVERY`和`FOR`,或者是其中之一。如果没有提供`EVERY`间隔或`FOR`间隔,则CQ默认为相关为基本语法。 283 | 284 | #### 高级语法例子 285 | 示例数据如下: 286 | 287 | ``` 288 | name: bus_data 289 | -------------- 290 | time passengers 291 | 2016-08-28T06:30:00Z 2 292 | 2016-08-28T06:45:00Z 4 293 | 2016-08-28T07:00:00Z 5 294 | 2016-08-28T07:15:00Z 8 295 | 2016-08-28T07:30:00Z 8 296 | 2016-08-28T07:45:00Z 7 297 | 2016-08-28T08:00:00Z 8 298 | 2016-08-28T08:15:00Z 15 299 | 2016-08-28T08:30:00Z 15 300 | 2016-08-28T08:45:00Z 17 301 | 2016-08-28T09:00:00Z 20 302 | ``` 303 | 304 | ##### 例一:配置执行间隔 305 | 在`RESAMPLE`中使用`EVERY`来指明CQ的执行间隔。 306 | 307 | ``` 308 | CREATE CONTINUOUS QUERY "cq_advanced_every" ON "transportation" 309 | RESAMPLE EVERY 30m 310 | BEGIN 311 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h) 312 | END 313 | ``` 314 | 315 | `cq_advanced_every`从`bus_data`中计算`passengers`的一小时平均值,并将结果存储在数据库`transportation`中的`average_passengers`中。 316 | 317 | `cq_advanced_every`以30分钟的间隔执行,间隔与`EVERY`间隔相同。每30分钟,`cq_advanced_every`运行一个查询,覆盖当前时间段的时间范围,即与`now()`交叉的一小时时间段。 318 | 319 | 下面是2016年8月28日上午的日志输出: 320 | 321 | >在8:00`cq_basic_every`执行时间范围`time> ='7:00'AND time <'8:00'`的查询。 322 | `cq_basic_every`向`average_passengers`写入一个点: 323 | > 324 | ``` 325 | name: average_passengers 326 | ------------------------ 327 | time mean 328 | 2016-08-28T07:00:00Z 7 329 | ``` 330 | >在8:30`cq_basic_every`执行时间范围`time> ='8:00'AND time <'9:00'`的查询。 331 | `cq_basic_every`向`average_passengers`写入一个点: 332 | > 333 | ``` 334 | name: average_passengers 335 | ------------------------ 336 | time mean 337 | 2016-08-28T08:00:00Z 12.6667 338 | ``` 339 | >在9:00`cq_basic_every`执行时间范围`time> ='8:00'AND time <'9:00'`的查询。 340 | `cq_basic_every`向`average_passengers`写入一个点: 341 | > 342 | ``` 343 | name: average_passengers 344 | ------------------------ 345 | time mean 346 | 2016-08-28T08:00:00Z 13.75 347 | ``` 348 | 349 | 结果为: 350 | 351 | ``` 352 | > SELECT * FROM "average_passengers" 353 | name: average_passengers 354 | ------------------------ 355 | time mean 356 | 2016-08-28T07:00:00Z 7 357 | 2016-08-28T08:00:00Z 13.75 358 | ``` 359 | 360 | 请注意,`cq_advanced_every`计算8:00时间间隔的结果两次。第一次,它运行在8:30,计算每个可用数据点在8:00和9:00(8,15和15)之间的平均值。 第二次,它运行在9:00,计算每个可用数据点在8:00和9:00(8,15,15和17)之间的平均值。由于InfluxDB处理重复点的方式,所以第二个结果只是覆盖第一个结果。 361 | 362 | ##### 例二:配置CQ的重采样时间范围 363 | 在`RESAMPLE`中使用`FOR`来指明CQ的时间间隔的长度。 364 | 365 | ``` 366 | CREATE CONTINUOUS QUERY "cq_advanced_for" ON "transportation" 367 | RESAMPLE FOR 1h 368 | BEGIN 369 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(30m) 370 | END 371 | ``` 372 | 373 | `cq_advanced_for`从`bus_data`中计算`passengers`的30分钟平均值,并将结果存储在数据库`transportation`中的`average_passengers`中。 374 | 375 | `cq_advanced_for`以30分钟的间隔执行,间隔与`GROUP BY time()`间隔相同。每30分钟,`cq_advanced_for`运行一个查询,覆盖时间段为`now()`和`now()`减去`FOR`中的间隔,即是`now()`和`now()`之前的一个小时之间的时间范围。 376 | 377 | 378 | 下面是2016年8月28日上午的日志输出: 379 | 380 | >在8:00`cq_advanced_for`执行时间范围`time> ='7:00'AND time <'8:00'`的查询。 381 | `cq_advanced_for`向`average_passengers`写入两个点: 382 | > 383 | ``` 384 | name: average_passengers 385 | ------------------------ 386 | time mean 387 | 2016-08-28T07:00:00Z 6.5 388 | 2016-08-28T07:30:00Z 7.5 389 | ``` 390 | >在8:30`cq_advanced_for`执行时间范围`time> ='7:30'AND time <'8:30'`的查询。 391 | `cq_advanced_for`向`average_passengers`写入两个点: 392 | > 393 | ``` 394 | name: average_passengers 395 | ------------------------ 396 | time mean 397 | 2016-08-28T07:30:00Z 7.5 398 | 2016-08-28T08:00:00Z 11.5 399 | ``` 400 | >在9:00`cq_advanced_for `执行时间范围`time> ='8:00'AND time <'9:00'`的查询。 401 | `cq_advanced_for `向`average_passengers`写入两个点: 402 | > 403 | ``` 404 | name: average_passengers 405 | ------------------------ 406 | time mean 407 | 2016-08-28T08:00:00Z 11.5 408 | 2016-08-28T08:30:00Z 16 409 | ``` 410 | 411 | 请注意,`cq_advanced_for`会计算每次间隔两次的结果。CQ在8:00和8:30计算7:30的平均值,在8:30和9:00计算8:00的平均值。 412 | 413 | 结果为: 414 | 415 | ``` 416 | > SELECT * FROM "average_passengers" 417 | name: average_passengers 418 | ------------------------ 419 | time mean 420 | 2016-08-28T07:00:00Z 6.5 421 | 2016-08-28T07:30:00Z 7.5 422 | 2016-08-28T08:00:00Z 11.5 423 | 2016-08-28T08:30:00Z 16 424 | ``` 425 | 426 | ##### 例三:配置执行间隔和CQ时间范围 427 | 在`RESAMPLE`子句中使用`EVERY`和`FOR`来指定CQ的执行间隔和CQ的时间范围长度。 428 | 429 | ``` 430 | CREATE CONTINUOUS QUERY "cq_advanced_every_for" ON "transportation" 431 | RESAMPLE EVERY 1h FOR 90m 432 | BEGIN 433 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(30m) 434 | END 435 | ``` 436 | 437 | `cq_advanced_every_for`从`bus_data`中计算`passengers`的30分钟平均值,并将结果存储在数据库`transportation`中的`average_passengers`中。 438 | 439 | `cq_advanced_every_for`以1小时的间隔执行,间隔与`EVERY`间隔相同。每1小时,`cq_advanced_every_for`运行一个查询,覆盖时间段为`now()`和`now()`减去`FOR`中的间隔,即是`now()`和`now()`之前的90分钟之间的时间范围。 440 | 441 | 442 | 下面是2016年8月28日上午的日志输出: 443 | 444 | >在8:00`cq_advanced_every_for`执行时间范围`time>='6:30'AND time <'8:00'`的查询。 445 | `cq_advanced_every_for`向`average_passengers`写三个个点: 446 | > 447 | ``` 448 | name: average_passengers 449 | ------------------------ 450 | time mean 451 | 2016-08-28T06:30:00Z 3 452 | 2016-08-28T07:00:00Z 6.5 453 | 2016-08-28T07:30:00Z 7.5 454 | ``` 455 | >在9:00`cq_advanced_every_for`执行时间范围`time> ='7:30'AND time <'9:00'`的查询。 456 | `cq_advanced_every_for `向`average_passengers`写入三个点: 457 | > 458 | ``` 459 | name: average_passengers 460 | ------------------------ 461 | time mean 462 | 2016-08-28T07:30:00Z 7.5 463 | 2016-08-28T08:00:00Z 11.5 464 | 2016-08-28T08:30:00Z 16 465 | ``` 466 | 467 | 请注意,`cq_advanced_every_for`会计算每次间隔两次的结果。CQ在8:00和9:00计算7:30的平均值。 468 | 469 | 结果为: 470 | 471 | ``` 472 | > SELECT * FROM "average_passengers" 473 | name: average_passengers 474 | ------------------------ 475 | time mean 476 | 2016-08-28T06:30:00Z 3 477 | 2016-08-28T07:00:00Z 6.5 478 | 2016-08-28T07:30:00Z 7.5 479 | 2016-08-28T08:00:00Z 11.5 480 | 2016-08-28T08:30:00Z 16 481 | ``` 482 | 483 | ##### 例四:配置CQ的时间范围并填充空值 484 | 使用`FOR`间隔和`fill()`来更改不含数据的时间间隔值。请注意,至少有一个数据点必须在`fill()`运行的`FOR`间隔内。 如果没有数据落在`FOR`间隔内,则CQ不会将任何点写入目标measurement。 485 | 486 | ``` 487 | CREATE CONTINUOUS QUERY "cq_advanced_for_fill" ON "transportation" 488 | RESAMPLE FOR 2h 489 | BEGIN 490 | SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h) fill(1000) 491 | END 492 | ``` 493 | 494 | `cq_advanced_for_fill`从`bus_data`中计算`passengers`的1小时的平均值,并将结果存储在数据库`transportation`中的`average_passengers`中。并会在没有结果的时间间隔里写入值`1000`。 495 | 496 | `cq_advanced_for_fill`以1小时的间隔执行,间隔与`GROUP BY time()`间隔相同。每1小时,`cq_advanced_for_fill`运行一个查询,覆盖时间段为`now()`和`now()`减去`FOR`中的间隔,即是`now()`和`now()`之前的两小时之间的时间范围。 497 | 498 | 下面是2016年8月28日上午的日志输出: 499 | 500 | >在6:00`cq_advanced_for_fill`执行时间范围`time>='4:00'AND time <'6:00'`的查询。 501 | `cq_advanced_for_fill`向`average_passengers`不写入任何点,因为在那个时间范围`bus_data`没有数据: 502 | > 503 | >在7:00`cq_advanced_for_fill`执行时间范围`time>='5:00'AND time <'7:00'`的查询。 504 | `cq_advanced_for_fill`向`average_passengers`写入两个点: 505 | > 506 | ``` 507 | name: average_passengers 508 | ------------------------ 509 | time mean 510 | 2016-08-28T05:00:00Z 1000 <------ fill(1000) 511 | 2016-08-28T06:00:00Z 3 <------ 2和4的平均值 512 | ``` 513 | > [...] 514 | > 515 | >在11:00`cq_advanced_for_fill`执行时间范围`time> ='9:00'AND time <'11:00'`的查询。 516 | `cq_advanced_for_fill`向`average_passengers`写入两个点: 517 | > 518 | ``` 519 | name: average_passengers 520 | ------------------------ 521 | 2016-08-28T09:00:00Z 20 <------ 20的平均 522 | 2016-08-28T10:00:00Z 1000 <------ fill(1000) 523 | ``` 524 | > 525 | > 在12:00`cq_advanced_for_fill`执行时间范围`time>='10:00'AND time <'12:00'`的查询。 526 | `cq_advanced_for_fill`向`average_passengers`不写入任何点,因为在那个时间范围`bus_data`没有数据. 527 | 528 | 结果: 529 | 530 | ``` 531 | > SELECT * FROM "average_passengers" 532 | name: average_passengers 533 | ------------------------ 534 | time mean 535 | 2016-08-28T05:00:00Z 1000 536 | 2016-08-28T06:00:00Z 3 537 | 2016-08-28T07:00:00Z 7 538 | 2016-08-28T08:00:00Z 13.75 539 | 2016-08-28T09:00:00Z 20 540 | 2016-08-28T10:00:00Z 1000 541 | ``` 542 | 543 | >注意:如果前一个值在查询时间之外,则`fill(previous)`不会在时间间隔里填充数据。 544 | 545 | 546 | #### 高级语法的常见问题 547 | ##### 问题一:如果`EVERY`间隔大于`GROUP BY time()`的间隔 548 | 如果`EVERY`间隔大于`GROUP BY time()`间隔,则CQ以与`EVERY`间隔相同的间隔执行,并运行一个单个查询,该查询涵盖`now()`和`now()`减去`EVERY`间隔之间的时间范围(不是在`now()`和`now()`减去`GROUP BY time()`间隔之间)。 549 | 550 | 例如,如果`GROUP BY time()`间隔为5m,并且`EVERY`间隔为10m,则CQ每10分钟执行一次。每10分钟,CQ运行一个查询,覆盖`now()`和`now()`减去`EVERY`间隔之间的时间段,即`now()`到`now()`之前十分钟之间的时间范围。 551 | 552 | 此行为是故意的,并防止CQ在执行时间之间丢失数据。 553 | 554 | ##### 问题二:如果`FOR`间隔比执行的间隔少 555 | 如果`FOR`间隔比`GROUP BY time()`或者`EVERY`的间隔少,InfluxDB返回如下错误: 556 | 557 | ``` 558 | error parsing query: FOR duration must be >= GROUP BY time duration: must be a minimum of got 559 | ``` 560 | 561 | 为了避免在执行时间之间丢失数据,`FOR`间隔必须等于或大于`GROUP BY time()`或者`EVERY`间隔。 562 | 563 | 目前,这是预期的行为。GitHub上[Issue#6963](https://github.com/influxdata/influxdb/issues/6963)要求CQ支持数据覆盖的差距。 564 | 565 | ## CQ的管理 566 | 只有admin用户允许管理CQ。 567 | 568 | ### 列出CQ 569 | 列出InfluxDB实例上的所有CQ: 570 | 571 | ``` 572 | SHOW CONTINUOUS QUERIES 573 | ``` 574 | 575 | `SHOW CONTINUOUS QUERIES`按照database作分组。 576 | 577 | #### 例子 578 | 下面展示了`telegraf`和`mydb`的CQ: 579 | 580 | ``` 581 | > SHOW CONTINUOUS QUERIES 582 | name: _internal 583 | --------------- 584 | name query 585 | 586 | 587 | name: telegraf 588 | -------------- 589 | name query 590 | idle_hands CREATE CONTINUOUS QUERY idle_hands ON telegraf BEGIN SELECT min(usage_idle) INTO telegraf.autogen.min_hourly_cpu FROM telegraf.autogen.cpu GROUP BY time(1h) END 591 | feeling_used CREATE CONTINUOUS QUERY feeling_used ON telegraf BEGIN SELECT mean(used) INTO downsampled_telegraf.autogen.:MEASUREMENT FROM telegraf.autogen./.*/ GROUP BY time(1h) END 592 | 593 | 594 | name: downsampled_telegraf 595 | -------------------------- 596 | name query 597 | 598 | 599 | name: mydb 600 | ---------- 601 | name query 602 | vampire CREATE CONTINUOUS QUERY vampire ON mydb BEGIN SELECT count(dracula) INTO mydb.autogen.all_of_them FROM mydb.autogen.one GROUP BY time(5m) END 603 | ``` 604 | 605 | ### 删除CQ 606 | 从一个指定的database删除CQ: 607 | 608 | ``` 609 | DROP CONTINUOUS QUERY ON 610 | ``` 611 | 612 | `DROP CONTINUOUS QUERY`返回一个空的结果。 613 | 614 | #### 例子 615 | 从数据库`telegraf`中删除`idle_hands`这个CQ: 616 | 617 | ``` 618 | > DROP CONTINUOUS QUERY "idle_hands" ON "telegraf"` 619 | > 620 | ``` 621 | 622 | ### 修改CQ 623 | CQ一旦创建就不能修改了,你必须`DROP`再`CREATE`才行。 624 | 625 | ## CQ的使用场景 626 | ### 采样和数据保留 627 | 使用CQ与InfluxDB的保留策略(RP)来减轻存储问题。结合CQ和RP自动将高精度数据降低到较低的精度,并从数据库中移除可分配的高精度数据。 628 | 629 | ### 预先计算昂贵的查询 630 | 通过使用CQ预先计算昂贵的查询来缩短查询运行时间。使用CQ自动将普通查询的高精度数据下采样到较低的精度。较低精度数据的查询需要更少的资源并且返回更快。 631 | 632 | 提示:预先计算首选图形工具的查询,以加速图形和仪表板的展示。 633 | 634 | ### 替换HAVING子句 635 | InfluxQL不支持`HAVING`子句。通过创建CQ来聚合数据并查询CQ结果以达到应用`HAVING`子句相同的功能。 636 | 637 | >注意:InfluxDB提供了子查询也可以达到类似于`HAVING`相同的功能。 638 | 639 | #### 例子 640 | InfluxDB不接受使用`HAVING`子句的以下查询。该查询以30分钟间隔计算平均`bees`数,并请求大于20的平均值。 641 | 642 | ``` 643 | SELECT mean("bees") FROM "farm" GROUP BY time(30m) HAVING mean("bees") > 20 644 | ``` 645 | 646 | 要达到相同的结果: 647 | 648 | ##### 1. 创建一个CQ 649 | 此步骤执行以上查询的`mean("bees")`部分。因为这个步骤创建了CQ,所以只需要执行一次。 650 | 651 | 以下CQ自动以30分钟间隔计算`bees`的平均数,并将这些平均值写入measurement`aggregate_bees`中的`mean_bees`字段。 652 | 653 | ``` 654 | CREATE CONTINUOUS QUERY "bee_cq" ON "mydb" BEGIN SELECT mean("bees") AS "mean_bees" INTO "aggregate_bees" FROM "farm" GROUP BY time(30m) END 655 | ``` 656 | 657 | ##### 2. 查询CQ的结果 658 | 这一步要实现`HAVING mean("bees") > 20`部分的查询。 659 | 660 | 在`WHERE`子句中查询measurement`aggregate_bees`中的数据和大于20的`mean_bees`字段的请求值: 661 | 662 | ``` 663 | SELECT "mean_bees" FROM "aggregate_bees" WHERE "mean_bees" > 20 664 | ``` 665 | 666 | ### 替换嵌套函数 667 | 一些InfluxQL函数支持嵌套其他函数,大多数是不行的。如果函数不支持嵌套,可以使用CQ获得相同的功能来计算最内部的函数。然后简单地查询CQ结果来计算最外层的函数。 668 | 669 | >注意:InfluxQL支持也提供与嵌套函数相同功能的子查询。 670 | 671 | #### 例子 672 | 673 | InfluxDB不接受使用嵌套函数的以下查询。 该查询以30分钟间隔计算`bees`的非空值数量,并计算这些计数的平均值: 674 | 675 | ``` 676 | SELECT mean(count("bees")) FROM "farm" GROUP BY time(30m) 677 | ``` 678 | 679 | 为了得到结果: 680 | 681 | ##### 1. 创建一个CQ 682 | 此步骤执行上面的嵌套函数的`count(“bees”)`部分 因为这个步骤创建了一个CQ,所以只需要执行一次。 以下CQ自动以30分钟间隔计算`bees`的非空值数,并将这些计数写入`aggregate_bees`中的`count_bees`字段。 683 | 684 | ``` 685 | CREATE CONTINUOUS QUERY "bee_cq" ON "mydb" BEGIN SELECT count("bees") AS "count_bees" INTO "aggregate_bees" FROM "farm" GROUP BY time(30m) END 686 | ``` 687 | 688 | ##### 2. 查询CQ的结果 689 | 此步骤执行上面的嵌套函数的`mean([...])`部分。 在`aggregate_bees`中查询数据,以计算`count_bees`字段的平均值: 690 | 691 | ``` 692 | SELECT mean("count_bees") FROM "aggregate_bees" WHERE time >= AND time <= 693 | ``` 694 | -------------------------------------------------------------------------------- /Query_language/database_management.md: -------------------------------------------------------------------------------- 1 | # 数据库管理 2 | 3 | InfluxQL提供了一整套管理命令,包括数据管理和保留策略的管理。 4 | 5 | 下面的示例使用InfluxDB的命令行界面(CLI)。 您还可以使用HTTP API执行命令; 只需向`/query`发送GET请求,并将该命令包含在URL参数`q`中。 6 | 7 | >注意:如果启用了身份验证,只有管理员可以执行本页上列出的大部分命令。 8 | 9 | ## 数据管理 10 | ### 创建数据库 11 | #### 语法 12 | ``` 13 | CREATE DATABASE [WITH [DURATION ] [REPLICATION ] [SHARD DURATION ] [NAME ]] 14 | ``` 15 | 16 | #### 语法描述 17 | CREATE DATABASE需要一个数据库名称。 18 | 19 | `WITH`,`DURATION`,`REPLICATION`,`SHARD DURATION`和`NAME`子句是可选的用来创建与数据库相关联的单个保留策略。如果您没有在`WITH`之后指定其中一个子句,将默认为`autogen`保留策略。创建的保留策略将自动用作数据库的默认保留策略。 20 | 21 | 一个成功的`CREATE DATABASE`查询返回一个空的结果。如果您尝试创建已存在的数据库,InfluxDB什么都不做,也不会返回错误。 22 | 23 | #### 例子 24 | ##### 例一:创建数据库 25 | ``` 26 | > CREATE DATABASE "NOAA_water_database" 27 | > 28 | ``` 29 | 该语句创建了一个叫做`NOAA_water_database`的数据库,默认InfluxDB也会创建`autogen`保留策略,并和数据库`NOAA_water_database`关联起来。 30 | 31 | ##### 例二:创建一个有特定保留策略的数据库 32 | ``` 33 | > CREATE DATABASE "NOAA_water_database" WITH DURATION 3d REPLICATION 1 SHARD DURATION 1h NAME "liquid" 34 | > 35 | ``` 36 | 该语句创建了一个叫做`NOAA_water_database`的数据库,并且创建了`liquid`作为数据库的默认保留策略,其持续时间为3天,副本数是1,shard group的持续时间为一个小时。 37 | 38 | ### 删除数据库 39 | `DROP DATABASE`从指定数据库删除所有的数据,以及measurement,series,continuous queries, 和retention policies。语法为: 40 | 41 | ``` 42 | DROP DATABASE 43 | ``` 44 | 45 | 一个成功的`DROP DATABASE`查询返回一个空的结果。如果您尝试删除不存在的数据库,InfluxDB什么都不做,也不会返回错误。 46 | 47 | ### 用DROP从索引中删除series 48 | `DROP SERIES`删除一个数据库里的一个series的所有数据,并且从索引中删除series。 49 | 50 | >`DROP SERIES`不支持`WHERE`中带时间间隔。 51 | 52 | 该查询采用以下形式,您必须指定`FROM`子句或`WHERE`子句: 53 | 54 | ``` 55 | DROP SERIES FROM WHERE ='' 56 | ``` 57 | 58 | 从单个measurement删除所有series: 59 | 60 | ``` 61 | > DROP SERIES FROM "h2o_feet" 62 | ``` 63 | 64 | 从单个measurement删除指定tag的series: 65 | 66 | ``` 67 | > DROP SERIES FROM "h2o_feet" WHERE "location" = 'santa_monica' 68 | ``` 69 | 70 | 从数据库删除有指定tag的所有measurement中的所有数据: 71 | 72 | ``` 73 | > DROP SERIES WHERE "location" = 'santa_monica' 74 | ``` 75 | 76 | ### 用DELETE删除series 77 | `DELETE`删除数据库中的measurement中的所有点。与`DROP SERIES`不同,它不会从索引中删除series,并且它支持`WHERE`子句中的时间间隔。 78 | 79 | 该查询采用以下格式,必须包含`FROM`子句或`WHERE`子句,或两者都有: 80 | 81 | ``` 82 | DELETE FROM WHERE [=''] | [