InfluxDB

2016-09-25 database linux

InfluxDB 是一个开源分布式时序、事件和指标数据库,使用 Go 语言编写,无需外部依赖,其设计目标是实现分布式和水平伸缩扩展。

InfluxData 提供了 TICK 一套解决方案,不过使用比较多的是 InfluxDB,在此就介绍下 InfluxDB 以及 Telegraf 。

influxdb

简介

在对时序数据进行存储时,常见的有多种格式:A) 使用文件 (如: RRD, Whisper);B) 使用 LSM 树 (如: LevelDB, RocksDB, Cassandra);C) 使用 B-Tree 排序和 k/v 存储 (如: BoltDB, LMDB) 。

如下,就是 InfluxDATA 提供的一整套监控解决方案,包括了数据采集 (Telegraf)、数据存储 (InfluxDB)、数据展示 (Chronograf) 以及报警 (Kapacitor) 。

TICK

而实际上,使用比较多的是 InfluxDB ,这是一个时序数据库,关于时序数据库的排名,可以直接在 db-engines.com 查看,InfluxDB 的活跃度基本排在第一。

除了上述 InfluxDATA 提供的解决方案之外,通常还可以使用如下的方案。

采集数据 (collectd) ==>>==>> 存储数据 (InfluxDB) ==>>==>> 显示数据 (Grafana)

0.8.4 版本之前只能通过 influxdb-collectd-proxy 采集 collectd 上报的数据,之后 InfluxDB 自动提供了接口;当然,默认是不开启的,需要在配置文件中设置。

在此,还是重点介绍下 InfluxDB 。

特性

简单列举下 InfluxDB 所支持的特性:

  • 支持 Regular Timeseries 以及 Irregular Timeseries,前者是指时间间隔固定,后者指不固定,例如报警、入侵事件等;
  • 可以将秒级监控在后台转换为分钟级,减小存储空间 (Continuous Queries);
  • 采用 Schemaless ,列存储,压缩率高,可以存储任意数量的列;
  • 提供 min, max, sum, count, mean 等聚合函数;
  • 使用类 SQL 语句;
  • Built-in Explorer 自带管理工具,默认不打开,需要在配置文件中配置;
  • Native HTTP API,采用内置 HTTP 服务 (Protobuf API 暂时不提供)。

常用概念

简单列举下常见的概念。

Database

数据库,可以创建多个,不同数据库中的数据文件存放在磁盘上的不同目录。

Measurement

数据库中的表,例如 memory 记录了内存相关统计,其中包括了 used、cached、free 等。

Point

表里的一行数据,由 A) 时间戳 (timestamp,每条记录的时间,数据库的主索引,会自动生成);B) 数据 (field,记录的 Key/Value 例如温度、湿度);C) 标签 (tags,有索引如地区、海拔)组成。

Tag/tag key/tag value

有点不太好解释,可以理解为标签,或者二级索引,例如采集机器的 CPU 信息的时候,可以设置两个 tag 分别是机器 IP 以及第几个 CPU,在查询的时候放在 where 条件中,从而不需要遍厉整个表,这是一个 map[stirng]string 结构。

Fields

也就是实际记录的数据值,是 map[string]interface{} 类型,类似于 C 语言中的 void * ,这里的 interface{} 可以是 int、int32、int64、float32、float64,也就是真正需要显示或者计算的值,例如 CPU 的 sys, user, iowait 等。

Retention Policy

存储策略,InfluxDB 会自动清理数据,可以设置数据保留的时间,默认会创建存储策略 autogen (保留时间为永久),之后用户可以自己设置,例如保留最近 30 天的数据。

                       +----------+
                   +-->|  series  |
                   |   +----------+
+-------------+    |   +----------+
| measurement | ---+-->|  series  |
+-------------+    |   +----------+
                   |   +----------+
                   +-->|  series  |
                       +----------+

安装

实际上,编译好的二进制程序,可以直接从官网 www.influxdata.com/downloads/ 上下载,例如,在 CentOS 中,可以通过如下方式安装,安装后数据默认保存在 /var/lib/influxdb 目录下。

