本文要点
时序数据管理对于组织中的数据分析至关重要, 举例来说, 股票价格或 CPU 性能指标都是时序数据.
像 RedisTimeSeries 这样专门构建的数据库解决了处理时序数据的需求, 同时摆脱了关系型数据库强加给我们的限制.
其他专门为此构建的数据库包括 InfluxDB 和 Prometheus.
通过将 Grafana 和 RedisTimeSeries 集成在一起, 我们可以实时放大或缩小图表.
时序数据可以广义地定义为按照时间顺序存储的一系列数据, 举例来说, 多年内的股票价格变动或过去几个小时 CPU 性能指标都是时序数据. 时序数据广泛用于很多垂直行业, 因为关系型, 面向文档的以及流式数据库都不能满足这种特殊类型的数据的需求.
时序数据的特点
时序数据库有着独特的特点(如下面列表所示), 如果与其他数据库一起管理的话, 通常会是非常低效的:
高速的数据摄入 : 不管是 IoT 使用场景还是市场分析数据, 我们都会有一个稳定的数据流, 数据以很快的速度抵达, 而且常常是爆发性的. 对于大多数解决方案, 一年中 365 天, 24/7 之内都有数据抵达.
数据不可变 : 一旦插入到数据库之中, 在过期或删除之前, 数据点不会进行任何修改. 数据通常是带有时间戳和多个数据点的日志.
非结构化的标签 : 时序数据通常是在一定的时间范围内有很多源连续生成的. 例如, 在 IoT 使用场景中, 每个传感器都是时序数据的源. 在这样的场景中, 序列中的每个数据点都以标签的形式存储源信息和其他传感器测量数据. 来自每个源的数据标签可能并不符合相同的结构或顺序.
数据的价值随时间递减 : 只有恰当时间范围内的聚合汇总数据才会对未来产生价值. 例如, 在一年之后, 大多数用户都不需要毫秒范围内存储的每个数据点. 只有按照分钟, 小时或每天聚合和汇总起来的数据才有意义.
查询要根据时间间隔进行聚合 : 基于时序数据生成图表能够让我们放大和缩小查询. 之所以能够实现这一点是因为它们的数据是根据间隔聚合而成的. 一般而言, 时序数据查询是聚合的. 这与从数据库检索单条记录是截然不同的.
在时序场景中使用传统数据库所面临的问题
很多解决方案会依然在关系型数据库中存储时序数据. 这种方式有很多缺点, 这主要是因为关系型数据库:
是针对事务性使用场景设计的, 并对此进行了优化.
会带来锁和同步的开销, 对于不可变的时序数据来说, 这是没有必要的. 这会导致数据摄入和查询的性能都比要求更慢. 企业最后只能投资额外的计算资源实现扩展.
会对标签强制定义严格的结构, 不能存放非结构化的数据.
需要定期的任务来清理旧数据.
会用于多个使用场景. 时序数据查询的过量使用可能会影响其他的工作负载.
重新思考时序数据库
专门的时序数据库解决了处理时序数据的需求. 它同时移除了关系型数据库强加的限制. RedisTimeSeries 是一个专门构建的用来收集, 管理和交付大规模时序数据的方案. 它提供了如下的功能:
快速的数据摄入 : 作为一个内存数据库, RedisTimeSeries 可以在单个节点上 每秒钟摄入超过 500000 条记录 . 根据我们的基准测试, 在 16 个 Redis 分片 (shard) 的集群中, 每秒可以摄入超过 1150 万条记录.
高效的资源使用 : 借助 RedisTimeSeries, 我们可以通过缩减采样 (downsampling) 的方法添加规则来压缩数据. 举例来说, 如果我们每天会收集超过 10 亿个数据点, 但是, 我们可以按照每分钟对这些数据进行聚合, 从而实现缩减采样, 所以这样可以把数据集缩减到 24 * 60 = 1440 个数据点. 我们还可以设置数据保留策略, 在不需要它们的时候将其设置为过期失效.
图 1: 使用时序数据库缩减采样和聚合
简单快速的查询 :RedisTimeSeries 允许我们根据平均值, 最小值, 最大值, 总和, 计数, 范围, 第一个和最后一个来聚合数据. 我们可以以毫秒级的延迟每秒钟运行超过 100,000 个聚合. 我们还可以在特定的时间范围内对标签执行反向查找.
其他专门适用于时序数据的数据库包括 Influx DB 和 Prometheus.
典型的时序数据库通常就是为了管理时序数据来构建的, 所以它所面临的一项挑战就是在时序数据之上进行某些计算的使用场景. 举例来说, 我们要在时序数据库中捕获实时视频. 如果我们要使用某种 AI 模型进行人脸识别, 那么必须要抽取时序数据, 应用某种类型的数据转换, 然后再进行计算. 对于实时使用场景来说, 这种方式并不理想. 多模型的数据库还能够管理其他的数据模型, 这样的数据库解决了这些使用场景的问题, 它们可以在恰当的位置操作多个数据模型.
RedisTimeSeries 快速指南
开始学习 RedisTimeSeries 的最便捷方式就是将其作为数据源添加到 Grafana https://grafana.com/ 仪表盘中. 在本文的下一节中, 我将会展示如何加载样例时序数据到 RedisTimeSeries 中, 并在 Grafana 仪表盘中浏览该数据.
我选择比较苹果公司 (Apple Inc.,AAPL) 和英特尔公司 (Intel Inc.,INTC) 过去 19 年间的股价表现, 在这里会使用 Grafana 面板上的图表:
图 2: 使用 RedisTimesSeries 和 Grafana 对比苹果和英特尔的股价
我的 RedisTimeSeries 搭建过程
我首先从 GitHub https://github.com/RedisTimeSeries/RedisTimeSeries 下载了 RedisTimeSeries 的源码, 并在本地进行构建. 随后, 我使用命令将 ".so" 文件导入到 Redis 中:
MODULELOAD[pathto]/redistimeseries.so
我也可以通过在 Redis.conf 中插入以下命令来加载模块:
loadmodule [pathto]/redistimeseries.so
如果你更喜欢 Docker 的话, 那么可以尝试执行如下的命令:
dockerrun-p6379:6379-it--rm redislabs/redistimeseries
Redis 服务器启动之后, 我们可以通过运行 "module list" 命令检查 Redis 是否已经成功加载模块. 如下所示,"timeseries" 作为一个模块列到了下面:
127.0.0.1:6379> module list1)1)"name"2)"timeseries"3)"ver"4) (integer)200
示例数据集: 过去 19 年的股票市场数据
我从 Wall Street Journal 网站下载了 AAPL 和 INTC 的每日股票价格. 该文件以 CSV(逗号分隔值)的格式包含了从 2000 年到现在的价格信息. 如下是 AAPL 的一些示例数据:
2006-01-03,10.34,10.68,10.32,10.68,201853036,AAPL2006-01-04,10.73,10.85,10.64,10.71,155225609,AAPL2006-01-05,10.69,10.7,10.54,10.63,112396081,AAPL2006-01-06,10.75,10.96,10.65,10.9,176139334,AAPL2006-01-09,10.96,11.03,10.82,10.86,168861224,AAPL2006-01-10,10.89,11.7,10.83,11.55,570088246,AAPL2006-01-11,11.98,12.11,11.8,11.99,373548882,AAPL2006-01-12,12.14,12.34,11.95,12.04,320201966,AAPL2006-01-13,12.14,12.29,12.09,12.23,194153393,AAPL2006-01-17,12.24,12.34,11.98,12.1,209215265,AAPL
接下来, 我编写了一个 Python 脚本将该数据导入到 RedisTimeSeries 中:
importsysimport csvimport timeimport redisif(len(sys.argv)>1): ticker = str(sys.argv[1])else: ticker ='test'file = ticker +'.csv'r = Redis.Redis(host='localhost', port=6380, db=0)withopen(file)ascsv_file: csv_reader = CSV.reader(csv_file, delimiter=",") r.execute_command("ts.create stock:"+ticker); count =0forrowincsv_reader: time_tuple =time.strptime(row[0],'%Y-%m-%d') time_epoch =time.mktime(time_tuple)*1000r.execute_command("ts.add stock:"+ticker+""+str(int(time_epoch))+" "+row[1]) count = count +1print(f'Imported {count} lines')
可以看到, 我在这里使用 RedisTimeSeries 的 TS.CREATE 命令来建立新的时序数据结构, 并使用它的 TS.ADD 命令填充该数据结构. 对于代码为 AAPL 的股票, 该程序创建了名为 stock:aapl 的数据结构. 添加数据的样例命令如下所示:
TS.ADDstock:aapl1513324800000 173.04
接下来, 我运行 TS.RANGE 命令来校验数据. 请注意, 该查询中所使用的时间戳是毫秒级别的.
127.0.0.1:6379> TS.RANGE stock:aapl15133248000001514324800000aggregation avg11)1) (integer)15133248000002)"173.63"2)1) (integer)15135840000002)"174.88"3)1) (integer)15136704000002)"174.99000000000001"4)1) (integer)15137568000002)"174.87"5)1) (integer)15138432000002)"174.16999999999999"6)1) (integer)15139296000002)"174.68000000000001"7)1) (integer)15142752000002)"170.80000000000001"
在下一节中, 我将会阐述如何使用 Grafana 来浏览和对比股票价格.
在 Grafana 中浏览 RedisTimeSeries 数据
在本节中, 我将会介绍如何安装 Grafana, 并使用 SimpleJSON 数据连接器 从 RedisTimeSeries 中读取数据. 为了实现这一点, 我开发了一个新的 SimpleJSON 数据源应用程序. 它是一个中间层, 是基于 HTTP 的 Node.JS 应用, 它会将 SimpleJSON 调用转换为 Redis 调用, 并将 RedisTimeSeries 数据转换为 JSON 数据.
第一步: 安装 Grafana
首先, 我使用 homebrew 工具将 Grafana 安装到我的 Mac 电脑上(如果你使用 PC 的话, 请按照 Grafana 的使用说明安装并搭建环境). 我运行如下的命令启动 Grafana:
$brewinstallgrafana$brewservices start grafana==> 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, 我们可以实时放大或缩小图表. 每秒钟我们可以处理更多的查询, 从而能够让仪表盘的面板上展示更多的数据点. 基于此, 我们能够添加更多的面板, 服务于更多的用户.
来源: http://www.tuicool.com/articles/NVRZnun