MQ消息中间件介绍及使用

MQ

全称Message Queue(消息队列),在分布式系统中有着广泛应用,满足异步、解耦等需求。消息中间件是分布式系统中接收和发送消息的基础软件,有很多,如RabbitMQ RocketMQ ActiveMQ Kafka等。

消息中间件可使系统间进行异步通讯,实现解耦。

JMS消息模型

JMS是JavaEE中的一个关于消息的规范,是一套与具体平台无关的API。

1、点对点或队列模型

JMS 点对点队列模型特点:

1、消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。

2、消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。

3、Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。

 

2、发布者/订阅者模型

JMS 发布/订阅模型特点:

消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。

发布到topic的消息会被所有订阅者消费。

实现了JMS规范的消息中间件产品:ActiveMQ、RocketMQ、RabbitMQ、HornetQ …

activeMQ安装

官网:http://activemq.apache.org

1、安装jdk,参见"linux/服务器搭建1.docx"

2、下载apache-activemq-5.11.1-bin.tar.gz,解压

如放到/root下

tar -zxf apache-activemq-5.11.1-bin.tar.gz

重命名解压后的目录

mv apache-activemq-5.11.1 activemq-01

 

3、进入activemq-01/bin,查看是否有执行启动脚本activemq文件的权限(绿色表示有),如果没有,则执行

chmod 755 activemq授权。

4、防火墙打开61616和8161端口,61616是消息通讯端口,在activemq-01/conf/activemq.xml中可以修改。8161是管理控制台的jetty端口,在activemq-01/conf/jetty.xml中配置。

 

5、启动服务,浏览器访问

进入bin目录启动

cd /root/activemq-01/bin/

./activemq start

 

浏览器即可访问

http://192.168.128.128:8161/

 

6、点击这里,默认密码是admin admin

 

7、配置安全机制

无安全机制情况下所有人都可以随意收发mq消息,不安全。因此需要配置安全机制,在conf/activemq.xml中</broker>结束标签之前增加如下配置:

    

<plugins>

    <simpleAuthenticationPlugin>

        <users>

            <authenticationUser username="wusc" password="wusc.123"

                groups="users,admins" />

        </users>

    </simpleAuthenticationPlugin>

</plugins>

定义了一个用户wusc,密码是wusc.123,角色是users,admins,表示程序连入mq服务器所需要的验证。

 

管控台的密码修改

1、确保conf/jetty.xml中securityConstraint下的authenticate是true

2、在conf/jetty-realm.properties下:

三列分别表示用户名、密码、角色

 

修改后重启jetty即可。

./activemq restart

 

java客户端

点对点模式

生产者producer配置

spring中配置:

 

    <!-- 真正可以产生ConnectionConnectionFactory,由对应的 JMS服务厂商提供 -->

    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">

        <!-- ActiveMQ服务地址 -->

<property name="brokerURL" value="${mq.brokerURL}" />

<property name="userName" value="${mq.userName}"></property>

<property name="password" value="${mq.password}"></property>

    </bean>

 

<!--

    ActiveMQ为我们提供了一个PooledConnectionFactory,通过往里面注入一个ActiveMQConnectionFactory

    可以用来将ConnectionSessionMessageProducer池化,这样可以大大的减少我们的资源消耗。

    要依赖于 activemq-pool

-->

    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">

        <property name="connectionFactory" ref="targetConnectionFactory" />

        <property name="maxConnections" value="${mq.pool.maxConnections}" />

    </bean>

 

    <!-- Spring用于管理真正的ConnectionFactoryConnectionFactory -->

    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">

        <!-- 目标ConnectionFactory对应真实的可以产生JMS ConnectionConnectionFactory -->

        <property name="targetConnectionFactory" ref="pooledConnectionFactory" />

    </bean>

    

    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->

    

    <!-- 队列模板 -->

    <bean id="activeMqJmsTemplate" class="org.springframework.jms.core.JmsTemplate">

     <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->

     <property name="connectionFactory" ref="connectionFactory"/>

     <property name="defaultDestinationName" value="${queueName}"></property>

    </bean>

类似于jdbc的配置,targetConnectionFactory配置mq的服务器地址,登录账号密码,

最终使用的是activeMqJmsTemplate,它实现了JmsTemplate

mq.pool.maxConnections是连接池数

queueName是队列名称,表示发送到哪一个队列

