【问题标题】:Is holding a java JMX connection open a good idea是持有一个 java JMX 连接打开一个好主意
【发布时间】:2014-07-17 10:42:08
【问题描述】:

我有一个支持网站,我想展示一些通过 JMX 从另一个 Java 应用程序收集的统计信息。我们注意到,在其他应用重新启动后,支持应用有时无法获取统计信息。我猜这是因为支持应用程序打开了与另一个应用程序的 JMX 连接并保持它。然后,每次您转到该页面以显示 JMX 统计信息时,它都会尝试使用连接来收集它们,但它失败了。

我的问题是,建立一个 JMX 连接并尝试确定何时应该重新连接它会更好吗?

或者每次我们加载带有 JMX 统计信息的页面时,我们是否应该创建一个新的 JMX 连接,然后在获得所需值后关闭它?

【问题讨论】:

    标签: java jmx


    【解决方案1】:

    据我所知,

    JMX 连接是 RMI 连接器对象,因此可以保存在客户端应用程序中。 + 使用心跳方式重新连接。

    这样我们可以避免重新建立非轻量级 RMI 连接的开销。

    参考:javax.management.remote.rmi.RMIConnector

    【讨论】:

    • 正确。但这仍然使它成为您需要深入思考的事情,而不是您可以应用模式的事情。尽可能长时间地保持打开状态:好主意。永远保持开放:坏主意。尽可能长时间地同时在 200 个不同的客户上打开它:非常糟糕的主意。
    • 连接数总是可以限制的。但我真的同意,尽可能长时间地保持开放:好主意 :)
    【解决方案2】:

    我们最终没有使用心跳,但在阅读了 Girish 的回答后,我们得出了以下结论

    public class JmxMetricsRetriever {
    
    private final JMXServiceURL jmxUrl;
    private final Map<String, Object> env;
    
    private MBeanServerConnection connection;
    
    private JmxMetricsRetriever(JMXServiceURL jmxUrl, Map<String, Object> env) {
        this.jmxUrl = jmxUrl;
        this.env = env;
        reconnect();
    }
    
    public synchronized Object getAttributeValue(String jmxObjectName, String attributeName) {
        try {
            if (connection == null) {
                reconnect();
            }
            try {
                return getAttributeValuePrivate(jmxObjectName, attributeName);
            } catch (ConnectException exc) {
                //This is to reconnect after the Server has been restarted.
                reconnect();
                return getAttributeValuePrivate(jmxObjectName, attributeName);
            }
        } catch (MalformedObjectNameException |
                AttributeNotFoundException |
                MBeanException |
                ReflectionException |
                InstanceNotFoundException |
                IOException ex) {
            throw new RuntimeException(ex);
        }
    }
    
    private synchronized Object getAttributeValuePrivate(String jmxObjectName, String attributeName) throws MalformedObjectNameException, MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException {
        ObjectName replication = new ObjectName(jmxObjectName);
    
        return connection.getAttribute(replication, attributeName);
    }
    
    private synchronized void reconnect() {
        logger.info(String.format("Reconnecting to [%s] via JMX", jmxUrl.toString()));
        try {
            JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, env);
            this.connection = jmxConnector.getMBeanServerConnection();
            jmxConnector.connect();
        } catch (IOException e) {
            //Log something but don't throw an exception otherwise our app will fail to start.
        }
    }
    
    public static JmxMetricsRetriever build(String url, String port, String user, String password) {
        try {
            JMXServiceURL jmxUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + url + ":" + port + "/jmxrmi");
            Map<String, Object> env = new HashMap<>();
            env.put(JMXConnector.CREDENTIALS, new String[]{user, password});
    
    
            return new JmxMetricsRetriever(jmxUrl, env);
        } catch (MalformedURLException ex) {
            throw new RuntimeException(ex);
        }
    }
    

    }

    当我们启动我们的应用程序时,我们会尝试创建一个 JMX 连接并保留它。每次获得 JMX 属性时,我们都会检查连接是否已创建(如果我们连接的服务器在我们启动服务时未启动,则可能不会创建)。然后尝试检索我们的属性。如果失败,请尝试重新连接并获取属性值。我们找不到更好的方法来测试 JMX 连接是否仍然可用,因此必须捕获异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-29
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      相关资源
      最近更新 更多