----- 下载二进制安装包
$ wget https://dl.influxdata.com/influxdb/releases/influxdb-1.1.1.x86_64.rpm
----- 查看二进制包的内容
$ rpm -qpl influxdb-1.1.1.x86_64.rpm
----- 解压二进制包
$ rpm2cpio influxdb-1.1.1.x86_64.rpm | cpio -div
----- 安装二进制包
# rpm -ivh influxdb-1.1.1.x86_64.rpm
----- 启动服务,可以查看/usr/lib/systemd/system/influxdb.service文件
# systemctl start influxdb

安装完之后,可以看到如下的可执行文件。

  • influxd,服务器,可以直接通过该命令启动;
  • influx,InfluxDB 命令行客户端,可链接服务器,执行一些常见的命令;
  • influx_inspect,用于查看磁盘 shards 上的详细信息;
  • influx_stress,压力测试工具;
  • influx_tsm,数据库转换工具,可以将数据库从 b1 或 bz1 格式转换为 tsm1 格式。

源码编译

当然,主要介绍下 influxdb 和 telegraf 的源码编译。

build.py

在源码中,有一个编译脚本 build.py,可以通过该脚本进行编译、打包等操作。

实际上,在 build.py 脚本中,会通过 git 检查相应的版本 (详见 get_current_XXX 类函数),所以需要保证这是一个 git 版本库,也就是说,如果通过该工具编译,需要通过 git clone 下载源码。

另外,代码库的依赖是通过 Go Dependancy Manager, GDM 管理的,当然如果没有安装,则会自动安装;然后下载依赖的代码库;最后,会直接调用 go install 安装。

TIP: 如果无法直接连接到网络,可以将 get_current_XXX()、go_get()、local_changes() 返回正常的值即可,例如 get_current_commit() 返回 “foobar” ,go_get() 返回 true 等等;当然,此时,依赖的代码库需要手动下载 (执行go install时会显示依赖包)。

编译后的程序,会最终安装到 $GOPATH/bin/ 目录下;也可以打包成 rpm 包,不过没仔细研究,后面再看看。

influxdb

对于 InfluxDB 可以通过如下方式安装。