使用类:

@Service("mqProducer")

public class MQProducer {

    

    @Autowired

    private JmsTemplate activeMqJmsTemplate;

 

    /**

     * 发送消息.

     * @param mail

     */

    public void sendMessage(final MailParam mail) {

        activeMqJmsTemplate.send(new MessageCreator() {

            public Message createMessage(Session session) throws JMSException {

                return session.createTextMessage(JSONObject.toJSONString(mail));

            }

        });

        

    }

 

}

 

public class MQProducerTest {

    private static final Log log = LogFactory.getLog(MQProducerTest.class);

 

    public static void main(String[] args) {

        try {

            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");

            context.start();

 

            MQProducer mqProducer = (MQProducer) context.getBean("mqProducer");

            // 邮件发送

            MailParam mail = new MailParam();

            mail.setTo("wu-sc@foxmail.com");

            mail.setSubject("ActiveMQ测试");

            mail.setContent("通过ActiveMQ异步发送邮件!");

 

            mqProducer.sendMessage(mail);

 

            context.stop();

        } catch (Exception e) {

            log.error("==>MQ context start error:", e);

            System.exit(0);

        } finally {

            log.info("===>System.exit");

            System.exit(0);

        }

    }

}

执行后查看界面,就有记录了

各列分别表示:队列名、等待消费消息数、消息进入数、消费消息数

 

消费者consumer配置

spring配置类似生产者,只是多了消息目的地和listener配置

 

    

    <!--这个是sessionAwareQueue目的地 -->

    <bean id="sessionAwareQueue" class="org.apache.activemq.command.ActiveMQQueue">

        <constructor-arg>

            <value>${queueName}</value>

        </constructor-arg>

    </bean>

 

    <!-- 可以获取sessionMessageListener -->

    <bean id="consumerSessionAwareMessageListener" class="wusc.edu.demo.mqtest.listener.ConsumerSessionAwareMessageListener"></bean>

 

    <bean id="sessionAwareListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">

        <property name="connectionFactory" ref="connectionFactory" />

        <property name="destination" ref="sessionAwareQueue" />

        <property name="messageListener" ref="consumerSessionAwareMessageListener" />

    </bean>

queueName表示消息队列名。

 

mq.properties

## MQ

mq.brokerURL=tcp\://192.168.128.129\:61616

mq.userName=wusc

mq.password=wusc.123

mq.pool.maxConnections=10

#queueName

queueName=wusc.edu.mqtest.v1

 

 

 

监听listener

public class ConsumerSessionAwareMessageListener implements SessionAwareMessageListener<Message> {

 

    private static final Log log = LogFactory.getLog(ConsumerSessionAwareMessageListener.class);

 

    @Autowired

    private JmsTemplate activeMqJmsTemplate;

    @Autowired

    private Destination sessionAwareQueue;

    @Autowired

    private MailBiz bailBiz;

 

    public synchronized void onMessage(Message message, Session session) {

        try {

            ActiveMQTextMessage msg = (ActiveMQTextMessage) message;

            final String ms = msg.getText();

            log.info("==>receive message:" + ms);

            MailParam mailParam = JSONObject.parseObject(ms, MailParam.class);// 转换成相应的对象

            if (mailParam == null) {

                return;

            }

 

            try {

                bailBiz.mailSend(mailParam);

            } catch (Exception e) {

                // 发送异常,重新放回队列

//                activeMqJmsTemplate.send(sessionAwareQueue, new MessageCreator() {

//                    public Message createMessage(Session session) throws JMSException {

//                        return session.createTextMessage(ms);

//                    }

//                });

                log.error("==>MailException:", e);

            }

        } catch (Exception e) {

            log.error("==>", e);

        }

    }

}

收到消息后会自动调用onMessage,通过msg.getText()获取消息内容

运行消费者的main,启动监听,此时会立刻收到消息,界面变为:

等待消费消息变为0,消费者变为1,入列1,出列1

 

如果停止监听程序,消费者变为0

 

在监听程序开启的情况下,再发一条消息,消息会立刻被消费,界面变为:

增加了一个入列和出列数。

发布订阅模式

生产者producer配置

spring配置

    <!-- connection+topic=template,每个主题需要一个topicbean和一个templatebean -->

    

    <!-- connection连接-->

    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">

        <!-- ActiveMQ服务地址 -->

