首页 > 解决方案 > 一种数据结构,用于查询不同时间间隔内的事件数

问题描述

我的程序在一秒钟内接收到来自不同类型的数千个事件。例如,拥有数百万个不同 IP 地址的用户在一秒钟内访问 10 万次 API。我想在 1 分钟、1 小时、1 天等内保留统计信息并限制访问次数。所以我需要每个用户在最后一分钟、一小时或一天的事件计数,我希望它像一个滑动窗口。在这种情况下,事件类型是用户地址。

我开始使用时间序列数据库 InfluxDB;但它未能每秒插入 10 万个事件,并且聚合查询以在一分钟或一小时内查找事件计数甚至更糟。我确信 InfluxDB 不能每秒插入 10 万个事件并同时执行 30 万个聚合查询。

我不希望从数据库中检索事件,因为它们只是一个简单的地址。我只想在不同的时间间隔内尽可能快地计算它们。我想获取特定时间间隔(例如,过去 1 小时)内 x 类型的事件数。

我不需要在硬盘中存储统计数据;所以也许在不同时间间隔内保持事件计数的数据结构对我有好处。另一方面,我需要它像一个滑动窗口。

将 RAM 中的所有事件存储在链表中并对其进行迭代以回答查询是我想到的另一个解决方案,但由于事件数量太多,将所有事件保存在 RAM 中并不是一个好主意。

为此目的是否有任何好的数据结构甚至数据库?

标签: eventsdata-structurestime-seriesinfluxdb

解决方案


您没有提供有关事件输入格式以及如何将事件传递到统计后端的足够详细信息:它是 udp 消息流、http put/post 请求还是其他。

一种可能的解决方案是使用Yandex Clickhouse数据库。建议模式的粗略描述:

  1. 将来自应用程序的传入原始事件加载到基于内存的表事件Buffer storage engine
  2. 使用 Buffer 引擎在另一个基于内存的表EventsPerMinute中创建具有每分钟聚合的物化视图
  3. 对EventsPerHour中的每小时数据聚合执行相同的操作
  4. 或者,使用带有 clickhouse 数据源插件的 Grafana 来构建仪表板

在 Clickhouse DB Buffer 中,与任何磁盘表无关的存储引擎将完全保存在内存中,旧数据将自动替换为新数据。这将为您提供简单的原始数据管理。

如果您想在磁盘上保存统计信息,也可以使用 MergeTree 存储引擎创建表(物化视图)EventsPerMinuteEventsPerHour 。Clickhouse 可以轻松处理数十亿条记录。

在 100K 事件/秒时,您可能需要在数据库前使用某种整形器/负载均衡器。


推荐阅读