消息的发送策略
持久化消息,默认情况下,生产者发送的消息时持久化的。消息发送到broker后,producer会等待broker对这条消息的处理情况的反馈,默认情况是同步的需要堵塞等待,效率较低,可以设置消息发送端发送持久化消息的异步方式。
connectionFactory.setUseAsyncSend(true)
回执窗口大小设置,通过这个来控制borker在确认收到消息前,生产者能发送的最大数据量(字节)
connectionFactory.setProducerWindowSize()
非持久性消息,非持久化消息模式下,默认就是异步发送过程
textMessage.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENCE)
如果需要对非持久化消息的每次发送的消息都获得broker的回执的话
connectionFactory.setAlwaysSyncSend()
consumer获取消息时pull还是broker主动push?
默认情况下,mq服务器(broker)采用异步方式向客户端主动推送消息(push)。也就是说broker在向某个消费者会话推送消息后,不会等待消费者响应消息,知道消费者处理完消息以后,主动向broker返回处理结果。
预读取消息数量:
broker端一旦有消息,就主动按照默认设置的规则推送给当前活动的消费者。每次推送都有一定的数量限制,而这个数量限制就是prefetchSize。
Queue:
持久化消息:prefetchSize:1000
非持久化消息:prefetchSize:1000
topic:
持久化消息 prefetchSize:100
非持久化消息 prefectSize:32766
假如prefetchSize=0,此时对于consumer来说,就是一个pull模式。
消息确认
ACK_TYPE,消费者和broker交换ACK指令时,还需要告诉broker ACK_TYPE。
ACK_TYPE表示确认指令的类型,broker可以根据不同的ACK_TYPE去针对当前消息做不同的应对策略
REDELIVERED_ACK_TYPE (broker会重新发送该消息) 重发侧策略
DELIVERED_ACK_TYPE 消息已经接收,但是尚未处理结束
STANDARD_ACK_TYPE 表示消息处理成功
ACK_TYPE是开发人员看不到的是底层的机制。
activeMQ结合Spring开发
Spring提供了对JMS的支持,需要添加Spring支持JMS的包
添加jar包:(接收端与发送端相同)
配置Spring文件:(接收端与发送端相同)
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://192.168.74.131:61616</value>
</property>
</bean>
</property>
<property name="maxConnections" value="50"/>
</bean>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="spring-queue"/>
</bean>
<!--<bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="spring-topic"/>
</bean>-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="destination"/>
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
</property>
</bean>
发送端代码:
public class SpringJmsSender {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=
new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/service-jms.xml");
JmsTemplate jmsTemplate=(JmsTemplate) context.getBean("jmsTemplate");
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message=session.createTextMessage();
message.setText("Hello,mic");
return message;
}
});
}
}
接收端代码:
public class SpringJmsReceiver {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=
new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/service-jms.xml");
JmsTemplate jmsTemplate=(JmsTemplate) context.getBean("jmsTemplate");
String msg=(String)jmsTemplate.receiveAndConvert();
System.out.println(msg);
}
}
以上为queue方式,将其改完发布订阅模式:
修改配置文件:
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://192.168.74.131:61616</value>
</property>
</bean>
</property>
<property name="maxConnections" value="50"/>
</bean>
<bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="spring-topic"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="destinationTopic"/>
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
</property>
</bean>
再将其改为时间通知方式来配置消费者:
更改消费端Spring的配置:
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destinationTopic"/>
<property name="messageListener" ref="messageListener"/>
</bean>
<bean id="messageListener" class="com.gupao.vip.mic.dubbo.jms.SpringJmsListener"/>
增加监听类:
public class SpringJmsListener implements MessageListener{
@Override
public void onMessage(Message message) {
try {
System.out.println(((TextMessage)message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
更改启动类:
public class SpringJmsReceiver {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=
new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/service-jms.xml");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ActiveMQ支持的传输协议
client端和broker端的通讯协议
TCP(可靠性高)、UDP(可能会丢包) 、NIO(访问量大)、
SSL(加密)、Http 、Https 、vm
生产者与消费者协议能不一样吗?
不能,因为不同协议端口号不能一样。
如何修改协议或端口号?
在conf/activemq.xml中修改
ActiveMQ持久化存储
1.kahaDB 默认的存储方式(持久化存储,存储在根目录的kahaDB文件下),在activemq.xml中配置
2.AMQ基于文件的存储方式,写入速度快,容易恢复,文件默认32M大小
3.JDBC基于数据库存储之JDBC Store。 配置完成后启动activemq,会在数据库中生成三个表
ACTIVEMQ_ACKS 存储持久订阅的信息
ACTIVEMQ_LOCK 锁表(用来做集群时,实现master选举的表)
ACTIVEMQ_MSGS 消息表
如何配置activeMQ基于jdbc存储?
首先配置:
然后,添加jar包依赖
4.JDBC Message store with activeMQ joural 这种方式克服了 JDBC Store的不足,用快速的缓存写入技术,大大提高了性能
JDBC Store和 JDBC Message Store with ActiveMQ Journal的区别:
Jdbc with journal的性能优表jdbc
Jdbc用于 master/ slave模式的数据库分享
Jdbc with journal不能用于 master/ slave模式
一般情况下,推荐使用 jdbc with journal
5.levelDB
5.8之后引入的持久化策略,通常用于集群配置,levelDB是能够处理十亿级别规模的key-value型数据持久性存储的C++程序库,由Google发起并开源。LevelDB只能由本操作系统的其他进程调用,所以不具备网络性。如果需要网络上的远程进程操作levelDB,那么就要自行封装服务层。
ActiveMQ的网络连接
activeMQ如果要实现扩展性和高可用性的话,就要用到网络连接模式
NetworkConnector,主要用于配置broker与broker之间的通信连接
如上图所示,服务器s1与s2通过NetworkConnector相连,则生产者P1发送消息,消费者C3和C4都可以接收到。生产者P3发送的消息,消费者C1和C2同样也可以接收到。
静态网络连接
通过在activemq.xml中配置服务器列表实现静态网络连接
丢失的消息
在s1上注册10条消息,通过c4访问呢s2服务器,取出一条消息,发现10条消息都转移到了s2服务器,s1服务器上剩余消息为0,此时,c1与c2访问s1服务器也无法再取出消息。c3与c4访问s2服务器仍然可以继续取出消息。
从5.6版本开始,在destinationPolicy上新增了一个选项replayWhenNoConsumers属性,这个属性可以用来解决broker1上有需要转发的消息但是没有消费者时,把消息回流到原始的broker。同时把enableAudit设置为false,防止消息回流后被当做重复消息而不被分发。通过如下配置,即可完成消息回流处理:
动态网络连接
静态网络连接当机器特别多时,由于每个都是互相连接的,配置将会非常繁琐。
动态网络连接,使用multicast
networkConnector是一个高性能方案,并不是一个高可用方案,因为当没有消费者时,时有a1和a2两台服务器,往A1上发送10条消息,然后没有消费者消费,此时a1挂掉了,消费者读取a2,也读取不到消息。
通过zookeeper+activemq实现高可用方案
高可用方案:(master/slave模型)master对外服务,slave同步数据,当master挂掉时,从slave中选举出新的master,这个master数据是最新的,继续提供服务。
首先搭建好,zookeeper集群环境与activeMQ集群环境
1.修改activeMQ
参数的含义:
directory:levelDB数据文件存储的位置
replicas:replicas”参数非常重要,默认为3,表示消息最多可以备份在几个broker实例上,同是只有当“replicas/2 + 1”个broker存活时(包含master),集群才有效,才会选举master和备份消息,此值必须>=2。Client发送给Master的持久化消息(包括ACK和事务),master首先在本地保存,然后立即同步(sync)给选定的(replicas/2)个slaves,只有当这些节点也同步成功后,此消息的交互才算结束;对于剩下的replicas个节点,master采用异步的方式(async)转发。这种设计要求,可以保证集群中消息的可靠性,只有当(replicas/2 + 1)个节点物理故障,才会有丢失消息的风险。通常replicas为3,这要求开发者需要至少部署3个broker实例。如果replicas过大,会严重影响master的吞吐能力,因为它在sync消息的过程中会消耗太多的时间。
bind:用来负责slave和master的数据同步的端口和ip
zkAddress:表示zookeeper的服务端地址
hostname:服务名称,通常用本机ip命名
2.启动zookeeper集群
3.启动activeMQ集群
然后发现activeMQ在zookeeper的znode上注册了activeMQ服务:
这里最先启动的是activeMQ就是master,只有一个activeMQ对外提供服务,其余的都是备份服务器,当它挂掉时,会通过master选举选举出新的master。此时访问192.168.74.131:2181可以访问到zctiveMQ管理界面,而其他的ip访问不到。
另外还有jdbc存储的主从方案(基于LOCK锁表的操作实现master/slave,数据可以持久化存储,但是性能会依赖mysql或oracle),基于共享文件系统的主从方案(挂载网络磁盘,将数据文件保存到指定磁盘即可完成master/slave模式)
高可用+高性能方案
每一个broker集群都通过zk集群实现master选举,master之间通过网络双向连接传递消息
activeMQ容错的链接
具体看下这个博客:https://www.cnblogs.com/Eternally-dream/p/9890659.html
ActiveMQ监控
activemq自带的管理界面功能十分简单,只能查看activeMQ当前的Queue和Topics等简单信息,不能监控ActiveMQ自身运行的信息。
hawtio
HawtIO 是一个新的可插入式 HTML5 面板,设计用来监控 ActiveMQ, Camel等系统;ActiveMQ在5.9.0版本曾将hawtio嵌入自身的管理界面,但是由于对hawtio的引入产生了争议,在5.9.1版本中又将其移除,但是开发者可以通过配置,使用hawtio对ActiveMQ进行监控。本文介绍了通过两种配置方式,使用hawtio对ActiveMQ进行监控。
- 从http://hawt.io/getstarted/index.html 下载hawtio的应用程序
- 下载好后拷贝到ActiveMQ安装目录的webapps目录下,改名为hawtio.war并解压到到hawtio目录下
- 编辑ActiveMQ安装目录下conf/jetty.xml文件,在第75行添加以下代码
<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/hawtio" />
<property name="war" value="${activemq.home}/webapps/hawtio" />
<property name="logUrlOnStart" value="true" />
</bean>
4.修改bin/env文件
Dhawtio.realm=activemq -Dhawtio.role=admins
-Dhawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal
需要注意的是-Dhawtio的三个设定必须放在ACTIVEMQ_OPTS设置的最前面(在内存参数设置之后),否则会出现验证无法通过的错误(另外,ACTIVEMQ_OPTS的设置语句不要回车换行)
5.启动activeMQ服务。访问http://ip:8161/hawtio.