<property name="brokerURL" value="${mq.brokerURL}" />

<property name="userName" value="${mq.userName}"></property>

<property name="password" value="${mq.password}"></property>

    </bean>

 

<!-- 连接池 -->

    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">

        <property name="connectionFactory" ref="targetConnectionFactory" />

        <property name="maxConnections" value="${mq.pool.maxConnections}" />

    </bean>

 

    <!-- connectionFactory -->

    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">

        <property name="targetConnectionFactory" ref="pooledConnectionFactory" />

    </bean>

      

<!-- companyList start -->

<bean id="companyListTopic" class="org.apache.activemq.command.ActiveMQTopic">

<constructor-arg index="0" value="${company.list.topic}" />

</bean>

<bean id="companyListTemplate" class="org.springframework.jms.core.JmsTemplate">

<property name="connectionFactory" ref="connectionFactory" />    <!-- connectionFactory -->

<property name="defaultDestination" ref="companyListTopic" /> <!-- topic -->

<property name="pubSubDomain" value="true" /> <!-- 订阅发布模式 -->

<property name="receiveTimeout" value="10000" />

</bean>

<!-- companyList end -->

 

<!-- companyEdit start -->

<bean id="companyEditTopic" class="org.apache.activemq.command.ActiveMQTopic">

<constructor-arg index="0" value="${company.edit.topic}" />

</bean>

<bean id="companyEditTemplate" class="org.springframework.jms.core.JmsTemplate">

<property name="connectionFactory" ref="connectionFactory" /> <!-- connectionFactory -->

<property name="defaultDestination" ref="companyEditTopic" /> <!-- topic -->

<property name="pubSubDomain" value="true" /> <!-- 订阅发布模式 -->

<property name="receiveTimeout" value="10000" />

</bean>

<!-- companyEdit end -->

 

test.properties:

#mq

mq.brokerURL=tcp\://192.168.128.134\:61616

mq.userName=kkk

mq.password=kkk.123

mq.pool.maxConnections=10

company.list.topic=mvd.company.man.company.list.test

company.edit.topic==mvd.company.man.company.edit.test

java调用

            final String message = "查询公司信息,company=" + JSONObject.toJSON(company);

            LOGGER.info("发布company_listmq:{}", message);

            companyListTemplate.send(new MessageCreator() {

public Message createMessage(Session session) throws JMSException {

TextMessage msg = session.createTextMessage();

msg.setStringProperty("hello", "company_list"); // 设置消息属性

msg.setText(message); // 设置消息内容

return msg;

}

});

 

消费者consumer配置

spring配置

    

    <!-- 接收: connection+topic+自定义接收类MessageListener=ListenerContainer -->

    

    <!-- 配置JMS连接工厂 -->

    <bean id="connectionFactory"

        class="org.springframework.jms.connection.CachingConnectionFactory">

        <!-- Session缓存数量 -->

        <property name="sessionCacheSize" value="10" />

        <property name="clientId" value="${client.id}" /> <!-- 接收者ID -->

        <property name="targetConnectionFactory">

            <bean class="org.apache.activemq.ActiveMQConnectionFactory">

                <!-- MQ地址 -->

                <property name="brokerURL" value="${mq.brokerURL}" />

                <property name="userName" value="${mq.userName}"></property>

                <property name="password" value="${mq.password}"></property>

            </bean>

        </property>

    </bean>

 

    <!-- companyList start -->

    <!-- topic -->

    <bean id="companyListTopic" class="org.apache.activemq.command.ActiveMQTopic">

        <constructor-arg index="0" value="${company.list.topic}" />

    </bean>

    <!-- listener -->

    <bean id="companyListListener" class="com.mvd.erp.mq.CompanyListListener" />

    <!-- container -->

    <bean id="companyListListenerContainer"

        class="org.springframework.jms.listener.DefaultMessageListenerContainer">

        <property name="connectionFactory" ref="connectionFactory" /> <!-- connectionFactory -->

        <property name="destination" ref="companyListTopic" /> <!-- topic -->

        <property name="messageListener" ref="companyListListener" /> <!-- 自定义Listener -->

        <property name="pubSubDomain" value="true" /> <!-- 发布订阅模式 -->

        <!-- 消息持久化 -->

        <property name="subscriptionDurable" value="true" />

        <property name="receiveTimeout" value="10000" />

        <property name="clientId" value="${client.id}" /> <!-- 接收者ID -->

        <property name="durableSubscriptionName" value="${company.list.topic}" />

    </bean>

    <!-- companyList end -->

 

 

    <!-- companyEdit start -->

    <!-- topic -->

    <bean id="companyEditTopic" class="org.apache.activemq.command.ActiveMQTopic">

        <constructor-arg index="0" value="${company.edit.topic}" />

    </bean>

    <!-- listener -->

    <bean id="companyEditListener" class="com.mvd.erp.mq.CompanyEditListener" />

    <!-- container -->

    <bean id="companyEditListenerContainer"

        class="org.springframework.jms.listener.DefaultMessageListenerContainer">

        <property name="connectionFactory" ref="connectionFactory" /> <!-- connectionFactory -->

        <property name="destination" ref="companyEditTopic" /> <!-- topic -->

        <property name="messageListener" ref="companyEditListener" /> <!-- 自定义Listener -->

        <property name="pubSubDomain" value="true" /> <!-- 发布订阅模式 -->

        <!-- 消息持久化 -->

        <property name="subscriptionDurable" value="true" />

        <property name="receiveTimeout" value="10000" />

        <property name="clientId" value="${client.id}" /> <!-- 接收者ID -->

        <property name="durableSubscriptionName" value="${company.edit.topic}" />

    </bean>

    <!-- companyEdit end -->

