在 WebLogic 中配置 JMS 消息大小:weblogic.socket.MaxMessageSizeExceededException

Posted

技术标签:

【中文标题】在 WebLogic 中配置 JMS 消息大小:weblogic.socket.MaxMessageSizeExceededException【英文标题】:Configuring JMS Message Size in WebLogic: weblogic.socket.MaxMessageSizeExceededException 【发布时间】:2012-08-20 05:58:34 【问题描述】:

我目前有两个客户端(生产者/消费者),我正在尝试通过 JMS 发送一个大文件。我成功地生成文件并将其发送到 JMS 服务器,没有任何问题。问题是当我尝试使用消息时,我得到以下异常:

Aug 24, 2012 11:25:37 AM client.Client$1 onException
SEVERE: Connection to the Server has been lost, will retry in 30 seconds. weblogic.jms.common.LostServerException: java.lang.Exception: weblogic.rjvm.PeerGoneException: ; nested exception is: 
    weblogic.socket.MaxMessageSizeExceededException: Incoming message of size: '10000080' bytes exceeds the configured maximum of: '10000000' bytes for protocol: 't3'
<Aug 24, 2012 11:25:37 AM CDT> <Error> <Socket> <BEA-000403> <IOException occurred on socket: Socket[addr=127.0.0.1/127.0.0.1,port=7001,localport=51764]
 weblogic.socket.MaxMessageSizeExceededException: Incoming message of size: '10000080' bytes exceeds the configured maximum of: '10000000' bytes for protocol: 't3'.
weblogic.socket.MaxMessageSizeExceededException: Incoming message of size: '10000080' bytes exceeds the configured maximum of: '10000000' bytes for protocol: 't3'
    at weblogic.socket.BaseAbstractMuxableSocket.incrementBufferOffset(BaseAbstractMuxableSocket.java:174)
    at weblogic.rjvm.t3.MuxableSocketT3.incrementBufferOffset(MuxableSocketT3.java:351)
    at weblogic.socket.SocketMuxer.readFromSocket(SocketMuxer.java:983)
    at weblogic.socket.SocketMuxer.readReadySocketOnce(SocketMuxer.java:922)

我相信这与我在 WebLogic 中的 MaxMessage 大小设置有关,而不是代码问题(但我当然可能是错的)。这是我对最大消息大小的设置

我不确定为什么会收到此异常,因为此协议的最大消息大小大于异常声称的大小...有什么想法吗?

我也尝试添加服务器启动参数 -Dweblogic.MaxMessageSize=200000000,但无济于事。

这是我设置 MessageListener 和消息使用者本身的一些代码。

