单例模式解决RabbitMQ超出最大连接问题

今天在项目稳定性测试过程中遇到一个情景:通过工具jMeter一直请求消息转发服务器,消息转发服务器再向rabbitMQ发送数据,在这期间出现了问题、MQ意外宕机。

1. 查看rabbitMQ管理界面。如下图、rabbitMQ连接数不断往上涨。

 

2.初步定为为代码问题、通过分析工具代码发现:

public class MQSender extends BaseEndPoint {
    public MQSender(String endPointName) throws IOException{
        super(endPointName);
    }

    public void sendMessage(Serializable object) throws IOException {
        if (channel != null) {
            channel.basicPublish("", endPointName, MessageProperties.PERSISTENT_TEXT_PLAIN, SerializationUtils.serialize(object));
        }
    }
}

 项目中每次在调用时:

 MQSender mqSender = new MQSender(EnvConstant.NODE_PASS_QUEUE_NAME);

 通过代码不难发现mq的连接会最终撑爆,再通过linux命令nohup确定jar包错误:

java.util.concurrent.TimeoutException
	at com.rabbitmq.utility.BlockingCell.get(BlockingCell.java:77)
	at com.rabbitmq.utility.BlockingCell.uninterruptibleGet(BlockingCell.java:111)
	at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:37)
	at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:367)
	at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:293)
	at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:678)
	at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:722

3.解决:通过单例模式改造

 用“双重检查加锁”改造后的工具类:

 

/**
 * 用“双重检查加锁”,getMqSender()中减少使用同步
 * 利用双重检查加锁,首先检查是否实例已经创建,如果没有才同步。
 * 这样只有第一次才会同步。
 * @author monkjavaer
 * @date 2018/08/27 22:28
 */
public class MQSender extends BaseEndPoint {
    private volatile static MQSender mqSender;

    public static MQSender getMqSender(String endPointName) throws IOException {
        //如果实例不存在,进入同步区
        if (mqSender == null){
            //只有第一次才执行
            synchronized (MQSender.class){
                //进入区块再检查一次
                if (mqSender == null){
                    mqSender =new MQSender(endPointName);
                }
            }
        }
        return mqSender;
    }
    private MQSender(String endPointName) throws IOException{
        super(endPointName);
    }
    public void sendMessage(Serializable object) throws IOException {
        if (channel != null) {
            channel.basicPublish("", endPointName, MessageProperties.PERSISTENT_TEXT_PLAIN, SerializationUtils.serialize(object));
        }
    }
}
通过改写后mq正常使用。

 

posted @ 2018-09-08 21:41  monkjavaer  阅读(7574)  评论(0编辑  收藏  举报