listener类

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.TextMessage;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

 

/**

* @描述: companylisttopic监听器 .

*

*/

@Component

public class CompanyListListener implements MessageListener {

 

    private static final Logger LOGGER = LoggerFactory.getLogger(CompanyListListener.class);

 

    @Override

    public void onMessage(Message message) {

        TextMessage textMessage = (TextMessage)message;

        try {

            LOGGER.info("CompanyListListener收到消息,getText()={}, getStringProperty(\"hello\")={}", textMessage.getText(), message.getStringProperty("hello"));

        } catch (JMSException e) {

            LOGGER.error("接收消息失败", e);

        }

    }

}

 

test.properties

#mq

mq.brokerURL=tcp\://192.168.128.134\:61616

mq.userName=kkk

mq.password=kkk.123

client.id=mvd.erp.man

mq.pool.maxConnections=10

company.list.topic=mvd.company.man.company.list.test

company.edit.topic==mvd.company.man.company.edit.test

activeMQ集群

概念

三种集群方式:

共享文件目录、共享数据库、zookeeper+levelDB(基于可复制的levelDB)

主要是为了解决集群切换时的数据同步问题,单节点时默认采用共享文件目录方式。集群配置一般采用zookeeper+levelDB方式。

 

引用:

LevelDB 是 Google 开发的一套用于持久化数据的高性能类库。LevelDB 并不是一种服务,用户需要自

行实现 Server。是单进程的服务,能够处理十亿级别规模 Key-Value 型数据,占用内存小。

 

采用zookeeper只用用它提供主备功能,避免单点故障,不实现负载均衡等功能。

 

高可用的原理:

原理图:

使用 ZooKeeper(集群)注册所有的 ActiveMQ Broker(节点)。只有其中的一个 Broker 可以提供服务,被视为 Master,其他的 Broker 处于待机状态,被视为 Slave。如果 Master 因故障而不能提供服务,ZooKeeper 会从 Slave 中选举出一个 Broker 充当 Master。

Slave 连接 Master 并同步他们的存储状态,Slave 不接受客户端连接。所有的存储操作都将被复制到连接至 Master 的 Slaves。如果 Master 宕了,得到了最新更新的 Slave 会成为 Master。故障节点在恢复后会重新加入到集群中并连接 Master 进入 Slave 模式

zookeeper+levelDB方式集群安装

需要首先安装zookeeper(一般都用zookeeper集群,而不用zookeeper单节点)。

这里用192.168.128.129、192.168.128.130、192.168.128.131三台服务器做集群

主机

集群端口

消息端口

管控台端口

节点安装目录

192.168.128.129 

62621 

51511 

8161 

~/activemq/node-01 

192.168.128.130 

62622 

51512 

8162 

~/activemq/node-02 

192.168.128.131 

62623 

51513 

8163 

~/activemq/node-03 

安装集群主要是配置activemq内部通信的集群端口、对外提供的消息端口、管理控制台的端口。

