分类目录归档:系统

InfluxDB使用笔记

 

概述

InfluxDB是 InfluxData 公司发布的一款开源时序数据库产品。

关于时序数据库,除了常用的ElasticSearch之外,InfluxDB也是一个选择。

InfluxDB 使用 go 语言编写。个人认为几个外在的优点在于:

  1. 无特殊依赖,几乎开箱即用(如ES需要Java);
  2. 自带HTTP管理界面,免插件配置(如ES的kopf或者head);
  3. 自带数据过期功能;
  4. 类SQL查询语句(再提ES,查询使用自己的DSL,虽然也可以通过sql插件来使用类SQL进行查询);
  5. 自带权限管理,精细到“表”级别;

这些好处官网都有提及。

关键概念

手册中对这些名词有了详细的定义,这里稍微提及一下。

time

Time 在 InfluxDB 中的每一行数据中都会存在。

Time 即数据生成时的时间戳。

类比更为熟悉的 MySQL 来说,InfluxDB 中的 Time 几乎可以看做是主键的代名词了。

field

Field 在 InfluxDB 中是必须的数据的组成部分。

Field 未被索引。这意味着如果查询field的话将会扫描所有数据,找出匹配项;手册上也建议不要在field中存储将会频繁查询的数据(存储区分度更高的数据)。

类比 MySQL,Field 可以看做没有索引的列。

tag

Tag 在 InfluxDB 中是可选的数据组成部分。

不同于 Filed,Tag 的数据会被索引。

类比 MySQL,Tag就是有索引的列。

measurement

InfluxDB 是时序数据库,时间数据 time 与 Tag 以及 Field 组合成了 Measurement。

类比 MySQL,Measurement可以看做的是表。

retention policy

应用程序记录日志的情况下,如果没有关注,很有可能会出现打爆硬盘的情况出现。运维同学一般会在服务器上部署自动清理脚本。

在InfluxDB中,合理的设置了 Measurement 的 Retention Policy 的情况下,无需太过担心磁盘被打爆的情况。

Retention Policy 可以看做是数据清理策略。基础应用个人认为应该关注如下的一些参数:

  • DURATION,即保存时间,有 m h d w INF几种,即分,小时,天,周以及无限(Infinity);
  • REPLICATION,即副本数,即会有多少份副本保留在集群之中。

point

Point 即同一时间戳产生的数据的集合。

series

Series 表示Measurement、Retention Policy、Tag都相同(tag的名称与值)的一组数据,Field不在考虑衡量范围之内。

基本操作

基本操作简单提及数据的 CURD 以及数据库管理方面的一些使用方式。

CURD

CREATE

在已创建数据库的前提下,新增数据,可以通过两种基本的方式进行数据的写入:

  • CLI
  • InfluxDB HTTP API

CLI

CLI 自然与 MySQL 类似,通过 InfluxDB 提供的 CLI 工具,使用类 SQL 语句进行写入。

但是 CLI 毕竟不是使用 InfluxDB 作为后端存储的好方式,InfluxDB 也提供了非常方便的HTTP API 供开发者们使用。

InfluxDB 的特点是无结构的,即文档中提到的 schemaless,可以随时的动态增添数据域和表,所以使用时直接写入,无需考虑关系型数据库中类似建表等过程。

不过,CLI 虽然不能做到随时随地的的使用,但是类 SQL 语句还是在特定场景下还是有应用空间的(例如使用默认的Web管理端)。

CLI 写入数据时,语法相当简单,只需要使用:INSERT 数据 这样的语句即可。但是数据部分有InfluxDB自己的一些协议,目前在使用的规则叫做 Line Protocol。

Line Protocol

文档中已有详细描述,这里总结一下,简单来说,个人认为可以关注如下的特点:

  • 第一个字段是表名
  • 如果有tag,表名之后使用英文逗号分隔,以k=v的方式逐个列出
  • field在前两部分之后,用空格分隔开,之后所有的field,也使用英文逗号分隔,以k=v的方式逐个列出
  • 如果要指定时间戳,那么在field之后,通过空格分隔,将纳秒级别的时间戳写入
  • 在 tag 的键,值,以及 field 的键中包含, 、= 以及空格的,需要进行转义(变为\, \= \),field 的值可以通过 英文双引号 包裹起来(但是双引号决定了这个值必然是一个字符串)
  • 数据分为 string int64 float64 boolean 几种类型
  • string 最大存储的长度为64KB
  • float64 是默认的的类型,如果整数值要存成整数,需要在数字后通过字母 i 标明

