mysql 查询存储和事件






这是系列的第二篇文章,描述了我们最近在Plumbr进行的基础架构/体系结构转换。 第一部分着重于架构的事件捕获部分 。 在当前文章中,我们正在分析捕获的事件如何存储并随后通过用户界面访问。 同样,该帖子将引导您了解进行更改的动机并描述我们所做的选择。

对于不熟悉我们所做工作的读者,请先提供一些背景知识,以便为您提供背景知识。 Plumbr旨在监视每个用户与应用程序的交互。 这些交互由部署在参与交互的节点中的代理捕获。 捕获的交互将发送到服务器,在服务器上存储交互以供稍后查询。

要求

通过这种交互,Plumbr捕获了要存储和查询的不同属性。 这给了我们不同维度数据结构的基础要求:

  • 互动的开始和结束时间戳记;
  • 进行交互的用户的身份;
  • 完成的操作(将项目添加到购物车,创建新发票等);
  • 交互的结果(成功/缓慢/失败);
  • 对于不成功的交互,源代码中的根本原因是;

另外,每个交互都具有许多指标。 这种度量的一个示例可以是交互的总持续时间(以毫秒为单位)。

除了数据的结构之外,在选择存储时,数据访问用例也很重要。 以下是我们的用户如何访问数据集的一些示例:

  • 向我显示过去一个月特定应用程序的每日活跃用户趋势。
  • 上周影响我的网站性能的前三大根源是什么?
  • 比较当前和上周结帐操作的效果。 通过比较两个时段的延迟分布向我介绍结果。

最后要考虑的需求类别毫无疑问是非功能需求部分。 对于各种NFR,要实现的最棘手的就是确保我们可以快速访问大量数据。 我们必须从包含数万亿个事件的数据集中回答上述问题。 这样的答案将在几秒钟内给出。

解决方案

数据的结构和访问模式使我们很明显地正在处理时间序列数据的教科书定义。 在承认这一事实之后,很显然,最初决定将所有内容存储在关系数据库中可能不是最好的决定。

因此,我们一直在寻找适合时间序列数据的新存储解决方案。 在根据需求测试了InfluxDBCassandraMonetDBDruid之后 ,我们最终选择了Druid。 在以下各节中,我将引导您了解Druid中最重要的概念,使我们能够满足要求。

数据汇总

Plumbr旨在回答的问题本质上是分析性的。 这样就可以将答案基于汇总而不是单个事件。 了解了这一点,我们将Druid配置为在数据摄取期间执行数据汇总。 汇总使我们能够将(某些)聚合和计算的成本转移到数据存储阶段,而不是数据访问阶段。

如果听起来太复杂,请查看以下示例。 让我们使用以下五个事件来表示两种不同的事件类型(登录和支付发票),它们都在同一天的12:20和12:21之间发生:

ID

事件类型

开始

结束

#1

登录()

12:20:02

12:20:04

#2

工资()

12:20:05

12:20:10

#3

登录()

12:20:03

12:20:20

#4

登录()

12:20:42

12:20:44

#5

工资()

12:20:45

12:20:46

现在,我们可以将这五个事件汇总到Druid存储中的两个条目中:

范围

事件类型

事件数

12:20 – 12:21

登录()

3

12:20 – 12:21

工资()

2

由于汇总,我们避免了存储单个事件。 由于事件的特性,我们能够实现这一目标:我们无需存储单个事件,而是使用预先计算的汇总将事件汇总到Druid中的两个单个值。 从减少的存储需求和加快查询的角度来看,汇总的好处都是可以衡量的。

在我们的案例中,汇总的结果是原始事件减少了十到一百倍,这取决于我们最终监视的特定应用程序。 我们为此付出的代价也很明确–数据访问操作的最小粒度限制为一分钟。

资料分割

显然,时间序列是……好,取决于时间�� 因此,我们有一系列连续的1分钟的存储桶,其中包含汇总数据。 对此类数据桶的大多数查询都执行简单的关联聚合(求和,平均,最大值等)。

聚合的关联性质意味着Druid可以将原始查询拆分为单独的块,在多个节点上并行运行这些子查询,然后仅合并部分结果以计算最终答案。 为了让您对此有个更好的了解,让我们考虑以下示例:

用户要求系统“在过去7天内从www.example.com应用程序中提供10个最常用的端点列表”。

Druid Broker会将查询分为多个子查询,而不是在单个节点中执行原始查询,每个子查询从7天周期开始的一天开始请求数据,并在不同的Historical节点中执行每个子查询。

MySQL上亿数据的秒级查询 实现 mysql几亿数据查询时间_大数据

在所有节点都响应之后,剩下的就是将结果汇总到代理中,然后将其发送回发送请求的客户端。

如果这听起来像著名的MapReduce算法的实现,那么您是正确的,的确如此。 结果,开发人员以零的努力获得了可观的查询加速。 该方法的副作用越来越接近于基础架构中的线性水平缩放。 只需将更多服务器添加到您的群集中,确保根据使用模式配置了及时的分区,其余的由Druid负责。

实时数据与历史数据

在提供历史数据和实时数据之间,德鲁伊具有内置的关注点分离。 在我们的情况下,“实时”转换为“最后一小时”。 当我们通过不同的微服务从Plumbr Agents接收并处理数据时,Druid将不断获得新的数据点:

MySQL上亿数据的秒级查询 实现 mysql几亿数据查询时间_python_02

专用索引节点(Indexer)使用传入的提要。 完全相同的索引器将负责回答有关最近一小时的最新数据的所有(子)查询。

每小时一次,该索引节点将原始提要转换为汇总的数据,并将其交给要存储数据的节点。 这些节点称为历史节点。 该方法允许Druid有效地查询具有不同特征的两个数据集:

  • 从Indexer节点中的原始事件查询仍可能更改的最新数据
  • 从历史节点(已汇总原始事件)中查询预期不会更改的较旧数据。

MySQL上亿数据的秒级查询 实现 mysql几亿数据查询时间_python_03

该方法的缺点是历史数据的只写格式。 无法更改历史节点中的数据。 更新数据的唯一方法是从原始事件流中重新生成整个段

带走

数据处理和存储更改花费了我们六个月的时间来实施,测试和推出。 我们仍在完善结果–这样的重大更改并不会在白板和测试中完全暴露出全部的复杂性。 当某些事情没有按预期工作时,我本人在早上有2AM警报。

但是我什至无法想象没有新架构的生活。 由关系数据库支持的整体上的同步处理感觉就像是我想忘记的遥远过去的噩梦。

翻译自: https://www.javacodegeeks.com/2017/02/storing-querying-trillions-events.html

mysql 查询存储和事件