1、配置host,三台服务器分别创建activemq目录

三台服务器都增加hosts

vim /etc/hosts

192.168.128.129 edu-zk-01

192.168.128.130 edu-zk-02

192.168.128.131 edu-zk-03

 

创建activemq目录

mkdir ~/activemq

 

2、将apache-activemq-5.11.1-bin.tar.gz分别放到三台服务器的~用户目录,解压,按节点重命名

129:

cd ~

tar -zxf apache-activemq-5.11.1-bin.tar.gz

mv apache-activemq-5.11.1 activemq-node-01

 

130:

cd ~

tar -zxf apache-activemq-5.11.1-bin.tar.gz

mv apache-activemq-5.11.1 activemq-node-02

 

131:

cd ~

tar -zxf apache-activemq-5.11.1-bin.tar.gz

mv apache-activemq-5.11.1 activemq-node-03

 

3、分别修改3台服务器activemq管理控制台端口

vim activemq-node-03/conf/jetty.xml

Node-01 管控台端口:

<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">

<!-- the default port number for the web console -->

<property name="host" value="0.0.0.0"/>

<property name="port" value="8161"/>

</bean>

Node-02 管控台端口:

<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">

<!-- the default port number for the web console -->

<property name="host" value="0.0.0.0"/>

<property name="port" value="8162"/>

</bean>

Node-03 管控台端口:

<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">

<!-- the default port number for the web console -->

<property name="host" value="0.0.0.0"/>

<property name="port" value="8163"/>

</bean>

 

4、分别修改conf/activemq.xml,配置持久化适配器,修改消息端口

129:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="DubboEdu" dataDirectory="${activemq.data}">

 

<persistenceAdapter>

        <!-- kahaDB directory="${activemq.data}/kahadb"/ -->

            <replicatedLevelDB

            directory="${activemq.data}/leveldb"

            replicas="3"

            bind="tcp://0.0.0.0:62621"

            zkAddress="192.168.128.129:2181,192.168.128.130:2182,192.168.128.131:2183"

            hostname="edu-zk-01"

            zkPath="/activemq/leveldb-stores"

            />

        </persistenceAdapter>

<transportConnector name="openwire" uri="tcp://0.0.0.0:51511?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

 

 

130:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="DubboEdu" dataDirectory="${activemq.data}">

 

<persistenceAdapter>

        <!-- kahaDB directory="${activemq.data}/kahadb"/ -->

            <replicatedLevelDB

            directory="${activemq.data}/leveldb"

            replicas="3"

            bind="tcp://0.0.0.0:62622"

            zkAddress="192.168.128.129:2181,192.168.128.130:2182,192.168.128.131:2183"

            hostname="edu-zk-02"

            zkPath="/activemq/leveldb-stores"

            />

        </persistenceAdapter>

<transportConnector name="openwire" uri="tcp://0.0.0.0:51512?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

 

 

 

131:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="DubboEdu" dataDirectory="${activemq.data}">

 

<persistenceAdapter>

        <!-- kahaDB directory="${activemq.data}/kahadb"/ -->

            <replicatedLevelDB

            directory="${activemq.data}/leveldb"

            replicas="3"

            bind="tcp://0.0.0.0:62623"

            zkAddress="192.168.128.129:2181,192.168.128.130:2182,192.168.128.131:2183"

            hostname="edu-zk-03"

            zkPath="/activemq/leveldb-stores"

            />

        </persistenceAdapter>

 

 

<transportConnector name="openwire" uri="tcp://0.0.0.0:51513?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

 

说明:

其中persistenceAdapter是配置持久化适配器,replicatedLevelDB 表示用复制levelDB的方式。

replicas 是activemq集群的节点数,每个activemq没有配置其他节点的地址,而是通过注册中心去找其他节点,是否大于一半节点可用的判断就是用这个节点数除以2,再跟zookeeper上找到的节点数做的比较。

bind是集群节点间的通信端口,zkAddress是zookeeper集群地址。

hostname是/etc/hosts配置的。

transportConnector的51511、51512、51513是消息端口。每个 ActiveMQ 的 BrokerName 必须相同,否则不能加入集群

5、按顺序启动三台服务器的mq

129

cd ~/activemq-node-01/bin/

./activemq start

 

130

cd ~/activemq-node-02/bin/

./activemq start

 

