MQ - 队列数据压缩

MQ - Data Compression on queue

问题:MQ7 有最大 100MB jms 消息的硬性限制。对于接近那个的大负载 ( xml ),是否可以在队列上对其进行压缩以缩短数据长度?

我尝试在 svr.def.conn 通道上使用 MQ ZLIB 压缩来压缩 7MB 的 jms 字符串消息,但它对 jms 消息的数据长度没有任何影响。我只设置了一个通道,并期望使用的通道会压缩进入队列的数据。

MQ 服务器:7.5 客户:JAVA 消息类型:字符串

通道级压缩用于压缩在通道两端之间传输的数据,在您的例子中是在 JMS 客户端和 MQ SVRCONN 通道之间。消息本身在通过网络传输时会被压缩,但在队列中时不会。

我建议压缩负载并使用 ByteMessage。消息属性可用于限定负载类型,类似于 HTTP,例如"Content-Encoding"、"Content-Type"

String payload = ...; // the xml

Session session = ...;
BytesMessage bytesMessage = session.createBytesMessage();

bytesMessage.writeBytes(compressGZIP(payload, StandardCharsets.UTF_8));
bytesMessage.setStringProperty("Content-Encoding", "gzip");
bytesMessage.setStringProperty("Content-Type", "text/xml; charset=utf-8");

这里是压缩GZIP的方法:

private byte[] compressGZIP(String string, Charset charset) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    try (GZIPOutputStream out = new GZIPOutputStream(byteArrayOutputStream)) {
        StringReader stringReader = new StringReader(string);
        // IOUtils from apache commons-io
        IOUtils.copy(stringReader, out, charset);
    }
    return byteArrayOutputStream.toByteArray();
}

消费者然后可以请求消息属性,根据 "Content-Encoding" 和 "Content-Type" 消息属性解压缩并重新创建 xml。

像这样

public void onMessage(Message message) {
    BytesMessage bytesMessage = (BytesMessage) message;

    long bodyLength = bytesMessage.getBodyLength();
    byte[] rawPayload = new byte[(int) bodyLength];
    InputStream payloadInputStream = new ByteArrayInputStream(rawPayload);

    String contentEncoding = bytesMessage.getStringProperty("Content-Encoding");
    if("gzip".equals(contentEncoding)) {
        payloadInputStream = new GZIPInputStream(payloadInputStream);
    }

    String contentType = bytesMessage.getStringProperty("Content-Type");
    MimeType mimeType = new MimeType(contentType); // from javax.activation

    if("text".equals(mimeType.getPrimaryType())) {
        if("xml".equals(mimeType.getSubType())) {
            Charset charset;

            String charsetString = mimeType.getParameter("charset");
            if(charsetString != null) {
                charset = Charset.forName(charsetString);
            } else {
                charset = StandardCharsets.UTF_8; // default
            }

            Reader reader = new InputStreamReader(payloadInputStream, charset);

            String xml = IOUtils.toString(reader);
            IOUtils.closeQuietly(reader);
        }
    }
}

此解决方案的优点是您可以使用标准 JMS api,而不是使用提供程序特定的配置。

缺点是发送方和接收方必须实现内容类型处理。

因此您必须在可移植性和实施工作之间做出决定。