[关闭]
@levinzhang 2019-11-28T22:01:55.000000Z 字数 6540 阅读 655

使用Redis TimeSeries和Grafana实现实时分析

by

摘要:

在本文中,作者Roshan Kumar讨论了如何使用像RedisTimeSeries这样专门构建的数据库来管理时序数据。他还展示了如何在Grafana仪表盘中可视化这些数据。


核心要点

时序数据可以广义地定义为按照时间顺序存储的一系列数据,举例来说,多年内的股票价格变动或过去几个小时CPU性能指标都是时序数据。时序数据广泛用于很多垂直行业,因为关系型、面向文档的以及流式数据库都不能满足这种特殊类型的数据的需求。

时序数据的特点

时序数据库有着独特的特点(如下面列表所示),如果与其他数据库一起管理的话,通常会是非常低效的:

  1. 高速的数据摄入:不管是IoT使用场景还是市场分析数据,我们都会有一个稳定的数据流,数据以很快的速度抵达,而且常常是爆发性的。对于大多数解决方案,一年中365天,24/7之内都有数据抵达。
  2. 数据不可变:一旦插入到数据库之中,在过期或删除之前,数据点不会进行任何修改。数据通常是带有时间戳和多个数据点的日志。
  3. 非结构化的标签:时序数据通常是在一定的时间范围内有很多源连续生成的。例如,在IoT使用场景中,每个传感器都是时序数据的源。在这样的场景中,序列中的每个数据点都以标签的形式存储源信息和其他传感器测量数据。来自每个源的数据标签可能并不符合相同的结构或顺序。
  4. 数据的价值随时间递减:只有恰当时间范围内的聚合汇总数据才会对未来产生价值。例如,在一年之后,大多数用户都不需要毫秒范围内存储的每个数据点。只有按照分钟、小时或每天聚合和汇总起来的数据才有意义。
  5. 查询要根据时间间隔进行聚合:基于时序数据生成图表能够让我们放大和缩小查询。之所以能够实现这一点是因为它们的数据是根据间隔聚合而成的。一般而言,时序数据查询是聚合的。这与从数据库检索单条记录是截然不同的。

在时序场景中使用传统数据库所面临的问题

很多解决方案会依然在关系型数据库中存储时序数据。这种方式有很多缺点,这主要是因为关系型数据库:

重新思考时序数据库

专门的时序数据库解决了处理时序数据的需求。它同时移除了关系型数据库强加的限制。RedisTimeSeries是一个专门构建的用来收集、管理和交付大规模时序数据的方案。它提供了如下的功能:

图1:使用时序数据库缩减采样和聚合

其他专门适用于时序数据的数据库包括Influx DB和Prometheus。

典型的时序数据库通常就是为了管理时序数据来构建的,所以它所面临的一项挑战就是在时序数据之上进行某些计算的使用场景。举例来说,我们要在时序数据库中捕获实时视频。如果我们要使用某种AI模型进行人脸识别,那么必须要抽取时序数据、应用某种类型的数据转换,然后再进行计算。对于实时使用场景来说,这种方式并不理想。多模型的数据库还能够管理其他的数据模型,这样的数据库解决了这些使用场景的问题,它们可以在恰当的位置操作多个数据模型。

RedisTimeSeries快速指南

开始学习RedisTimeSeries的最便捷方式就是将其作为数据源添加到Grafana仪表盘中。在本文的下一节中,我将会展示如何加载样例时序数据到RedisTimeSeries中,并在Grafana仪表盘中浏览该数据。

我选择比较苹果公司(Apple Inc.,AAPL)和英特尔公司(Intel Inc.,INTC)过去19年间的股价表现,在这里会使用Grafana面板上的图表:

图2:使用RedisTimesSeries和Grafana对比苹果和英特尔的股价

我的RedisTimeSeries搭建过程

我首先从GitHub下载了RedisTimeSeries的源码,并在本地进行构建。随后,我使用命令将“.so”文件导入到Redis中:

MODULE LOAD [path to]/redistimeseries.so

我也可以通过在redis.conf中插入以下命令来加载模块:

loadmodule [path to]/redistimeseries.so

如果你更喜欢Docker的话,那么可以尝试执行如下的命令:

docker run -p 6379:6379 -it --rm redislabs/redistimeseries

Redis服务器启动之后,我们可以通过运行“module list”命令检查Redis是否已经成功加载模块。如下所示,“timeseries”作为一个模块列到了下面:

  1. 127.0.0.1:6379> module list
  2. 1) 1) "name"
  3. 2) "timeseries"
  4. 3) "ver"
  5. 4) (integer) 200

示例数据集:过去19年的股票市场数据

我从Wall Street Journal网站下载了AAPL和INTC的每日股票价格。该文件以csv(逗号分隔值)的格式包含了从2000年到现在的价格信息。如下是AAPL的一些示例数据:

  1. 2006-01-03,10.34,10.68,10.32,10.68,201853036,AAPL
  2. 2006-01-04,10.73,10.85,10.64,10.71,155225609,AAPL
  3. 2006-01-05,10.69,10.7,10.54,10.63,112396081,AAPL
  4. 2006-01-06,10.75,10.96,10.65,10.9,176139334,AAPL
  5. 2006-01-09,10.96,11.03,10.82,10.86,168861224,AAPL
  6. 2006-01-10,10.89,11.7,10.83,11.55,570088246,AAPL
  7. 2006-01-11,11.98,12.11,11.8,11.99,373548882,AAPL
  8. 2006-01-12,12.14,12.34,11.95,12.04,320201966,AAPL
  9. 2006-01-13,12.14,12.29,12.09,12.23,194153393,AAPL
  10. 2006-01-17,12.24,12.34,11.98,12.1,209215265,AAPL

接下来,我编写了一个Python脚本将该数据导入到RedisTimeSeries中:

  1. import sys
  2. import csv
  3. import time
  4. import redis
  5. if(len(sys.argv) > 1):
  6. ticker = str(sys.argv[1])
  7. else:
  8. ticker = 'test'
  9. file = ticker + '.csv'
  10. r = redis.Redis(host='localhost', port=6380, db=0)
  11. with open(file) as csv_file:
  12. csv_reader = csv.reader(csv_file, delimiter=",")
  13. r.execute_command("ts.create stock:"+ticker);
  14. count = 0
  15. for row in csv_reader:
  16. time_tuple = time.strptime(row[0], '%Y-%m-%d')
  17. time_epoch = time.mktime(time_tuple)*1000
  18. r.execute_command("ts.add stock:"+ticker+" "+str(int(time_epoch))+" "+row[1])
  19. count = count + 1
  20. print(f'Imported {count} lines')

可以看到,我在这里使用RedisTimeSeries的TS.CREATE命令来建立新的时序数据结构,并使用它的TS.ADD命令填充该数据结构。对于代码为AAPL的股票,该程序创建了名为stock:aapl的数据结构。添加数据的样例命令如下所示:

TS.ADD stock:aapl 1513324800000 173.04

接下来,我运行TS.RANGE命令来校验数据。请注意,该查询中所使用的时间戳是毫秒级别的。

  1. 127.0.0.1:6379> TS.RANGE stock:aapl 1513324800000 1514324800000 aggregation avg 1
  2. 1) 1) (integer) 1513324800000
  3. 2) "173.63"
  4. 2) 1) (integer) 1513584000000
  5. 2) "174.88"
  6. 3) 1) (integer) 1513670400000
  7. 2) "174.99000000000001"
  8. 4) 1) (integer) 1513756800000
  9. 2) "174.87"
  10. 5) 1) (integer) 1513843200000
  11. 2) "174.16999999999999"
  12. 6) 1) (integer) 1513929600000
  13. 2) "174.68000000000001"
  14. 7) 1) (integer) 1514275200000
  15. 2) "170.80000000000001"

在下一节中,我将会阐述如何使用Grafana来浏览和对比股票价格。

在Grafana中浏览RedisTimeSeries数据

在本节中,我将会介绍如何安装Grafana,并使用SimpleJSON数据连接器从RedisTimeSeries中读取数据。为了实现这一点,我开发了一个新的SimpleJSON数据源应用程序。它是一个中间层,是基于HTTP的Node.js应用,它会将SimpleJSON调用转换为Redis调用,并将RedisTimeSeries数据转换为JSON数据。

