原文作者:ShiftLeft 资深基础架构工程师Preetam Jinka,发布于 2018 年 12 月 5 日。本文最初作为Time Series发布于ShiftLeft。
时间序列(Time series)是 ShiftLeft 运行时体验的主要组成部分。对于很多其他产品和组织来说也是如此,但是,每种情况都涉及不同的特性和要求。本文描述了我们必须要用到的要求,我们如何使用TimescaleDB来存储和检索时间序列数据,以及我们为管理基础架构而开发的工具。
我们有两类时间序列数据:指标和漏洞事件。指标代表应用事件,那些涉及安全问题的子集是漏洞事件。在这两种情况下,这些时间序列都具有某种 ID、时间戳和计数。漏洞事件也可以有事件样本,其中包含实施安全漏洞要求的详细信息。除了这些属性之外,时间序列也可以由内部 ID 来键入,我们称该内部 ID 为 SP ID,其本质上代表了特定版本的客户项目。
指标的数据模型与代码属性图的源-汇模型(source-sink model)密切相关,因此,对于给定的应用,其方式和 I/O 以及数据流被组织成触发器、输入及输出。下图说明了这一点,它总结了一些充当触发器的典型端点,以及在这些端点处接收的输入最终到达输出(如日志)的流。我们很少查询单个指标的时间序列数据;通常,我们需要根据该数据模型查询大量相关指标。
流及其触发器、输入和输出端点的可视化
以下是我们用于实施的要求:
需要用 Go 语言,因为几乎所有的运行时基础架构都是用 Go 语言编写的。
需要与我们的其他开发及测试环境相匹配。例如,我们的端到端(end-to-end,E2E)测试环境是用Docker Compose实现的,因此,所有数据库需要作为 Docker 映像可用。
必须支持快速迭代工作流。新功能可以改变需求,因此,我们不能过于拘泥于单一数据模型。
必须能够通过小型团队进行管理。我们是资源有限的初创公司,因此,最好选择很多人都熟悉的技术。
多粒度支持和保留管理让我们能够快速查询并保持低成本。
到目前为止,我们发现TimescaleDB最符合这些要求。TimescaleDB 是开源的 PostgreSQL 插件,提供称为元数据表(hypertable)的特殊表,操作起来类似常规的 PostgreSQL 表,但在底层被划分为几个块。这些块可以是时间分区和用户定义的属性。在我们的案例中,我们把 SP ID 用作分区栏。这样可以快速更新和查询,有益于多个表的使用,无需在查询中处理分区逻辑。
我们的元数据表可以有上千个块。对于给定 SP ID 和时间范围,我们查询指标时,TimescaleDB 会过滤掉不必要的块,只查询小子集以执行查询操作。元数据表的另一个优点是,我们能够通过丢弃块而不是在大型表上运行昂贵的删除操作来快速清除旧数据。
最后,因为我们仍在使用 PostgreSQL,所以可以利用已有的开发和运营经验。我们把其他 PostgreSQL 实例用于一些我们所需的其他 SaaS 数据存储,因此,我们受益于像 Gaum 这样的代码重用。还有很多支持 PostgreSQL 开箱即用的监控解决方案。
基础架构
几乎所有的 ShiftLeft 是用 Docker 容器部署在编排系统上的。这包括 TimescaleDB。我们也用 Docker 映像来进行测试,并拥有一个使用 Docker Compose 的复杂 E2E 测试套件。
大多数 ShiftLeft 运行时基础架构是用 Go 语言编写的。来自代理的运行时指标数据结束于网关实例,这些网关实例发布到 Kafka 主题。另一方面,我们有消费者实例,它们会摄取和汇总指标数据,偶尔会批量写入 TimescaleDB。最小的粒度是 2 秒,在消费者中,我们也有 1 分钟和 5 分钟汇总粒度。ShiftLeft 也有 1 小时和 1 天的粒度,但是,这是用批处理来管理的。
汇总/下采样
我们创建了一个时段下采样工作来支持更大的粒度,而无需在内存中汇总。在摄取时,我们定期地更新metrics_downsampling_status
表,这是用于存储下采样任务的表。
metrics_downsampling_status
表中的样本数据:
在这张表中,输入的更新与我们的 5 秒刷新汇总同步。当下采样任务运行时(每小时一次),它寻找状态表中没有处理过的行,把 5 秒粒度的数据汇总成 1 小时或 1 天的粒度,然后再更新该状态表。
查询
我们的指标 API 是用 Go 语言编写的,它的逻辑是根据请求来使用最佳(或几个)粒度)。比如,如果一个 5 小时的间隔要求有 60 个点,这意味每个点是 5 分钟,因此,我们可以使用 5 分钟粒度的数据。任何比在 5 小时范围内采样 60 个点小的任务意味着我们必须使用 1 分钟或 2 秒钟的粒度。汇总计数(除了图表外)表现得像图表,只是用 1 个点而已。
粒度逻辑示例:
我们在查询上的问题是,有时候在计划上花费了太多时间。在有个例子中,我们观察到一个查询花费 17 秒来计划,但只用了 250 毫秒来执行。随着 0.10 版本的发布,这个问题得到了解决,0.10 版显著地改善了查询的块交互。可以阅读这里以了解更多有关 Timescale 在这个改进方面的工作。
##示例
漏洞事件可以有查询的详细信息,包括 HTTP 路径和表头的请求信息。其中的一些事件利用 JSONB 列进行采样并在元数据表中存储为 JSON。通这个方法,我们可以灵活地使用 JSON 和非结构性数据,以及元数据表的运营优势。
监控
我们用多种方式监控请求、TimescaleDB 和相关组件。为了监控查询性能,我们结合使用 PgHero 和应用程序指标。PgHero 使用 pg_stat_statements,并提供对顶层查询的粗略视图。在实践中,我们通常没觉得这有用,因为我们的查询往往很快,而我们的请求延迟主要来自于执行大量的这类查询,而不是单个慢速的查询。大多数时间序列指标请求监控使用 Prometheus 指标来完成,它们通过 API 和 Grafana 可视化展示出来。
平均指标延迟
在摄取监控方面,我们密切关注 DB 写入速率和延迟。
数据库写入速率
刷新指标到 TimescaleDB 的平均延迟时间
我们还广泛使用 Grafana 和 PostgreSQL,但是出于运营目的,同时,不从元数据表中提取时间序列。通过使用 Grafana 中的 PostgreSQL 数据源选项,我们可以针对任何 PostgreSQL 数据库,在查询的基础上创建可视化。我们的下采样图表就是好例子。这些例子利用前面所描述的 metrics_downsampling_status 表,并让我们关注待做的工作和处理时间。
利用 Grafana 来监控下采样作业状态
以下是 Grafana 图表的 SQL 查询之一:
平均下采样作业延迟时间
当缩小像 90 天这样比较长的时间段时,可以清楚地看到一些有趣的趋势。在我们的例子中,下采样任务用时开始变得越来越长。它们仍然保持在平均 2 秒钟,因此,我们还没有遇到任何问题。
长期下采样延迟趋势
接下来是什么
我们一直在用 kafka 运行基础架构,并在生产环境中用了一段时间的 TimescaleDB,在功能使用和监控方面已经用它完成了很多不同的工作。换句话说,还有些地方我们希望能看到改进,也即我们管理基础架构的方式和 TimescaleDB 可以实现的功能。
我们如何能够改进基础架构
最佳块的大小:我们还未决定最佳块的大小,我们也还未尝试自适应组块。
只读副本:我们还未使用只读副本。通过添加只读副本和并行化请求,我们可以轻松地提高只读查询性能。
PostgreSQL 10: 我们还在使用 PostgreSQL 9.6。PostgreSQL 10 引入了 JIT 编译和 WHERE 语句的评估,这可以真正地改进那些必须过滤很多行的查询。
更好的摄取监控:我们对 PostgreSQL 有很多可见性,但是,对在 PostgreSQL 之前指标上发生的事情没有可见性。例如,关于指标消息在 API 上被接受直到进入 TimescaleDB 所需的时间,我们想要有更好的指标。
我们希望从 TimescaleDB 看到的东西
RDS 支持:TimescaleDB 是我们自己托管的唯一数据库。其他的 PostgreSQL 实例托管在 RDS 上。如果 TimescaleDB 是受支持的插件,我们可能都用 RDS 了。
压缩:我们可以用 ZFS 来压缩,但是还未尝试。压缩还不是主要的需求。如果 TimescaleDB 支持开箱即用压缩,那是太好不过了。
阅读英文原文: How ShiftLeft Uses PostgreSQL Extension TimescaleDB
评论 1 条评论