InfluxDB HTTP API

InfluxDB 启动后,会默认监听 8086 端口,在这一端口上可以通过 HTTP POST 的方式,请求 /write ,写入数据。

写入方式手册已很清楚,即将 Line Protocol 格式的的数据提交到 InfluxDB 之上。

需要注意的是,InfluxDB 在通过HTTP方式操作时,需要注意下HTTP的状态码,尤其要注意204这一状态码,InfluxDB在返回这一状态码时认为请求合理但是并未完成,当返回这一个数值是需要注意HTTP的body段中附加的错误信息。至于4xx与5xx则是真的存在错误的情况。

时序相关

既然是时序数据库,那么时间作为重要的维度需要单独一提。

通过 Line Protocol 写入数据时,如果没有指定时间,将会根据系统时间指定时间,所以手册中提到:

If you do not specify a timestamp for your data point InfluxDB uses the server’s local nanosecond timestamp in UTC.

这个和 ES 的默认行为不太相同,所以这里需要注意。

如果要人工指定时间,需要按照 RFC3389 里提及的格式指定,即指定一个ns级别的时间戳,形如1465839830100400200。

RETRIEVE

与 CREATE 这一动作相同,数据的获取同样可以通过在 CLI 中执行InfluxQL(即InfluxDB中定义的类 SQL 语言),或者通过 HTTP API 提交查询语句的方式进行。通过 HTTP API 访问的话,InfluxDB会返回JSON格式的数据。

InfluxDB使用类 SQL 语言进行查询,确实是降低了使用的门槛,类似 SQL 的 SELECT GROUP BY LIMIT ORDER BY 操作的用法参见手册。

GROUP BY

值得一提的是,作为时序数据库,InfluxDB在查询上有一些时间相关的操作,例如 GROUP BY 操作可以按照时间戳进行聚合,获得每个时间片级别上的聚合数据。即通过 GROUP BY time(interval) 方法进行聚合,interval 即支持的时间片,支持的范围有:

时间片单位 范围
u 微秒
ms 毫秒
s 秒
m 分钟
h 小时
d 天
w 周

比如 time(3d) 表示按照3天作为周期进行聚合。

同时 fill() 方法也是一个有意思的功能,使用 GROUP BY 之后,如果某个聚合的结果内没有值,可以通过 fill() 设定为自己需要的值。更详细的用法参见手册。

INTO

如果说上述的的一些操作看起来和平常使用的关系型数据库没有特别大的区别的话,我想从 INTO 开始,InfluxQL就体现出时序数据库的一些特点了。

比如机器性能数据的采集,数据点多了之后,很可能我们期望能够看到的不是单一时间点上的数据,而是机器阶段性的表现和趋势,这样的数据自然可以通过聚合具体的采集数据获得,但是为什么不直接读取已经聚合完成的数据并展现呢?重复的计算是对机器性能的巨大浪费。

通常情况下,我们可能需要编写程序完成这样的工作,但是在InfluxDB中,可以通过内置的 INTO 语句来完成,无需额外的工作。

结合手册中的例子:

即在2015-08-18T00:00:00Z到2015-08-18T00:30:00Z的时间范围内,将每12分钟在santa_monica区域的水位的平均值存入average表中。

如是,如果要了解平均值,无需重复计算原始数值。

对于实际业务来说,统计接口PV/UV的场景很适合使用这一个子句,因为阶段统计中,并不关心具体的访问用户,而是期望了解趋势(对于UV的定义需要结合实际的业务场景)。

LIMIT & SLIMIT

LIMIT 限制的是数据的行数,而 SLIMIT 限制的则是返回的 Series 的个数,如果二者都要限制,则先设定 LIMIT,之后再设定 SLIMIT。

OFFSET & SOFFSET

分页是查询数据的一个基本方式,InfluxQL中通过 OFFSET 以及 SOFFSET 进行。