第一步:安装Grafana

首先,我使用homebrew工具将Grafana安装到我的Mac电脑上(如果你使用PC的话,请按照Grafana的使用说明安装并搭建环境)。我运行如下的命令启动Grafana:

  1. $ brew install grafana
  2. $ brew services start grafana
  3. ==> Successfully started `grafana` (label: homebrew.mxcl.grafana)

Grafana现在已经在3000端口运行了,因此我们可以使用http://localhost:3000登录。

第二步:开发和运行SimpleJSON数据源应用

Grafana有一个内置的数据源连接器,名为SimpleJSON,它能够连接至支持“/”、“/search”和“/query” HTTP服务器的任意应用程序。因为RedisTimeSeries目前还没有自己的连接器,所以我开发了一个新的Node.js应用程序,它支持HTTP协议,并且支持SimpleJSON数据源应用所需要的查询。你可以从GitHub上下载我的代码,并在本地Node.js环境中运行它。

SimpleJSON数据源应用中的每个HTTP查询都有特定的目的,针对每个HTTP查询,我基于如下的设计原则开发了我的程序:

1. “/”:这是一个默认的请求,其响应是任意的消息。它用来测试连接(类似于ping测试)。

2. “/search”:该查询应该返回持有时序数据的key列表。(在其他数据库中,这可能是表名的列表,而不是key的列表,但是,因为Redis是key-value存储,所以我们返回的是key的列表,它们用来表示时间序列的特定类型。)

为了获取key的列表,我使用了更安全的“SCAN”命令来替换“KEYS”。对于每个key,我会检查它是不是“TSDB-TYPE”类型,这是我们用于时序key的内部名称。程序维护了所有该类型key的一个数组,并以JSON格式返回这个数组。

3. “/query”:该查询接收输入参数,其中包含了key的列表、开始时间、结束时间和bucket时间。应用程序会基于传入的命令以JSON格式返回时序数据。

另外,还有第四个HTTP请求,名为“/annotations”,但是对于示例应用程序来说,我们并不需要这个请求。

代码就绪之后,我就可以运行node应用程序了。示例代码在3333端口监控HTTP请求,所以我可以在浏览器中通过访问http://localhost:3333对其进行测试。它将会返回:“I have a quest for you!”。

第三步:使用RedisTimeSeries连接Grafana

在所有的步骤中,这是最简单的一步。在登录Grafana之后,我添加了一个数据源,这是通过访问Configuration > Data Sources并点击“Add data source”实现的。

我搜索SimpleJSON选项并选中它。

这会打开一个配置界面,在这里输入URL,以便于连接至我的Node.js应用。

数据源配置完成之后,我就可以添加新的面板到仪表盘中。对于本例来说,我添加了一个具有两项查询的面板:对于每个股票的行情各有一个时序查询。如图所示,我的查询所对应的下拉菜单中已经填充了时序key,即:stock:aapl and stock:intc。我选完时序key之后,该图表将会立即填充上数据。在幕后,SimpleJSON连接器已经使用对应的查询(“/search”和“/query”)调用了我们的应用程序。

这就是最终结果:Grafana面板能够查询RedisTimeSeries了。搭建RedisTimeSeries并将其连接至Grafana是非常简单的。

总而言之,RedisTimeSeries结合了Redis和专门的时序数据库的所有优点。它能够以多种方式来帮助我们的业务,包括节省资源、支持更多的终端用户,并且借助便捷的集成,能够让我们的应用更快地推向市场。通过集成Grafana与RedisTimeSeries,我们可以实时放大或缩小图表。每秒钟我们可以处理更多的查询,从而能够让仪表盘的面板上展示更多的数据点。基于此,我们能够添加更多的面板,服务于更多的用户。

关于作者


Roshan Kumar是Redis Labs, Inc的高级产品经理。他在软件开发和产品管理方面有着丰富的经验。以前,Kumar曾在惠普(Hewlett-Packard)和多家成功的硅谷创业公司工作。他拥有美国加利福尼亚州圣克拉拉大学的计算机科学学士学位和MBA学位。

查看英文原文:How to Use Redis TimeSeries with Grafana for Real-time Analytics

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注