public boolean setClient(MessageListener listener) 

        try 
            Properties parm = new Properties();
            parm.setProperty("java.naming.factory.initial",
                    "weblogic.jndi.WLInitialContextFactory");
            parm.setProperty("java.naming.provider.url", iProps.getURL());
            parm.setProperty("java.naming.security.principal", iProps.getUser());
            parm.setProperty("java.naming.security.credentials",
                    iProps.getPassword());
            ctx = new InitialContext(parm);
            final QueueConnectionFactory connectionFactory = (QueueConnectionFactory) ctx
                    .lookup(iProps.getConFactory());
            connection = connectionFactory.createQueueConnection();
            ((WLConnection) connection)
                    .setReconnectPolicy(JMSConstants.RECONNECT_POLICY_ALL);
            ((WLConnection) connection).setReconnectBlockingMillis(30000L);
            ((WLConnection) connection).setTotalReconnectPeriodMillis(-1L);
            session = connection.createQueueSession(false,
                    Session.AUTO_ACKNOWLEDGE);
            queue = (Queue) ctx.lookup(iProps.getQueue());
            // The following code in the switch statement is the only code that
            // differs for the producer and consumer.
            switch (cType)
                
                case PRODUCER: 
                    producer = (WLMessageProducer) session
                            .createProducer(queue);
                    // Setting to send large files is done in WebLogic
                    // Administration Console.
                    // Set
                    producer.setSendTimeout(60000L);
                    break;
                
                case CONSUMER: 
                    consumer = session.createConsumer(queue);
                    if (listener != null) 
                        consumer.setMessageListener(listener);
                    else
                        log.warning("A Message listener was not set for the consumer, messages will not be acknowledged!");
                    
                    break;
                
                default:
                    log.info("The client type " + cType.toString()
                            + " is not currently supported!");
                    return false;
                

            connection.setExceptionListener(new ExceptionListener() 
                @Override
                public void onException(JMSException arg0) 
                    Logger log2 = new MyLogger().getLogger("BPEL Client");
                    if (arg0 instanceof LostServerException) 
                        log2.severe("Connection to the Server has been lost, will retry in 30 seconds. "
                                + arg0.toString());
                     else 
                        log2.severe(arg0.toString());
                    

                
            );
            shutdownListener = new ShutdownListener(connection, session, producer, consumer);

            connection.start();
            log.info("Successfully connected to " + iProps.getURL());
            return true;
         catch (JMSException je) 
            log.severe("Could not connect to the WebLogic Server, will retry in 30 seconds. "
                    + je.getMessage());
            try 
                Thread.sleep(30000L);
             catch (InterruptedException e) 
                log.warning(e.toString());
            
            return setClient(listener);
         catch (Exception e) 
            log.severe("Could not connect to the WebLogic Server, will retry in 30 seconds. "
                    + e.toString());
            try 
                Thread.sleep(30000L);
             catch (InterruptedException ie) 
                log.warning(ie.toString());
            
            return setClient(listener);

        
    

这是消息监听器:

public class ConsumerListener implements MessageListener 
    private Logger log;
    private File destination;
    private Execute instructions;

    public ConsumerListener(Execute instructions, File destination) 
        this.instructions = instructions;
        this.destination = destination;
        log = new MyLogger().getLogger("BPEL Client");
    

    @Override
    public void onMessage(Message arg0) 

        try 
            if (arg0.getJMSRedelivered()) 
                log.severe("A re-delivered message has been received, and it has been ignored!"
                        + arg0.toString());
             else 
                try 
                    if (arg0 instanceof TextMessage) 
                        consumeMessage((TextMessage) arg0);

                     else if (arg0 instanceof BytesMessage) 
                        consumeMessage((BytesMessage) arg0);
                     else 
                        log.warning("Currently, only TextMessages and BytesMessages are supported!");
                    
                 catch (JMSException e) 
                    log.severe(e.toString());
                 catch (IOException e) 
                    log.severe(e.toString());
                 catch (Throwable t) 
                    log.severe(t.toString());
                
            
         catch (JMSException e) 
            log.severe(e.toString());
        
    

    /**
     * Unwraps the JMS message received and creates a file and a control file if
     * there are instructions present.
     *
     * @param textMessage
     *            JMS message received to be consumed.
     * @throws JMSException
     * @throws IOException
     */
    protected void consumeMessage(TextMessage textMessage) throws JMSException,
            IOException 
        // ***All properties should be lowercase. for example fileName
        // should be
        // filename.***
        String fileName = textMessage.getStringProperty("filename");
        if (fileName == null || fileName.isEmpty()) 
            fileName = textMessage.getStringProperty("fileName");
        
        if (fileName != null && !fileName.isEmpty()) 
            // Check if the
            // file name is equal to the shutdown file. If it
            // is, shutdown the consumer. This is probably not a good way to
            // do this, as the program can no longer be shutdown locally!

            // We have a file in the queue, need to create the file.
            createFile(destination.getAbsolutePath() + "\\" + fileName,
                    textMessage.getText());
            log.info("Done creating the file");
            String inst = textMessage.getStringProperty("instructions");
            // If there are instructions included, then create the
            // instruction file, and route the message based on this file.
            if (inst != null && !inst.isEmpty()) 
                // We need to rout the file.
                log.info("Instructions found, executing instructions");
                String[] tokens = fileName.split("\\.");
                String instFileName = "default.ctl";
                if (tokens.length == 2) 
                    instFileName = tokens[0] + ".ctl";
                
                File controlFile = createFile(destination.getAbsolutePath()
                        + "\\" + instFileName, inst);
                Control control = new Control(controlFile);
                instructions.execute(control);
                log.info("Done executing instructions");
             else 
                log.info("No instructions were found");
            
            log.info("Done consuming message: " + textMessage.getJMSMessageID());
        

    

    /**
     * Unwraps the JMS message received and creates a file and a control file if
     * there are instructions present.
     *
     * @param bytesMessage
     *            The bytes payload of the message.
     * @throws JMSException
     * @throws IOException
     */
    protected void consumeMessage(BytesMessage bytesMessage)
            throws JMSException, IOException 
        // ***All properties should be lowercase. for example fileName
        // should be
        // filename.***
        log.info("CONSUME - 1");
        String fileName = bytesMessage.getStringProperty("filename");
        if (fileName == null || fileName.isEmpty()) 
            fileName = bytesMessage.getStringProperty("fileName");
        
        if (fileName != null && !fileName.isEmpty()) 
            // Check if the
            // file name is equal to the shutdown file. If it
            // is, shutdown the consumer. This is probably not a good way to
            // do this, as the program can no longer be shutdown locally!

            // We have a file in the queue, need to create the file.
            byte[] payload = new byte[(int) bytesMessage.getBodyLength()];
            bytesMessage.readBytes(payload);
            createFile(destination.getAbsolutePath() + "\\" + fileName, payload);
            log.info("Done creating the file");
            String inst = bytesMessage.getStringProperty("instructions");
            // If there are instructions included, then create the
            // instruction file, and route the message based on this file.
            if (inst != null && !inst.isEmpty()) 
                // We need to rout the file.
                log.info("Instructions found, executing instructions");
                String[] tokens = fileName.split("\\.");
                String instFileName = "default.ctl";
                if (tokens.length == 2) 
                    instFileName = tokens[0] + ".ctl";
                
                File controlFile = createFile(destination.getAbsolutePath()
                        + "\\" + instFileName, inst);
                Control control = new Control(controlFile);
                instructions.execute(control);
                log.info("Done executing instructions");
             else 
                log.info("No instructions were found");
            
            log.info("Done consuming message: "
                    + bytesMessage.getJMSMessageID());
        

    

    /**
     * Creates a file with the given filename (this should be an absolute path),
     * and the text that is to be contained within the file.
     *
     * @param fileName
     *            The filename including the absolute path of the file.
     * @param fileText
     *            The text to be contained within the file.
     * @return The newly created file.
     * @throws IOException
     */
    protected File createFile(String fileName, String fileText)
            throws IOException 
        File toCreate = new File(fileName);
        FileUtils.writeStringToFile(toCreate, fileText);
        return toCreate;
    

    /**
     * Creates a file with the given filename (this should be an absolute path),
     * and the text that is to be contained within the file.
     *
     * @param fileName
     *            The filename including the absolute path of the f ile.
     * @param fileBytes
     *            The bytes to be contained within the file.
     * @return The newly created file.
     * @throws IOException
     */
    protected File createFile(String fileName, byte[] fileBytes)
            throws IOException 
        File toCreate = new File(fileName);
        FileUtils.writeByteArrayToFile(toCreate, fileBytes);
        return toCreate;
    

【问题讨论】:

您可以尝试更改集群中的广播类型。如果已设置为UNICAST,请忽略。 我已经发现了问题,我没有在客户端应用程序上设置 -Dweblogic.MaxMessageSize,现在它可以正常工作了。 【参考方案1】:

您还必须从 WLS 控制台增加最大消息大小,如屏幕截图中所示所有托管服务器

然后重新启动,问题就解决了。

此外,还有第二种替代解决方案。根据Oracle Tuning WebLogic JMS Doc:

调整 MessageMaximum 限制