类似 LIMIT & SLIMIT, OFFSET 是针对数据行的翻页,SOFFSET 是针对 Series 的翻页。

时序相关

时序数据库,自然查询的数据经常会与时间有关。前面提及的时间单位,在选定时间范围时,可以通过组合简化时间区间的确定。

例如选出当前时间前3天到5小时前的数据,那么只需要指定条件为time >= now() - 3d AND time < now() - 5h即可。

如果你愿意,也可以与 RFC3339 格式的时间做对比。

UPDATE & DELETE

InfluxDB不存在常规意义上的 UPDATE 和 DELETE 这些动作!需要注意!

InfluxDB的设计初衷是为了记录时序相关的数据,这些数据被认为是不常变的,并且是仅仅有一次写入操作的(瞬时应当是唯一的)。

综上,InfluxDB期望通过牺牲了数据的灵活性,换取了更好的写入与查询性能。

实例:grahios使用InfluxDB作为后端

grahios 是一个将 Nagios 性能数据,使用不同的后端数据收集工具(or 时序数据库)进行收集的工具。在之前的笔记 使用Grafana+InfluxDB展示Nagios监控数据 之中有所提及。

graphios 使用 InfluxDB 作为存储后端,首先完成的步骤,是将 PERFDATA 解析,之后按照 Line Protocol 拼装,发送到后端。

由于 InfluxDB 是 Schemaless 的,所以 graphios 无需进行提前建表这一操作,直接发送数据即记录。

比较让我关心的是 Line Protocol 的运用,参见提交 sha 值为 02098f 的 graphios_backends.p 的文件的667行的 format_metric 方法:

生成Measurement

使用了 Line Protocol 的情况下,输入变量path将会作为 Measurement的名称,这里的 path 即 Nagios 中的 HOSTCHECKCOMMAND 或者 SERVICEDESC Macro 的值,即检测服务的名称。例如磁盘就是 Disk。

生成Tags

所有的检测数据都会作为 tags 存在,目的应是便于查询。检测数据的格式形如:

DISK OK – free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968

/ 15272 MB (77%);

/boot 68 MB (69%);

/home 69357 MB (27%);

/var/log 819 MB (84%); | /boot=68MB;88;93;0;98

/home=69357MB;253404;253409;0;253414

/var/log=818MB;970;975;0;980

橙色部分是 PERFDATA,将会被解析成Tags所需的格式:

/=2643MB,/boot=68MB,/home=69357MB,/var/log=818MB

由于 Nagios 中 / 一般被设定为需要转义的字符,所以,写入数据库是,可能会被转换为:

_=2643MB,_boot=68MB,_home=69357MB,_var_log=818MB

至于比如 PERFDATA 中的 WARNING CRITICAL 等标识去哪里了,可以看到提交 sha 值为8aa93b 的 graphios.py 文件的358行的 process_log方法,文件387行开始:

说明了实际上原始日志处理过后,只会有等号后的第一个数据存在。

生成Fileds

由于 Fileds 是InfluxDB数据不可缺少的一部分,但是实际上,由于没有索引的原因,查询时的成本比较大,所以 graphios 把 PERFDATA 的value作为数据的一个field value记录,个人任务因为这个value并没有足够的细节,具有足够的细节的数据已都做为tag存在。

生成时间戳

由于需要ns级别的时间戳,所以需要在检测的时间戳上乘以特定倍数即可。

查询

查询的工作,则交给Grafana这类专业的数据展现工具完成。

小结

以上是InfluxDB的基础使用笔记,数据库的诸如认证,部署,集群,以及使用上的如降采样(Downsampling)预计将会在后续笔记中提及。

使用Grafana+InfluxDB展示Nagios监控数据

 

概述

Nagios作为监控软件来说已经让人基本满意了,但是个人在使用中感觉还存在部分问题:

  1. 不能绘图

可能有同学会说不是有PNP4Nagios这样的软件吗?这个软件Nagios并没有默认携带,需要自己手动安装配置。

另外PHP4Nagios虽然已经能满足显示上的需求,但是绘图效果比较古老(图片来自网络,侵删):

PNP4Nagios sample

并且不能对某些数据进行对比(比如多台机器的负载情况在同一个图表中显示)。

  1. 无法查看历史数据

