2014-02-06 36 views
1

我正在使用Apache Camel連接到各種端點(包括JMS主題)並寫入數據庫。有時數據庫連接失敗(無論出於何種原因,數據庫問題,網絡信號等)以及主題訂閱者的消息開始備份。在某個時候,有太多的消息備份等待寫入數據庫,導致應用程序拋出內存不足錯誤。到目前爲止,我明白這一點。當JVM達到某個堆大小時,如何停止駱駝路由?

我的問題是:當應用程序被瘋狂地試圖垃圾回收之前最終放棄並接受它是內存不足,應用程序將停止工作,但仍然活着。這意味着主題訂閱者仍然被JMS提供者看作活躍的,但沒有閱讀任何主題,所以提供者開始排隊消息。最終,當最大深度用完時,供應商也會倒下。

如何配置我的應用程序要麼斷開達到一定堆的使用情況時,或者殺死自己完全多少更快的運行時內存不足?我相信有一些JVM參數可以讓應用程序在內存不足時更快地自殺,但我想知道這是否是最佳解決方案或是否有其他方法?

回答

0

您可以控制使用駱駝上下文方法.stop().start().suspend().resume()(啓動/停止和暫停/恢復)駱駝的路線。

您可以旋轉一個單獨的線程來監視當前的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(...); 
1

首先,我認爲你應該使用能夠刷新失敗連接的JDBC連接池。所以你首先不會碰到描述的場景。至少在數據庫/網絡問題短暫時不會發生。

接下來我會通過將生產流程控制保護消息代理(至少多數民衆贊成它是如何在ActiveMQ的稱呼)。即防止消息生成者在違反某個內存閾值時提交更多消息。如果閾值設置正確,那麼這將防止您的消息代理崩潰。

至於你的原始問題:我會使用JMX監視虛擬機。如果某個度量,例如內存,違反閾值,則可以通過MBeans Camel公開的方式暫停或關閉路由或整個Camel環境。

+0

謝謝拉爾夫。不幸的是,在我目前的項目中(這是一個非常大的公司,有大量的文書工作),我不得不使用我提供的休眠配置和可用的消息代理。我會詢問是否讓他們設置了「流量控制」的等價物。爲了監控虛擬機,虛擬機是否有可能監控自己?可以有一個駱駝機制來開箱即用嗎?或者它是否必須是一個單獨的VM,通過JMX進行監控? – Matt

+1

是的,你可以監控自己,但我懷疑它會非常強大。當虛擬機負載不足時,您需要採取措施。這意味着需要採取行動的流程是已經超載的虛擬機的一部分。許多監控工具,例如[Hyperic](http://www.hyperic.com/),允許您通過JMX監控VM度量標準並自動觸發一個操作,例如如果閾值被破壞,則調用MBean上的方法。也許你應該和你的操作人員討論他們用什麼工具來監控你的生產環境。 – Ralf