消息的发送策略
- 持久化消息
默认情况下,生产者发送的消息是持久化的。消息发送到broker以后,producer会等待broker对这条消息的处理情况的反馈可以设置消息发送端发送持久化消息的异步方式
// 持久化消息 异步发送(默认同步)
connectionFactory.setUseAsyncSend(false);
// 回执窗口大小设置, 消费端不可能一直发,缓冲区存不了
connectionFactory.setProducerWindowSize(1024);
- 非持久化消息
非持久化消息模式下,默认就是异步发送过程,如果需要对非持久化消息的每次发送的消息都获得broker的回执的话
// 非持久化消息 同步发送(默认异步)
connectionFactory.setAlwaysSyncSend(true);
...
// 非持久化消息
textMessage.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
consumer获取消息是pull/push
默认情况下,mq服务器(broker)采用异步方式向客户端主动推送消息(push)。也就是说broker在向某个消费者会话推送消息后,不会等待消费者响应消息,直到消费者处理完消息以后,主动向broker返回处理结果
协议更改
更改配置activemq.xml文件,添加
<transportConnector name="nio" uri="nio://0.0.0.0:55555?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
代码即可用
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("nio://176.16.0.135:55555");
ActiveMQ持久化存储
- kahaDB
默认的存储方式 - AMQ 基于文件的存储方式
写入速度很快,容易恢复。
文件默认大小是32M - JDBC 基于数据库的存储
具体实现: - LevelDB
5.8以后引入的持久化策略。通常用于集群配置
ActiveMQ的网络连接
用来配置broker与broker之间的通信连接
静态网络连接
修改activemq.xml,增加如下内容(每个主机都需要配置
)
主机192.168.1.103配置
<networkConnectors>
<networkConnector uri="static:(tcp://192.168.1.103:61616,tcp://192.168.1.104:61616)"/>
</networkConnectors>
主机192.168.1.104配置
<networkConnectors>
<networkConnector uri="static:(tcp://192.168.1.104:61616,tcp://192.168.1.103:61616)"/>
</networkConnectors>
测试一,页面测试
测试:192.168.1.103
测试:192.168.1.104
测试二,代码测试
192.168.1.103 生产消息2个
生产者代码
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JmsSender {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.1.103:61616");
System.out.println(connectionFactory);
Connection connection = null;
try {
// 创建连接
connection = connectionFactory.createConnection();
connection.start();
// 创建会话
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 创建队列,第一次才创建,first-queue表示名称,destination表示目的地
Destination destination = session.createQueue("first-queue");
MessageProducer producer = session.createProducer(destination);
TextMessage textMessage = session.createTextMessage();
for (int i = 0; i < 1; i++) {
textMessage.setText("这是我的消息: " + i);
textMessage.setStringProperty("name", "张三");
producer.send(textMessage);
}
session.commit();
session.close();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
}
}
192.168.1.104 消费消息2个
当前192.168.1.104主机显示没有任务
消费者代码
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JmsReceiver {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.1.104:61616");
System.out.println(connectionFactory);
Connection connection = null;
try {
// 创建连接
connection = connectionFactory.createConnection();
connection.start();
// 创建会话
Session session = connection.createSession(Boolean.TRUE, Session.CLIENT_ACKNOWLEDGE);
// 创建队列,第一次才创建,first-queue表示名称,destination表示目的地
Destination destination = session.createQueue("first-queue");
MessageConsumer consumer = session.createConsumer(destination);
for (int i = 0; i < 1; i++) {
TextMessage message = (TextMessage) consumer.receive();
String text = message.getText();
String name = message.getStringProperty("name");
System.out.println(text);
System.out.println(name);
}
session.commit();
session.close();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
}
}
- 先消费一个
192.168.1.103上面已经没有任务了,任务转移了
192.168.1.104上面还剩下一个任务
- 192.168.1.104继续消费
消费完成。
当192.168.1.104上面还有一个任务时候,192.168.1.103可以消费吗,答案是不可以,将出现丢失消息
丢失的消息
一些consumer连接到broker1、消费broker2上的消息。消息先被broker1从broker2消费掉,然后转发给这些consumers。假设,转发消息的时候broker1重启了,这些consumers发现brokers1连接失败,通过failover连接到broker2.但是因为有一部分没有消费的消息被broker2已经分发到broker1上去了,这些消息就好像消失了。除非有消费者重新连接到broker1上来消费
从5.6版本开始,在destinationPolicy上新增了一个选项replayWhenNoConsumers属性,这个属性可以用来解决当broker1上有需要转发的消息但是没有消费者时,把消息回流到它原始的broker。同时把enableAudit设置为false,为了防止消息回流后被当作重复消息而不被分发
通过如下配置,在activeMQ.xml中。 分别在两台服务器都配置。即可完成消息回流处理
修改activemq.xml下的<policyEntries>
下
<policyEntry queue=">" enableAudit="false">
<networkBridgeFilterFactory>
<conditionalNetworkBridgeFilterFactory replayWhenNoConsumers="true"/>
</networkBridgeFilterFactory>
</policyEntry>
解决上面上一个问题
192.168.1.103 (显示了三条消费)
192.168.1.104 (显示了二条消费)