Nagios只能看到“现在”的数据,无法回顾历史以及查看趋势。

譬如,如果使用现有的Nagios,想要回顾周日半夜任务对系统的消耗时,就会比较抓瞎了。

方案

绘图

先说绘图。

绘图作为一个附加的功能,可以考虑现有的一些优秀的数据展现软件,譬如Kibana和Grafana。

个人认为,Kibana更适合展现日志计数类型的数据,并且本身没有权限控制等功能,这一点比较麻烦,虽然可以通过第三方插件或者HTTP Basic Auth来解决,但是总是增加了维护成本。

相比之下,Grafana带有权限控制,能支持相当多的时序数据库,从graphite、opentsdb、influxdb,当然也有ES。多条曲线同时展示时还可以看到具体数值,显示效果也相当不错。

Grafana sample from it's website

并且,Grafana在4.0后将会具有告警功能,玩法会变得更多。

最终选择Grafana作为展示端。

数据内容

提一下数据内容。

在这个方案中,我们展现的数据,实际上是Nagios插件产生的Performance Data(或者叫PERFDATA),如果自行编写的插件没有按照 PERFDATA 的格式输出信息,是不会被收集到InfluxDB中的。如果有自行编写业务监控插件,除了基本的返回码和错误信息之外,要考虑按照标准输出相关的信息,以便收集到InfluxDB中。

Nagios 3的插件多行输出格式为:

TEXT OUTPUT | OPTIONAL PERFDATA

LONG TEXT LINE 1

LONG TEXT LINE 2

…

LONG TEXT LINE N | PERFDATA LINE 2

PERFDATA LINE 3

…

PERFDATA LINE N

如磁盘信息的收集,单行模式很好理解,通过 | 分隔输出信息以及 PERFDATA;多行模式的话,引用官网的例子:

DISK OK – free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968

/ 15272 MB (77%);

/boot 68 MB (69%);

/home 69357 MB (27%);

/var/log 819 MB (84%); | /boot=68MB;88;93;0;98

/home=69357MB;253404;253409;0;253414

/var/log=818MB;970;975;0;980

第一行仍然可以按照单行模式进行理解(红色部分是输出信息,橙色部分是 PERFDATA),从第二行开始,每行一个输出信息,最后将剩余的 PERFDATA 紧接着输出信息的最后一行,通过 | 分隔,逐行输出。

每项 PERFDATA 格式为:

引用上述例子的数据 /=2643MB;5948;5958;0;5968,可以看到对应关系为:

label /
value 263MB
warn 5498
crit 5958
min 0
max 5968

UOM 表示 unit of measurement,即单位,可以是:

  • 不设定(即数字)
  • 秒s(或者ms或us)
  • 百分数%
  • 字节B(或者KB, MB, TB)

详情可以参阅 Nagios Plugin Development Guidelines 以及 Nagios Plugin API。

数据落地

只有Grafana是不能完成期望的工作的,Grafana只是展现工具,需要有数据源才能展现。

目前主力使用的时序数据库是ES,但是可以看到Nagios官方网站上关于绘图这一主题推荐的插件中没有看到写入到ES中的插件(ES倒是可以把输出作为监控信息交给Nagios,参见)。

查阅资料,graphite性能可能存在问题,opentsdb需要有专业的运维同学维护(毕竟是Hadoop衍生产品),InfluxDB兼顾了性能和运维成本,考虑使用。

值得一提的是,InfluxDB提供了Web管理端,查询语句上类似SQL,便捷程度让人满意。

数据收集

落地方式确定之后,需要考虑如何将Nagios收集的诸如load、CPU、内存使用等信息存入InfluxDB了。

graphios可以相当便捷的完成这一工作。这是一个将Nagios perf data写入到InfluxDB中的工具。配置也相当便捷,基本上按照README即可完成。

Nagflux看起来也是不错,然而问题在于这个适用于4.x版本的Nagios,在不打算升级Nagios的情况下,只能放弃。

但是,凡事总有例外,使用软件的特定组合的情况下,会出现一些问题。

数据解析异常