131

cd ~/activemq-node-03/bin/

./activemq start

6、使用ZooInspector可以查看zookeeper节点状态

windows上:

进入zookeeper-dev-ZooInspector.jar所在目录,然后执行jar即可。

cd D:\acce\dubbo\ZooInspector\build

java -jar zookeeper-dev-ZooInspector.jar

这里输入任何一个zookeeper节点地址都可以,如

192.168.128.129:2181

192.168.128.130:2182

192.168.128.131:2183

 

可以看到只有节点3是Master,因为elected不为空,其他都是Slave

上面的对应了activemq.xml 里持久化适配器里的zkPath="/activemq/leveldb-stores"。

这个zookeeper同时在为activemq和dubbo提供分布式协调服务。

6、客户端连接

客户端连接:

mq.brokerURL=failover:(tcp://192.168.128.129:51511,tcp://192.168.128.130:51512,tcp://192.168.128.131:51513)?randomize=false

 

其中failover是一个协议,表示失败就换另一台再试

集群高可用

activemq的集群与zookeeper是不同概念,activemq的master与slave跟zookeeper的leader与follower没有关系。

activemq集群中哪个是master哪个是slave需要通过ZooInspector连接到zookeeper节点上去看。

通过这个通信端口去查配置即可

 

activemq集群中只有master的节点的管理控制台可以访问。当master挂掉时,会自动推举出一个新的master,会有短时间的闪断,不过不影响业务和数据。必须有大于一半的节点可用,整个activemq集群才可用,否则不会推举出master,集群无法使用。

 

在zookeeper正常的情况下,activemq集群大于一般节点挂掉又恢复后,会自动再次选出master,集群可自动恢复。

 

如果zookeeper集群大于一半节点挂掉又恢复后,activemq节点需要全部重启才能重新选举出master。

 

activemq多集群负载均衡

有很多种方式,如:

 

 

配置:

假设有两个集群

集群1:

192.168.128.129:53511、192.168.128.130:53512、192.168.128.131:53513

集群2(伪集群,因为节点都在同一台服务器132):

192.168.128.132:51511、192.168.128.132:51512、192.168.128.132:51513

在集群1的各节点conf/activemq.xml的<persistenceAdapter>标签前面(外面)增加

        <networkConnectors>

            <networkConnector

            uri="static:(tcp://192.168.128.132:51511,tcp://192.168.128.132:51512,tcp://192.168.128.132:51513)"

            duplex="false"/>

        </networkConnectors>

 

 

在集群2的各节点conf/activemq.xml的<persistenceAdapter>前面增加

        <networkConnectors>

            <networkConnector

            uri="static:(tcp://192.168.128.129:51511,tcp://192.168.128.130:51512,tcp://192.168.128.131:51513)"

            duplex="false"/>

        </networkConnectors>

表示互相通过网桥连接。两个集群只是生产者和消费者会互相消费,相当于实现了负载均衡。不能有集群挂掉,挂掉的集群依然无法使用。

 

 

持久化消息和持久化订阅

持久化消息是指mq发送消息之前,会先存到磁盘或数据库里,发送完以后再删除,目的是防止mq服务器挂掉消息丢失的情况,重启以后自动再发送。

 

持久化订阅是指发布订阅模式下,接收方服务没有启动,消息服务器会将消息暂存下来,带接收方启动以后再发送,没有开启持久化订阅则会直接丢失消息。

 

一般会把两个都开启。

 

持久化消息的方式

有AMQ、KahaDB、Jdbc、LevelDB等。

配置在conf/activemq.xml里

1、AMQ

文件方式存储,默认一条消息最大32M,可设置,发送完以后删除文件,特点是速度很快。

配置:

<persistenceAdapter>

<amqPersistenceAdapter directory="activemq-data"maxFileLength="32mb"/>

</persistenceAdapter>

 

2、KahaDB(默认的方式)

基于文件的本地数据库储存形式,特点是扩展性强,恢复快

配置:

<persistenceAdapter>

<kahaDB directory="${activemq.data}/kahadb"/>

</persistenceAdapter>

3、jdbc

MySQL、SQL Server、Oracle、DB2等

 

4、LevelDB

与KahaDB类似,也是文件数据库,速度更快

posted @ 2020-12-16 10:38  吴克兢  阅读(1038)  评论(0)    收藏  举报