esper中使用过多的内存,同时使用上下文聚合超过60分钟的值

时间:2017-09-11 10:27:56

标签: esper

我想汇总一天中每小时的传感器值。时间信息来自事件流中的时间戳。为此,我创建了四个EPL语句:

  1. 第一个语句声明了一个按sensorId
  2. 分区事件的上下文
  3. 第二个语句检测特定传感器的事件流中的时刻何时发生变化,并在发生事件时发送事件
  4. 第三个语句是一个上下文声明,它通过sensorId和hourOfDay对事件进行分区。上下文的生命周期由第二个语句发布的事件控制。
  5. 最后一个语句使用语句#3中创建的上下文,并计算传感器值的总和。
  6. 我每2-6秒接收大约300个传感器的事件。我将esper 6.1.0嵌入到堆大小为8 GB的Java应用程序中。大约15分钟后,内存压力使得垃圾收集进入过载状态,导致应用程序无法使用。如果我删除了最后一个EPL语句,我的应用程序会再次正常运行。

    我对这种行为感到有些困惑。我认为当使用上下文时,esper不会在内存中累积事件。

    所以我的问题是:使用EPL,我如何执行简单的聚合(例如总和,平均),使内存消耗 O(n)而不是 O(n * t),其中 n 是传感器的数量,而 t 是时间窗口的长度? < / p>

    具体来说,这是我的EPL陈述。

    声明1:

    create context ctxPartitionById partition by sensorId from SensorEvent
    

    声明2:

    context ctxPartitionById
    INSERT INTO HourChanged
    SELECT
      E.sensorId as sensorId,
      prev(1, E.occurredAtHour) AS lastHour,
      E.occurredAtHour AS currentHour
    FROM SensorEvent#length(2) E
    WHERE E.occurredAtHour != prev(1, E.occurredAtHour)
    

    陈述3:

    create context ctxPartitionByIdAndHour
      context PartitionedByKeys
        partition by
          sensorId, currentHour from HourChanged,
          sensorId, occurredAtHour from SensorEvent,
      context InitiateAndTerm
        initiated by HourChanged as e1
        terminated by HourChanged(sensorId=e1.sensorId and lastHour=e1.currentHour)
    

    陈述4:

    context ctxPartitionByIdAndHour
    SELECT
      E.sensorId,
      E.occurredAtHour,
      SUM(E.value) AS sensorValueSum
    FROM SensorEvent E
    output last when terminated
    

    sensorId是实现Comparable的java类的实例。

    occurredAtHourjava.util.Date个实例。它的值是一个已经向下舍入到小时的时间戳。

    valuedouble

2 个答案:

答案 0 :(得分:0)

键控上下文不会忘记分区。所以你做“通过sensorId进行分区,来自HourChanged的currentHour,来自SensorEvent的sensorId,happenAtHour”,因为这是一个键控上下文(在顶部)分区键保持不变,因为引擎认为你总是在寻找下一个HourChanged事件。同样的关键。这意味着引擎会记住“sensorId”和“currentHour”的每种可能组合。所以这可能不是你想要的。有关此问题的提示位于解决方案模式页面中。

对于语句4,输出速率限制可能导致事件保留在内存中,因为默认情况下引擎会在终止时计算输出。请注意select子句如何选择事件属性。当您选择事件属性时,这些属性来自实际事件。相反,你可以简单地将它作为一个完全聚合的查询,因此它没有理由保留任何事件。

context ctxPartitionByIdAndHour
SELECT last(E.sensorId), last(E.occurredAtHour), SUM(E.value) AS sensorValueSum
FROM SensorEvent E
output last when terminated

您可以在解决方案模式中执行类似操作。 http://espertech.com/esper/solution_patterns.php#absence-11 http://espertech.com/esper/solution_patterns.php#semantic-window-2

答案 1 :(得分:0)

@Hint('enable_outputlimit_opt')添加到第四个和最后一个EPL语句可以解决问题。

当使用output last时,显然esper会将事件保留在内存中,除非存在此特定提示。请参阅esper文档中的5.7.3. Runtime Considerations