graphios在Nagios官网上声称匹配3.x版本的Nagios,但是在与实际使用的Nagios 3.5结合时,会出现部分perf data无法成功解析的情况,检查后发现Nagios 3.5的部分数据在graphios读取时,并没有按数据协议组织,导致解析错误。

对此,针对输出数据,修改了解析所在部分源码进行了匹配,筛选出了所需数据。

InfluxDB版本

提示的InfluxDB版本较新,为0.13,然而,在graphios的配置文件中,backend部分,只有enable_influxdb09以及enable_influxdb选项,默认使用的json数据写入协议已经在0.13中废弃。

上述问题,考虑到版本后续兼容性,将0.13视作0.9版本配置,并且配置数据写入协议为line即可(即配置influxdb_line_protocol = True)。

为了让graphios永驻后台,可以考虑使用supervisord等工具。

展现样例

load

load

CPU

CPU

小结

使用Nagios+graphios+InfluxDB+Grafana可以将监控数据以更好的方式进行展现,并能够回顾历史,查看趋势,随着Grafana的升级,还可以有更多的玩法。

Nagios检查域名是否可连通

 

概述

日常服务器使用中,可能存在某些服务器被意外的更改路由表等问题,在多张网卡的情况下,可能会出现Nagios可以发现服务器,但是实际上服务器对外连接不可用的情况。

这必然是对服务有着致命打击的,将其纳入监控势在必行。

分析

大多数时候,我们只需要要关心这个服务需要访问的域名的连通性,即主机的连通性,可以考虑通过nagios定时ping。如果是web服务,还可以通过curl判断访问情况。

思路确定的话,那么编写插件即变得很容易。针对Nagios的使用上,可以考虑定义自定义命令,通过nrpe调用客户端上的插件,通过主动检查的方式进行。

通过nrpe调用命令的设置上有一个很有趣的地方,客户端定义的指令和服务端定义的指令有一个位置的偏移,因为服务端的调用check_nrpe插件第一个参数$ARG1必定是客户端上的命令名称。所以服务端的定义的$ARG2将会被作为到客户端的$ARG1使用。

例如,服务端指定命令为:

客户端的命令为:

服务端 客户端
\(ARG1\) check_domain_accessibilty
\(ARG2\) \(ARG1\)
\(ARG3\) \(ARG2\)
\(ARG4\) \(ARG3\)

可以看到的对应关系为:

插件代码

插件代码通过shell编写,按照Nagios插件的特定,只出现OK/CRITICAL/UNKNOWN三种情况。

考虑到内网请求是主要关注的点,连通性不佳(如ping丢包)也会被归类到CRITICAL之中,用于提醒SA关注。

一组PHP7在Nginx与Apache下的测试数据

概述

PHP7作为迄今为止性能最强的PHP版本,希望通过一些测试来了解它在Nginx与Apache下的表现。数据仅供参考。

由于个人水平有限,对测试的理解可能有所偏差,如有错误麻烦指出。

运行环境

测试环境一共分为两台机器,机器A用作PHP运行环境,机器B作为压测机。A与B的CPU均为12 x Xeon E5 + 16GB RAM。

两台机器位于同一网段。

测试工具使用ab。

为了便于测试,调整了内核参数:

测试使用的软件版本为:

  • Apache 2.2
  • Nginx 1.2.7
  • PHP 7.0.4

Apache在httpd-mpm.conf中的配置为:

由于Apache+modphp7与Nginx+PHP-FPM二者的工作模式差别较大,想要均衡的配置出一个均衡的测试比较环境很困难,从简单出发,考虑到Apache在上述配置下最大会fork出512个进程处理请求,将PHP-FPM最大进程数也设成512个,即:

测试方法

测试主要针对三种操作进行:输出Hello World,Redis KV读取操作,输出phpinfo()。

选择Redis KV读取操作的目的主要想测试下这一常用扩展的在Apache与Nginx作为WebServer环境下的表现。

测试分为2组,分别在25并发以及512并发下进行,测试时长为1min,同时记录服务器的load情况。

关注的数据为:

  • 最小响应时间
  • 平均响应时间
  • 平均每秒请求数
  • load
  • 相关进程数

测试结果

测试从性能指标以及系统负载两个方面进行观察。

性能指标

最小响应时间

min_response_time.png

