我正在使用Apache Camel连接到各种端点,包括JMS主题,并写入数据库。有时数据库连接失败(无论出于何种原因,数据库问题,网络blip等),主题订阅者的消息开始备份。在某个时刻,有许多消息备份等待写入数据库,应用程序抛出内存不足错误。到目前为止,我理解这一切。
我遇到的问题如下:当应用程序在最终放弃并接受内存不足之前疯狂地尝试垃圾收集时,应用程序停止工作,但仍处于活动状态。这意味着主题订阅者仍被JMS提供程序视为活动状态,但不会读取该主题之外的任何内容,因此提供程序开始对消息进行排队。最终,当最大深度耗尽时,提供者也会倒下。
如何将应用程序配置为在达到某个堆使用时断开连接,或者在内存不足时更快地自行终止?我相信有一些JVM参数允许应用程序在内存不足时更快地自杀,但我想知道这是否是最佳解决方案或是否有其他方法?
答案 0 :(得分:1)
首先,我认为您应该使用能够刷新失败连接的JDBC连接池。因此,您首先不要遇到所描述的场景。至少不是数据库/网络问题是短暂的。
接下来,我通过应用生产者流控制来保护消息代理(至少在ActiveMQ中调用它是如何)。即如果违反了某个内存阈值,则阻止消息生成者提交更多消息。如果阈值设置正确,那么这将阻止您的消息代理翻倒。
至于你原来的问题:我使用JMX来监控VM。如果是某个指标,例如内存,违反了一个阈值,然后您可以通过MBeans Camel公开的方式暂停或关闭路由或整个Camel上下文。
答案 1 :(得分:0)
您可以使用Camel上下文方法.stop()
,.start()
,.suspend()
和.resume()
控制(启动/停止和暂停/恢复)Camel路由。
您可以旋转一个监视当前VM内存的单独线程,并在满足特定条件时停止所需的路由。
new Thread() {
@Override
public void run() {
while(true) {
long free = Runtime.getRuntime().freeMemory();
boolean routeRunning = camelContext.isRouteStarted("yourRoute");
if (free < threshold && routeRunning) {
camelContext.stopRoute("yourRoute");
} else if (free > threshold && !routeRunning) {
camelContext.startRoute("yourRoute");
}
// Check every 10 seconds
Thread.sleep(10000);
}
}
}
正如在另一个答案中所评论的那样,依赖于此并不是特别健壮,但至少比获得OutOfMemoryException更强大。请注意,您需要.stop()
路由,.suspend()
不会释放资源,这意味着与队列提供程序的连接仍然是打开的,并且服务看起来像是为业务开放。
您也可以将路由作为路由本身错误处理的一部分来停止(这可能更强大,但是一旦错误被清除就需要手动干预以重新启动路由,或者定期检查错误是否有计划的路由条件仍然存在并重新启动路径(如果它已经消失)。要记住的是,您无法从当时为路径提供服务的同一线程停止路由,因此您需要旋转一个单独的线程来执行停止。例如:
route("sample").from("jms://myqueue")
// Handle SQL Exceptions by shutting down the route
.onException(SQLException.class)
.process(new Processor() {
// This processor spawns a new thread that stops the current route
Thread stop;
@Override
public void process(final Exchange exchange) throws Exception {
if (stop == null) {
stop = new Thread() {
@Override
public void run() {
try {
// Stop the current route
exchange.getContext().stopRoute("sample");
} catch (Exception e) {}
}
};
}
// start the thread in background
stop.start();
}
})
.end()
// Standard route processors go here
.to(...);