优雅关闭
优雅停机
Camel 支持使用 org.apache.camel.spi.ShutdownStrategy 实现可插拔的停机策略。它负责以优雅的方式关闭路由。其他资源仍将由 CamelContext 负责关闭。这样,可靠地正确关闭所有路由的问题就留给了 ShutdownStrategy。
Camel 在 org.apache.camel.impl.engine.DefaultShutdownStrategy 中提供了一个默认策略,能够完成这项工作。
默认停机策略
默认策略(DefaultShutdownStrategy)会以优雅的方式关闭路由:
- 按照与启动时相反的顺序关闭
- 在关闭之前,让待处理和当前正在处理的交换完成运行
- 使用 45 秒的超时时间(可配置),超时后将强制执行硬停机
这些设置均可配置,因此你可以更改超时时间,以及在超时的情况下是强制执行硬停机还是直接忽略。
停机过程中,该策略会将进度输出到日志:
2009-12-20 10:56:53,055 [main ] INFO DefaultCamelContext - Apache Camel (CamelContext:camel-1) is stopping
2009-12-20 10:56:53,056 [main ] INFO DefaultShutdownStrategy - Starting to graceful shutdown routes (timeout 45 seconds)
2009-12-20 10:56:53,059 [1: ShutdownTask] INFO DefaultShutdownStrategy - Waiting as there are still 5 inflight exchanges to complete before we can shutdown
2009-12-20 10:56:54,060 [1: ShutdownTask] INFO DefaultShutdownStrategy - Waiting as there are still 4 inflight exchanges to complete before we can shutdown
2009-12-20 10:56:55,061 [1: ShutdownTask] INFO DefaultShutdownStrategy - Waiting as there are still 3 inflight exchanges to complete before we can shutdown
2009-12-20 10:56:56,065 [1: ShutdownTask] INFO DefaultShutdownStrategy - Waiting as there are still 2 inflight exchanges to complete before we can shutdown
2009-12-20 10:56:57,066 [1: ShutdownTask] INFO DefaultShutdownStrategy - Waiting as there are still 1 inflight exchanges to complete before we can shutdown
2009-12-20 10:56:58,069 [main ] INFO DefaultShutdownStrategy - Graceful shutdown of routes complete in 5 seconds.
2009-12-20 10:56:58,072 [main ] INFO DefaultInflightRepository - Shutting down with no inflight exchanges.
2009-12-20 10:56:58,077 [main ] INFO DefaultCamelContext - Apache Camel (CamelContext:camel-1) stopped请注意,该策略会在仍有在途 Exchange 正在处理时先等待,然后再关闭路由,之后才关闭 Camel 本身。
由于超时导致所有在途消息无法全部完成而抑制日志输出
如果优雅停机无法在给定的超时期限内干净地完成,Camel 将执行更为强硬的停机(硬停机),强制关闭路由、线程池等,路由引擎也会拒绝继续处理 Exchange。发生这种情况时,你可能会看到关于 Exchange 被拒绝的 WARN 日志,以及因强制停机而导致的其他失败信息。
如果你不希望看到这些日志,可以将选项 suppressLoggingOnTimeout 设置为 true 来抑制它们。
- Java
- 应用属性
context.getShutdownStrategy().setSuppressLoggingOnTimeout(true);或者在 application.properties 中:
camel.main.shutdownSuppressLoggingOnTimeout = true请注意,抑制只是尽力而为的尝试,第三方库仍可能产生一些日志,这些是 Camel 无法控制的。
超时时记录在途交换消息信息
如果优雅关闭无法在给定的超时时间内干净地完成,Camel 将执行更强制的关闭操作,强制关闭路由和线程池等。当超时发生时,Camel 会记录当前在途(inflight)交换消息的信息,显示该交换消息来自哪条路由,以及当前正在哪条路由中传递。例如,下面的日志显示有 1 个在途交换消息,它来自 route1,目前仍在 route1 的 “delay1” 节点上。elapsed 表示在当前节点(例如 delay1)上停留的毫秒数,duration 表示总耗时的毫秒数。
如果你在 org.apache.camel.impl.engine.DefaultShutdownStrategy 上启用 DEBUG 日志级别,那么在优雅关闭期间也会记录相同的在途交换消息信息。
2015-01-12 13:23:23,656 [ - ShutdownTask] INFO DefaultShutdownStrategy -
There are 1 inflight exchanges: InflightExchange:
[exchangeId=ID-davsclaus-air-62213-1421065401253-0-3,
fromRouteId=route1, routeId=route1, nodeId=delay1, elapsed=2007,
duration=2017]如果您不想看到这些日志,可以将选项 shutdownLogInflightExchangesOnTimeout 设置为 false 来关闭它。
- Java
- 应用程序属性
context.getShutdownStrategy().setLogInflightExchangesOnTimeout(false);或者在 application.properties 中:
camel.main.shutdownLogInflightExchangesOnTimeout = falseJMX 管理
ShutdownStrategy 支持 JMX,因此你可以在 JMX 控制台中对其进行管理。这样就能够在运行时调整该策略。
超时设置也可以在 CamelContextMBean 上进行修改。 |
|---|
控制路由的顺序
你可以配置路由的启动顺序,从而也决定了它们关闭时的相同顺序。详情参见配置路由启动顺序与自动启动。
细粒度配置
你可以控制两个影响 Camel 路由优雅关闭的方面:
ShutdownRouteShutdownRunningTask
这些选项可以在两个层级上配置:context(上下文)和 route(路由)。路由层级优先于上下文层级,也就是说,如果在路由层级上没有显式配置,则使用上下文层级的配置。
ShutdownRoute
此选项用于控制给定路由在优雅关闭期间的行为。它有两个取值:Default 和 Defer。Default 显然是默认选项,让 Camel 尽早关闭该路由。Defer 则用于将该路由的关闭推迟到后续阶段。当其他路由依赖于它时,这就非常有用。例如,一个被其他路由重用的内部路由。
| 最好只对内部路由延迟关闭。公开路由应尽快关闭,否则它会不断接收新消息,从而延迟关闭过程;如果持续涌入大量新消息,甚至可能导致关闭超时。 |
|---|
ShutdownRunningTask
此选项用于控制给定路由消费者在关闭期间的行为。大多数路由消费者一次只处理一个任务(消息),但 Batch Consumer(批处理消费者)可以处理多条消息(一个批次)。此选项就是针对批处理消费者的。
默认值为 CompleteCurrentTaskOnly,表示当前进行中的任务(消息)将被完成,然后消费者才会关闭。另一个选项 CompleteAllTasks 则允许消费者在关闭前完成所有任务(消息)。例如,File 消费者会在关闭之前处理完它已拾取的所有待处理文件。
停止单个路由
可以使用 stopRoute(routeId) 方法停止(即执行优雅关闭)单个路由,如下所示:
camelContext.getRouteController().stopRoute(routeId);| 也可以通过 JMX 或 Hawtio 等外部工具来停止路由。 |
|---|
因异常停止并标记路由为失败
可以使用 stopRoute(routeId, cause) 方法停止并使单条路由失败(将执行优雅关闭),示例如下:
Exception cause = ...
camelContext.getRouteController().stopRoute(routeId, cause);这将停止路由,然后将该路由标记为失败,并附上导致失败的异常。
| 路由也可以通过 JMX 或外部工具(如 Hawtio)来停止和标记为失败。 |
|---|
实现自定义组件或 ShutdownStrategy
如果你要开发自己的 Camel 组件,或想实现自己的关闭策略,请阅读本节获取详细信息。
ShutdownStrategy
你可以通过实现 org.apache.camel.spi.ShutdownStrategy 接口来定义自己的关闭控制策略,并使用 setShutdownStrategy 方法将其设置到 CamelContext 上。
ShutdownAware
接口 org.apache.camel.spi.ShutdownAware 是一个可选接口,消费者可以实现它以在关闭过程中进行细粒度的控制。ShutdownStrategy 必须能够处理实现了该接口的消费者。引入此接口是为了适配诸如 SEDA 之类的内存型消费者,这类消费者的内部内存队列中可能积压了若干待处理消息。该接口的作用是让这些消费者能够控制关闭过程,从而处理完其待处理的消息。
方法 getPendingExchangesSize 应返回内存队列中待处理消息的数量。当不存在待处理和进行中的消息时,方法 deferShutdown 应返回 true,以将关闭推迟到后续阶段执行。
批处理消费者应当实现 ShutdownAware,以便正确支持 ShutdownRunningTask 选项。可参考 GenericFileConsumer 的示例。
评论
登录后参与评论
KnowForge