针对最小响应时间,并发数高低对最小响应时间没有显著的影响。在测试初期系统负载较低,测试数据应该表现最佳的阶段,推断二者在此阶段差距不大。

平均每秒请求数

requests_per_sec.png

针对平均每秒请求数,Nginx+PHP-FPM的组合处理能力稍低于Apache+modphp7的组合,考虑到Nginx与PHP-FPM之间有网络通信(测试中采用了tcp socket)的开销,这个结果是可以接受的。高并发下考虑系统开销较大,请求处理能力会稍有下降。

平均响应时间

mean_response_time.png

针对平均响应时间,高并发下同样由于系统开销较大的缘故,平均的请求处理响应时间升高也是符合预期的。

系统负载

从性能指标上看,Nginx+PHP-FPM的组合与Apache+modphp7的组合在表现上没有巨大的差距,但是在系统负载上,Nginx+PHP-FPM的配置在高并发的情况下远优于Apache+modphp7的组合。 在512并发时,在测试Hello world时,系统load的表现就有巨大的差距:

load_hello_world.png

同样的情况还出现在512并发之下对Redis KV操作的测试case之下:

load_redis_kv.png

即便是在低并发(25并发)下,Redis KV此类需要操作网络资源的操作,Apache+modphp7在系统负载上的表现也差于Nginx+PHP-FPM:

load_redis_kv_c25.png

对于这类需要操作I/O的操作来说,Apache+modphp7的组合表现差于使用了异步I/O的Nginx与PHP-FPM的组合是符合预期的。

在测试phpinfo()输出时,虽然二者在load上的区别不大,但是Nginx+PHP-FPM的组合在进程数这一指标上完全占优:

processes_count_phpinfo.png

考虑到Nginx+PHP-FPM的组合无需fork出新的子进程处理新到的客户端请求,以及phpinfo()的执行时间较长这两个因素,同时fork子进程等操作属于消耗系统资源较大的操作,这个现象是符合预期的。

总结

使用php7时,在性能上Apache+modphp7的组合与Nginx+PHP-FPM的组合相差无几,但对于系统负载上来说,Nginx+PHP-FPM组合综合表现优于Apache+modephp7的组合,可以推断Nginx+PHP-FPM的组合对于构建高并发的服务更有优势。

综合考虑,Nginx+PHP-FPM表现较优。

TODO

  • 尝试阅读ab源码,了解其测试原理
  • 比对fpm在动静模式之间的区别

一组Logstash与elasticsearch的压测数据

概述

组内的日志系统基于ELK搭建,本文中的数据在生产环境中进行测试得到,仅供参考。

系统构成

系统可以简要的分为:

  • 日志接收机
  • 日志数据队列
  • 日志数据处理机
  • ES集群

在日志接收机上通过一个 Logstash 进程 parse 日志数据,将 parse 后的结构写入由 Redis List 实现的日志数据队列中,之后在ES集群前,再使用一个日志处理机 Logstash 进程从 Redis 中 pop 出数据写入ES集群中。

使用 Redis List 的原因是在于当 parse 能力大于ES集群的处理能力时,缓存数据。

运行环境

日志接收机为CPU为4 * Xeon E5强IO型机器,Redis List 与向ES集群写入的 Logstash 位于同一机器上,即日志数据处理机,CPU为12 * Xeon E5。

处理日志为Nginx access日志,记录了如时间、域名、访问IP、URL、HTTP Method、响应时间、返回体长度等,约10+字段。

参数配置

日志接收机上的 Logstash 配置成了10个线程,output 中的 redis 的参数配置为:

日志数据处理机上的 input 对已配置为:

而 output 配置为:

测试方法

测试分为测试 Logstash 分析日志能力,以及ES集群写入能力。

Logstash 的分析能力通过每秒取样 Redis List 中的新增队列长度获得(日志接收机上的 Logstash 生产)。

ES集群的写入能力通过每秒取样 Redis List 中减少的队列长度获得(日志数据处理机 上的 Logstash 消费)。

在测试一个阶段时,会关闭另一端的 Logstash。

数据

平均数据后,可供参考的数据为:

Logstash 分析速度为:2352.94 lines/s

ES集群写入速度为:9345.79 records/s