2014-05-08 85 views
11

我與JMX監控Java應用程序啓用這樣的:允許與JMX監控重新啓動Java應用程序啓用立即

-Dcom.sun.management.jmxremote.port=9999 \ 
// some other properties omitted 

但是,當我嘗試重新啓動應用程序,有時我得到一個錯誤的JMX端口號說已在使用中。這是不可接受的。

所以我想爲底層套接字設置SO_REUSEADDR爲true來避免這個錯誤,但是沒有找到相關的JMX屬性。

有什麼想法?

+0

您是否看過使用該端口的應用程序? – BevynQ

+0

我必須是我的應用程序。當我停止應用程序時,我認爲綁定到這個端口的套接字實際上關閉了2MSL的TIME_WAIT狀態。所以我想讓這個端口可重用。 – George

+0

SO_REUSEADDR不能這樣工作。它允許套接字監聽特定的IP地址並忽略其他地址。要麼同一個應用程序運行兩次,要麼有另一個應用程序抓住這個端口。 – BevynQ

回答

6

恐怕你不能從命令行那樣做。

您將需要創建一個RMIServerSocketFactory,其中生成ServerSockets與所需的選項(SO_REUSEADDR)。

文檔瀏覽:http://docs.oracle.com/javase/8/docs/technotes/guides/rmi/socketfactory/

別人解決同樣的問題: https://svn.apache.org/viewvc?view=revision&revision=r1596579

+0

謝謝。恐怕這確實是唯一的解決方案。綜合起來,它比我想象的要冗長得多,但仍然比沒有更好。 – Boris

-1

添加一個關閉掛鉤上的應用程序,它會殺死JMX。

// kill process with port 9999  
fuser -k 9999/tcp 
+0

這將取決於平臺(在我的情況下這可以),但更重要的是它不起作用。通過fuser殺死進程似乎沒有改變有關SO_REUSEADDR的行爲。我嘗試了一個簡單的類,但仍然得到了BindException – Boris

1

是的,您應該以編程方式創建JMX連接器。 作爲更簡單的解決方法,如果默認端口正忙於死亡進程,則可以在運行時爲JMX選擇另一個端口。或者只是嘗試一次又一次地打開您的端口,直到成功。

這裏是我用來打開JConsole兼容的JMX連接器的代碼片段。在斯卡拉,對不起,但你應該能夠很容易地適應它

def startJmx(port: Int): Unit = { 
if (port < 1) { 
    return 
} 

val log = LoggerFactory.getLogger(getClass) 

log.info("Starting JMX server connector on port {}", port) 

val registry = LocateRegistry.createRegistry(port) 

val server = ManagementFactory.getPlatformMBeanServer() 

val url = new JMXServiceURL(s"service:jmx:rmi:///jndi/rmi://localhost:$port/jmxrmi") 

val connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, Collections.emptyMap(), server) 

val thread = new Thread { 
    override def run = try { 
    connectorServer.start() 
    } catch { 
    case e: Exception => log.error("Unable to start JMX connector", e) 
    } 
} 
thread.setDaemon(true) 
thread.setName("JMX connector Thread") 
thread.start() 
} 
0

我有同樣的問題。這是我的應用程序的第一個實例(我停止了),它仍然訂閱了此端口,所以新實例無法啓動。在我的情況下,它不需要使用套接字TIME_WAIT機制,而是在調用stop()之後,直到所有正在運行的線程都優雅地結束,花了一些時間。在我的情況下工作是在停止應用程序之前取消註冊bean,以便套接字是免費的。

private void unregisterBeanForName(String name) { 
     try { 

      JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.1:9999/jmxrmi"); 
      JMXConnector cc = JMXConnectorFactory.connect(jmxServiceURL); 
      MBeanServerConnection mbsc = cc.getMBeanServerConnection(); 
//This information is available in jconsole 
      ObjectName serviceConfigName = new ObjectName("YourObjectName"); 
      mbsc.unregisterMBean(serviceConfigName); 
// Close JMX connector 
      cc.close(); 
     } catch (Exception e) { 
      System.out.println("Exception occurred: " + e.toString()); 
      e.printStackTrace(); 
     } 
    } 
0

這可能是一個解決辦法: 在遠程服務器上,你可以有兩個端口:9999和9998轉〜9999

在每次重新啓動你的應用程序替代一個布爾值來決定連接到9999或9998.

相關問題