----- 1. 下载相关的分支
$ git clone -b v1.1.1 https://github.com/influxdata/influxdb.git .
----- 2. 直接进行编译,如果并非通过git下载源码,需要如上修改build.py文件
$ ./build.py
----- 3. 直接复制到$GOPATH/bin目录下即可
$ cp build/* $GOPATH/bin

telegraf

对于 telegraf 可以直接使用 make 安装,对于其中一些依赖库,如 golang.org/x/crypto ,可能会导致无法下载,可以直接从 github 上下载,然后删除 Godeps 相关依赖。

另外,通过上述方法下载时,需要使用 git clone 下载,否则会由于缺少 .git 目录导致报错;这也意味着,如果可以确保相关的依赖都已经下载之后,直接将 build.py 脚本中的 go_get() 注释掉即可,这样就不会通过 gdm 下载依赖包了。

$ go get github.com/influxdata/telegraf
$ cd $GOPATH/src/github.com/influxdata/telegraf
$ make

如官方所述,该工具是插件式的,这也就导致其在编译时,会依赖很多的插件,如果只需要部分插件,可以在 plugins 目录下,修改相应分类的 all/all.go 文件,将不需要的注释掉即可。

其实,主要修改 plubins/{inputs,outputs}/all/all.go 即可。

tips

需要注意的是,通过 gdm 安装依赖时,可能会由于墙 (你懂得) 部分包无法下载,但是现象是 hang 住 :-( 所以,可以从 github 上手动下载,一般都会有镜像的。

 配置文件

默认使用 /etc/influxdb/influxdb.conf ,默认会使用如下的端口:

  • 8083: Web-Admin管理服务的端口,如果是本地可以直接通过 http://localhost:8083 打开,不过默认没有开启,需要在配置文件中打开;
  • 8086: HTTP-API的端口,用于接收请求和发送数据;
  • 8088: 集群端口,用于 InfluxDB 集群通讯使用,不过 0.11.1 版本之后就不再提供集群化的解决方案了,只有企业版才提供该功能;

简单列举下常见的配置。

# 管理面需要打开如下配置
[admin]
enabled = true
bind-address = ":8083"

# 如果不指定,则会通过os.hostname()通过系统获取,可能会报错
hostname = '192.168.1.23'
# 默认每隔24小时会向usage.influxdata.com发送一些统计数据,可以关闭掉
reporting-disabled = true

Python访问

通过 Python 访问 InfluxDB 需要安装 InfluxDB Python,然后通过如下方式访问即可。

$ python
>>> from influxdb import InfluxDBClient
>>> json_body = [
    {
        "measurement": "cpu_load_short",
        "tags": {
            "host": "server01",
            "region": "us-west"
        },
        "time": "2009-11-10T23:00:00Z",
        "fields": {
            "value": 0.64
        }
    }
]
>>> client = InfluxDBClient('localhost', 8086, 'root', 'root', 'example')
>>> client.create_database('example')
>>> client.write_points(json_body)
>>> result = client.query('select value from cpu_load_short;')
>>> print("Result: {0}".format(result))

常用操作

在 InfluxDB 中,写入数据采用行格式,可以粗略的将要存入的一条数据看作一个虚拟的 key 和其对应的 value (field value),格式如下:

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

cpu,host=serverA,region=west value=0.64   服务器默认时间
temperature,zipcode=384250,province=zhejiang value=75,humidity=20 1434067467000000000

常见操作列举如下,可以通过 -precision 参数指定时间格式以及精度,例如 rfc3339 。

----- 写入数据
$ curl -i -XPOST 'http://localhost:8086/write?db=testDB'
    --data-binary 'weather,altitude=1000,area=北 temperature=11,humidity=-4'
$ curl -i -XPOST 'http://localhost:8086/write?db=testDB&precision=s'
    --data-binary 'weather,altitude=1000,area=北 temperature=11,humidity=-4'
influx> INSERT weather,altitude=1000,area=北 temperature=11,humidity=-4;

----- 查询
$ curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=mydb" -precision 'rfc3339'
    --data-urlencode "q=SELECT * FROM weather ORDER BY time DESC LIMIT 3"
$ curl -G 'http://localhost:8086/query?u=readonly&p=password&pretty=true' --data-urlencode "db=mydb"
    --data-urlencode "q=SELECT * FROM weather ORDER BY time DESC LIMIT 3"

----- 设置过期策略
$ curl -G http://localhost:8086/query --data-urlencode
    "q=CREATE RETENTION POLICY bar ON foo DURATION 300d REPLICATION 3 DEFAULT"

另外,支持 JSON 格式写入、GZIP 压缩数据插入及查询,详细可以参考源码中的 tests 目录。

运维操作

基本的数据保存目录如下。

.
├── data
│   ├── _internal
│   │   └── monitor
│   │       ├── 16   Shard-ID
│   │       │   └── 000000004-000000003.tsm
│   │       └── 3
│   └── telegraf
│       └── autogen  存储策略
│           ├── 12
│           │   └── 000000132-000000002.tsm
│           └── 7
│               └── 000000003-000000002.tsm
├── meta
│   └── meta.db    元数据
└── wal
    ├── _internal
    │   └── monitor
    │       ├── 16
    │       │   └── _00015.wal
    │       └── 3
    │           ├── _00001.wal
    │           ├── _00002.wal
    │           ├── _00003.wal
    │           └── _00006.wal
    └── telegraf
        └── autogen
            ├── 12
            │   └── _00395.wal
            └── 7
                └── _00010.wal

系统监控

可以查看 官方文档,关于 GoLang 的内部运行状态,可以参考 https://golang.org/pkg/runtime

----- InfluxDB本身的监控统计数据,保存在内存中,重启后会丢失
SHOW STATS FOR <'module'>

----- 包括编译信息、主机名、系统配置、启动时间、内存使用率、GoLang运行环境信息
SHOW DIAGNOSTICS FOR <'module'>

----- 内部监控进程保存的数据,包含了各种监控的历史数据
_internal

元数据查看

仅简单列举一下常见的命令,详细可以查看 官方文档

SHOW SERIES;
SHOW SERIES ON telegraf FROM mysql;

SHOW FIELD KEYS;
SHOW FIELD KEYS ON telegraf FROM cpu;

SHOW MEASUREMENTS

用户权限管理

InfluxDB 的权限设置比较简单,只有读、写、ALL 三种,详细参考 官方文档 。默认不开启用户认证,需要修改配置文件:

[http]
auth-enabled = true

常见命令如下:

----- 授权
GRANT [READ,WRITE,ALL] ON <database_name> TO <username>
GRANT ALL PRIVILEGES TO "username"

----- 撤销权限
REVOKE [READ,WRITE,ALL] ON <database_name> FROM <username>
REVOKE ALL PRIVILEGES FROM "username"

----- 查看权限
SHOW GRANTS FOR <user_name>

----- 显示用户
SHOW USERS

----- 创建用户
CREATE USER "readonly" WITH PASSWORD 'password'

----- 创建管理员权限的用户
CREATE USER "readonly" WITH PASSWORD 'password' WITH ALL PRIVILEGES

----- 删除用户
DROP USER "readonly"

----- 修改密码
SET PASSWORD FOR <username> = '<password>'

备份恢复

只支持全量备份,不支持增量,包括了元数据以及增量数据的备份,可以参考 官方文档

----- 元数据备份
$ influxd backup <path-to-backup>

----- 数据备份
$ influxd backup -database <mydatabase> <path-to-backup>
$ influxd backup -database telegraf -retention autogen -since 2016-02-01T00:00:00Z /tmp/backup
$ influxd backup -database mydatabase -host 10.0.0.1:8088 /tmp/remote-backup

----- 恢复
$ influxd restore -metadir /var/lib/influxdb/meta /tmp/backup
$ influxd restore -database telegraf -datadir /var/lib/influxdb/data /tmp/backup

数据保存策略

也就是 Retention Policies,可以设置保存的时间,例如保存 30 天。

----- 查询
SHOW RETENTION POLICIES ON "database_name";

----- 新建
CREATE RETENTION POLICY "rp_name" ON "db_name" DURATION 30d REPLICATION 1 DEFAULT;

----- 修改
ALTER RETENTION POLICY "rp_name" ON db_name DURATION 3w DEFAULT;

----- 删除
DROP RETENTION POLICY "rp_name" ON "db_name";

连续查询

也就是 Continuous Queries,当数据超过保存策略里指定的时间之后,就会被删除;可以通过连续查询把原来的秒级数据,保存为分钟级或者小时级的数据,从而减小数据的占用空间。

----- 查看
SHOW CONTINUOUS QUERIES;

----- 创建
CREATE CONTINUOUS QUERY cq-name ON db-name BEGIN
    SELECT mean(tbl-name) INTO newtbl-name FROM tbl-name GROUP BY time(30m) END;

----- 删除
DROP CONTINUOUS QUERY <cq-name> ON <db-name>;

其它

1. 获取最近更新数据,并转换为当前时间

select threads_running from mysql order by time desc limit 1;
date -d @`echo 1483441750000000000 | awk '{print substr($0,1,10)}'` +"%Y-%m-%d %H:%M:%S"

2. 检查系统是否存活

$ curl -sl -I localhost:8086/ping

3. 常用操作

----- 简单查询
SELECT * FROM weather ORDER BY time DESC LIMIT 3;

----- 指定时间范围,时间格式也可以为'2017-01-03 00:00:00'
SELECT usage_idle FROM cpu WHERE time >= '2017-01-03T12:40:38.708Z' AND time <= '2017-01-03T12:40:50.708Z';

----- 最近40min内的数据
SELECT * FROM mysql WHERE time >= now() - 40m;

----- 最近5分钟的秒级差值
SELECT derivative("queries", 1s) AS "queries" from "mysql" where time > now() - 5m;

----- 最近5min的秒级写入
$ influx -database '_internal' -precision 'rfc3339'
      -execute 'select derivative(pointReq, 1s) from "write" where time > now() - 5m'

----- 也可以通过日志查看
$ grep 'POST' /var/log/influxdb/influxd.log | awk '{ print $10 }' | sort | uniq -c
$ journalctl -u influxdb.service | awk '/POST/ { print $10 }' | sort | uniq -c

存储引擎

Bolt 是一个 Go 语言编写的嵌入式 KV 数据库,提供了一个简单可靠的方式做数据持久化,按照作者在 Github BoltDB 中的介绍:

Bolt is a pure Go key/value store inspired by Howard Chu's LMDB project. The goal
of the project is to provide a simple, fast, and reliable database for projects
that don't require a full database server such as Postgres or MySQL.

与 LevelDB 有所区别,BoltDB 支持完全可序列化的 ACID 事务;而且,提供稳定的 API 接口,而非类似 SQLite 的 SQL 接口;从而也就意味着它更加方便地整合到其它系统。

安装、使用

在设置好 golang 的环境变量之后,可以很简单的通过 go get 获取源码并安装到 $GOPATH/bin 目录下,其命令如下:

$ go get github.com/boltdb/bolt/...

参考