ActiveMQ is disconnected, the process crashes and exits after consumers reconnect for a period

problem

I recently encountered a problem (activemq version is 5.14.5). After the normal ActiveMQ is disconnected, because of the heartbeat detection and reconnection mechanism, using the failover method, consumers will actually continue to try to reconnect, and the process should always be existing. But the strange thing is that some process consumers will directly hang up after mq is disconnected, and there is no log output and no longer reconnect.
The main process is as follows. The consumer code is the code for setting up the MessageListener normally, so it will not be posted.

/**
 * @author ZZJ
 * @description:
 * @date 2020-9-9 9:46
 */
public class ActiveMQTest {
    
    

    public static void main(String[] args) {
    
    

        ActiveMQConsumer activeMQConsumer = new ActiveMQConsumer();
        activeMQConsumer.consume();
    }
}

the reason

Through comparison, it is found that only the process in which only the consumer thread runs independently will have such a problem. After a period of query, it is found that this is a problem of ActiveMQ's own reconnection mechanism.
The entire kimmking answer: link
is simple, since the ActiveMQ off, socket heartbeat can not get a response, it will disconnect after a period of time, but Normally, after you configure failover mode, ActiveMQ consumer client will then start a thread Keep trying to reconnect. Such as

failover:(tcp://broker1:61616,tcp://broker2:61616)?maxReconnectAttempts=1000&initialReconnectDelay=1000&maxReconnectDelay=300000"

After disconnecting from ActiveMQ, it will continue to select brokers from the list of broker URLs to reconnect. The parameter maxReconnectAttempts represents the maximum number of reconnections, initialReconnectDelay is the first reconnection time, which represents 1s after the first reconnection, and then after The reconnection time will be doubled every time, 1s, 2s, 4s, 8s, maxReconnectDelay is the maximum reconnection time.
But the reconnection thread is a daemon thread (Daemon Thread), to use a more popular metaphor, any daemon thread is the nanny of all non-daemon threads in the entire JVM: as long as there is no non-daemon thread in the current JVM instance , The daemon thread all work; only when the last non-daemon thread ends, the daemon thread ends with the JVM. The role of the daemon thread is to provide convenient services for the operation of other threads. The most typical application is the GC (garbage collector). When there is no non-daemon thread, the GC is naturally unnecessary and the process exits.
Therefore, the reason for this problem is very clear: If only the ActiveMQ consumer thread exists alone, the socket connection is disconnected when the heartbeat does not accept a response. Although there is a reconnection thread at this time, it cannot exist alone because it is a daemon thread. , JVM judges that there are no non-daemon threads, and the process naturally exits.

solve

the first method

Refer to the kimmking method, set the reconnect thread reconnectTaskFactory as a non-daemon thread

Add FailoverTransport.java under the path of activemq-all-5.8.0.jar!\org\apache\activemq\transport\failover

reconnectTaskFactory = new TaskRunnerFactory();
reconnectTaskFactory.setDaemon(false); // to set daemon=false by kimmking
reconnectTaskFactory.init();

I did not try this method because it is troublesome to modify the jar package, but it should be available.

The second method
is relatively simple and stupid. In fact, it is to set one more thread to make the non-daemon thread always exist. This method is not the best, but it can be used as needed, such as setting this thread to implement timing statistics. And output the number of successful consumption of consumers and other functions

/**
 * @author ZZJ
 * @description:
 * @date 2020-9-9 9:46
 */
public class ActiveMQTest {
    
    
    public  static AtomicInteger count = new AtomicInteger();
    public static void main(String[] args) {
    
    

        ActiveMQConsumer activeMQConsumer = new ActiveMQConsumer();
        activeMQConsumer.consume();

        new Thread(() ->{
    
    
            while (true) {
    
    
                System.out.println("I'm alive");
                System.out.println("当前消费了" + count + "条消息");
                try {
    
    
                    Thread.sleep(60000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

to sum up

In order to reproduce this problem, I temporarily set up a set of environmental tests. It turns out that the problem that can be reproduced is no longer a problem.
ActiveMQ is too old, throughput is average, maintenance is not good, there is not much information on the Internet, and messages may be lost. Unless it is a very old project, it is recommended to use a message queue such as RocketMQ

Guess you like

Origin blog.csdn.net/qq_35530005/article/details/108527136