如果推送给消费者的消息的总大小大于当前协议的最大消息大小(默认大小为 10 MB,并且使用控制台基于每个 WebLogic Server 实例配置,使用控制台基于每个客户端配置) Dweblogic.MaxMessageSize 命令行属性),消息传递失败。

在客户端上设置最大消息大小

在发送和接收大型消息时,除了 WebLogic Server 实例之外,您可能还需要配置 WebLogic 客户端。要在客户端上设置最大消息大小,请使用以下命令行属性:

-Dweblogic.MaxMessageSize

注意:此设置适用于所有传送到客户端的 WebLogic Server 网络数据包,而不仅仅是 JMS 相关数据包

已编辑:

可以通过执行以下一项或多项操作来解决此问题。

配置系统属性 -Dweblogic.MaxMessageSize 使用 WLS 控制台为管理员和所有托管服务器增加最大消息大小。 WLS 控制台中的步骤是:服务器/协议/常规 从 WLS 控制台增加最大消息大小。 WLS 控制台中的步骤是:队列/配置/阈值和配额/最大消息大小

PROCEDURE 用于应用 weblogic.MaxMessageSize 属性

保留 setDomainEnv 文件的备份。停止所有服务器。在每个 setDomainEnv 文件中添加 -Dweblogic.MaxMessageSize=yourValue,更具体地说,在 EXTRA_JAVA_PROPERTIES 行中添加。然后先启动 ADMIN,当 ADMIN 处于 RUNNING 状态时,再启动 MANAGED 服务器。

我希望这会有所帮助。

【讨论】:

感谢您的回复,虽然我已经尝试了这两种方法,但问题仍然存在。我不明白的是为什么我可以产生一个大的 JMS 消息并把它放在队列中,但我不能消费完全相同的 JMS 消息? 我已经更新了帖子。您是否尝试了所有 3 种可用的解决方案,但都没有解决您的问题?您是否从管理服务器和所有托管服务器中的 WLS 控制台配置了最大消息大小?谢谢 我已经尝试了所有 3 个选项,唯一不确定我是否正确执行的选项是系统属性。我用我在哪里设置属性的图像编辑了我的问题。这是正确的地方吗?进行更改后,我尝试重新启动服务器,但仍然收到相同的错误。 好像没问题。你能告诉我 WLS 版本吗? WebLogic 服务器版本:10.3.5.0【参考方案2】:

在我的情况下,设置 -Dweblogic.MaxMessageSize 解决了这个问题。我的问题是邮件大小的最大限制应该是多少?我们只是不能继续增加 消息大小来解决此问题。另外还有什么方法可以优化这个值 与某些其他值?

【讨论】:

这将是您必须通过找到您发送的最大消息来发现自己的东西。 如何找到最大的 t3 消息?我没有看到任何在 weblogic 中记录 t3 消息的机制。 您可以使用管理控制台监控队列,也可以使用企业管理器进行更图形化的布局,但 EM 主要用于实时查看流量。另一个选项是将值设置为最大可能数(可以在管理控制台上配置 MaxMessageSize 时找到)。如果您最大的消息超过该大小,那么 weblogic 将无法支持它。 在我的情况下实际上是 t3 消息,而不是 JMS 消息。我检查了 weblogic 控制台,找不到任何标志或任何配置可以帮助我记录或监控它。当然,通过增加它的大小它可以工作。但它更多的是打击和审判案件。我想知道它是如何随着我的远程数据大小的增加而增长的。任何指向记录或监视 t3 消息的任何机制的指针都将非常有帮助。我在官方weblogic论坛上问过同样的问题,但还没有得到任何答案。

以上是关于在 WebLogic 中配置 JMS 消息大小:weblogic.socket.MaxMessageSizeExceededException的主要内容,如果未能解决你的问题,请参考以下文章

获取Weblogic中JMS队列处理的消息的历史记录

Grails JMS插件到WebLogic JMS服务器

JMS 和 Weblogic 集群

如何从 weblogic JMS 队列集群环境中清除/删除消息

weblogic 与jms事例配置

什么是国外 JMS 提供者? Weblogic 在 JMS 应用程序中的典型作用是什么?