【问题标题】:How to calculate distribution (Histogram) of large amount of data in a distributed system?如何计算分布式系统中大量数据的分布(直方图)?
【发布时间】:2024-10-22 04:00:01
【问题描述】:

我正在一个包含超过 100,000 个前端实例的实例队列上构建一个指标报告系统。对于任何请求,每个实例都会有一个响应时间。而我需要的是在整个车队中各种请求的响应时间分布。例如 [requestType1, requestType2...requestType1000] 的 [Percentile 50, Percentile 90, Percentile 99, Percentile99.9...]。

每一个实例都会收集里面发生的响应时间。所以一分钟后,一个实例在内存中收集的是各种 requestType 的响应时间列表。比如requestType1 - [1, 2, 3, 4, 1, 2], requestType2 - [2, 2, 3, 2, 1]……那么我需要做的就是处理这些数据并产生最终结果。

我尝试了很多设计,我的主要痛点是我为每个 requestType 收集的大量数据点,以及实例之间的通信费用。 我会在下面解释我目前的设计,但我也想知道是否有更好的设计或者一些奇特的算法可以聚合直方图?

目前最有希望的是:每个前端实例都会将其数据发送到中间层实例队列的随机实例。在这个中间层队列中,每个实例都会聚合它在短时间内获得的所有数据点,例如5秒。 (它没有足够的内存来保存更长时间)。然后中间层实例将聚合后的数据通过 requestTypes 的哈希值分发给后端实例。这意味着所有中间层实例都会将相同请求类型的数据点发送到相同的后端实例。然后在后端实例中,我可以使用第三方的直方图容器(CodaHale 的直方图或 HdrHistogram)来计算传入数据点的 P50、P90、P99 ......我需要中间层实例队列的原因是从前端发送数据-终端实例很昂贵,所以我希望一次发送所有数据,但不要进行 100 次调用以发送到 100 个不同的后端实例。

这个设计我可能想到的主要问题是复杂度比较高,如果有一个back-instance宕机,我可能会丢失一些requestTypes的所有数据。 那么对于系统设计部分,有人有更好的想法吗?

我正在考虑的另一种方法是找到一种奇特的算法来聚合现有的直方图。上面的设计,我得到的数据将是 100% 准确的。但实际上我可以容忍一些错误。比如在 CodaHale 的直方图和 HdrHistogram 中,我确信它们实际上并没有保存所有数据点,而是应用了一些高级数学算法,以非常低的成本获得了相对高精度的结果。我可以在前端或中间层实例中使用直方图库。但问题是,虽然我可以以低成本获得每个前端实例或中间层实例的 [P50, P90, P99...],但我找不到聚合它们的方法。因为不同的前端实例可能会处理不同类型的请求,并且请求到前端实例的分布是未知的,所以简单计算ALL P50、P90、P99的平均值会有很大的不准确。 那么有谁知道,我怎样才能将多个 CodaHale 的直方图或 HdrHistogram 聚合在一起?或者是否有任何算法可以帮助将直方图聚合为一个?

================================================ ==========================

昨晚我有了一些新想法。由于 P50 和 P90 正在测量所有数据的“平均值”,我认为在每个中间层实例中计算的所有 P50 和 P90 上简单地应用加权平均值应该足够好。但是 P99、P99.9 和 P99.99 正在测量那些离群数据,因此子集的 P99 的平均值可能不准确。

但是如果假设中间层实例中的数据是相对随机分布的,我可以在每个中间层实例中获取前 5% 的数据点,并将它们发送到后端。每个中间层数据点的 5% 加起来是总数据点的 5%。而且我更有信心,这5%数据的P80接近整体数据的P99,这5%数据的P98接近整体数据的P99.9,5%数据的P99.8接近P99 .99 的整体数据。

我希望通过这种方式,我只能传输整体数据的 5%,但得到一个高精度的结果。你怎么看这种方式?

【问题讨论】:

  • 您说For any request, every single instance will have a response time. 在我看来就像每个实例都会处理您广播的每个请求,但稍后您说:Because different front-end instance may handle different types of requests, and the distribution of requests to front-end instances are unknown[...] 这意味着其他内容。你能解释一下请求处理是如何工作的吗?
  • 您实际上是否将响应时间作为整数(或者您是否四舍五入为整数)?这表明(使用计数排序或类似的东西)并使用 RLE 对数据进行编码应该会大大加快通信速度。
  • 当向前端队列发出请求时,系统会选择一个实例来处理该请求。这是一个黑匣子,所以我不知道哪个实例会处理请求。但可以肯定的是,只有一个实例可以处理一个请求。
  • 要以快速(但仍然不准确)的方式计算总百分位数,您可以使用百分位数的加权(!)平均值(您的直方图包括前端测量的响应时间总数例如,因此您可以使用它来获得比仅取平均值更好的近似值)。但是我还不太明白为什么你不能在单个后端实例收集单个请求类型的所有数据并在那里生成一个新的直方图(包括百分位数的 100% 准确计算)
  • 谢谢,我可以将所有数据点收集到一个 requestType 的后端实例中,就像我目前的设计一样。但我还是想知道是否有更好的方法,可以显着降低复杂度和使用的资源,但又不会损失太多的准确性。

标签: algorithm histogram distribution aggregation codahale-metrics


【解决方案1】:

系统设计:

如果调用很昂贵,那么也许您可以流式传输数据?我在您的描述中没有看到这个中间层的真正好处 - 为什么前端->中间层调用成本低于前端->后端?

如果您担心丢失数据,您有两种选择:

  • 向多个节点发送事件。但在处理它们时,您需要以某种方式避免重复。
  • 将所有内容写入持久日志(Kafka 可以在这里完成工作)

这完全取决于事件量(1/分钟/前端或 10k/s/前端)以及前端和后端之间的距离(相同的数据中心或移动设备 -> 数据中心?)。

如果它是同一个数据中心,您可以通过持久日志与后端进行通信 - 这解决了数据丢失问题。 如果有很多事件,您可以在前端聚合它们并将聚合推送到下游

聚合:

有多种算法,例如q-摘要,t-摘要。见Quantiles over Data Streams: An Experimental Study

另外值得注意的是 HdrHistograms can be combined

【讨论】:

    最近更新 更多