2014-05-08 49 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.

相关问题