一、简介
activeMQ是apache开源的一个消息中间件.之前的RPC基本上都是高耦合的,而消息中间件的采用,实现了松耦合.它基于JMS规范,支持多种传输协议,最重要的是它实现了异步的调用.
二、主要概念
provider(broker)
provider是消息中间件服务的提供者,在activeMQ也称为broker. 在两种实现方式:第一种我们下载的activeMQ包解压后就是一个完整的broker;第二种自己实现broker,也称为嵌入式的broker.
producer
producer是消息的生产者,相对于provider来说它是客户端.它会将生产的消息发送到provider.以供consumer使用.
consumer
consumer是消息的消费者,相对于provider来说它也是客户端,它会时刻监听provider的对应的domain消息.一旦监听到就会消费.
destination domain
有两种类型:一种是point-to-point即点对点的队列消息,一条消息只会有一个消费者;二种是publish/susribe发布与订阅消息,一条消息可以有多个消费者.
三、provider的配置
connectors的理解与配置
3.1 transportConnectors 消息中间件开放的协议地址,供producer和consumer访问.
<transportConnectors>
<transportConnector name="openwire" uri="tcp://localhost:61616?trace=true" discoveryUri="multicast://default"/>
<transportConnector name="ssl" uri="ssl://localhost:61617"/>
<transportConnector name="stomp" uri="stomp://localhost:61613"/>
<transportConnector name="xmpp" uri="xmpp://localhost:61222"/>
</transportConnectors>
支持多种协议:tcp/nio/udp/ssl/openWire/ssl/stomp/xmpp/ws/mqtt/amqp/vm
3.2 networkConnectors 多个broker相互间的通信
<networkConnectors>
<!-- by default just auto discover the other brokers -->
<networkConnector name="default-nc" uri="multicast://default"/>
<!-- Example of a static configuration:
<networkConnector name="host1 and host2" uri="static://(tcp://host1:61616,tcp://host2:61616)"/>
-->
</networkConnectors>
3.2.1 静态broker-cluster(固定已知的IP地址)
static:(uri1,uri2,uri3,...)?transportOptions
如:
<networkConnector name="host1 and host2" uri="static://(tcp://host1:61616,tcp://host2:61616)"/>
将消息发送到本地的broker会被分发到host1和host2上,producer和consumer都只连接本地的broker就做到负载均衡.
3.2.2 失败转移FailOver protocol
前面的负载有一个单点的问题,因此需要做一个主备的策略.
failover:(tcp://localhost:61616,tcp://remotehost:61616)?initialReconnectDelay=100
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616" updateClusterClients="true" updateClusterFilter=".*A.*,.*B.*"/>
updateClusterClients=true需要设置
结合以上两点就能做到发的集群效果.
3.2.3 动态broker-cluster(自动发现)
组播协议Multicast Protocol
<networkConnector name="default-nc" uri="multicast://default"/>
<transportConnector name="openwire" uri="tcp://localhost:61616?trace=true" discoveryUri="multicast://default"/>
1.需要配置discoveryUri,它是暴露的访问接口组播发现
2.networkConnector uri=multicast://default 多broker的相互发现,使用的是默认配置相当于uri=multicast://239.255.2.3:6155?group=default
3.组播协议需要brokers在同时一个网络.
四、消息持久化
4.1 JDBC存储于关系型数据库中,如mysql/oracle/Derby/PostgreSQL/SQLServer/Sybase
需要建两张表
表ACTIVEMQ_MSGS
ID INTEGER the sequence id used to retrieve the message
CONTAINER VARCHAR(250) the destination of the message
MSGID_PROD VARCHAR(250) The id of the message producer is used
MSGID_SEQ INTEGER the producer sequence number for the message.
EXPIRATION BIGINT the time in milliseconds when the message will expire
MSG BLOB the serialized message itself
表ACTIVEMQ_ACKS
CONTAINER VARCHAR(250) the destination
SUB_DEST VARCHAR(250) the destination of the durable subscriber (could be different from the container if using wild cards)
CLIENT_ID VARCHAR(250) the clientId of the durable subscriber
SUB_NAME VARCHAR(250) The subscriber name of the durable subscriber
SELECTOR VARCHAR(250) the selector of the durable subscriber
LAST_ACKED_ID Integer the sequence id of last message received by this subscriber
4.1.1 配置-消息存储
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds"/>
</persistenceAdapter>
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="activemq"/>
<property name="password" value="activemq"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<bean id="oracle-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:AMQDB"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<bean id="derby-ds" class="org.apache.derby.jdbc.EmbeddedDataSource">
<property name="databaseName" value="derbydb"/>
<property name="createDatabase" value="create"/>
</bean>
<bean id="postgres-ds" class="org.postgresql.ds.PGPoolingDataSource">
<property name="serverName" value="localhost"/>
<property name="databaseName" value="activemq"/>
<property name="portNumber" value="0"/>
<property name="user" value="activemq"/>
<property name="password" value="activemq"/>
<property name="dataSourceName" value="postgres"/>
<property name="initialConnections" value="1"/>
<property name="maxConnections" value="10"/>
</bean>
4.1.2 配置-日志存储
<persistenceAdapter>
<journaledJDBC dataDirectory="${activemq.base}/data" dataSource="#postgres-ds"/>
</persistenceAdapter>
适用场景:对于集群的broker用JDBC的消息和日志存储,可以有效的避免数据丢失.
4.2 存储于文件中,如:kaha
AMQ message store
<persistenceAdapter>
<amqPersistenceAdapter directory="${activemq.base}/data"
syncOnWrite="true" indexPageSize="16kb" indexMaxBinSize="100" maxFileLength="10mb" />
</persistenceAdapter>
Kaha message store
<persistenceAdapter>
<kahaPersistenceAdapter directory="activemq-data" maxFileLength="10mb" />
</persistenceAdapter>
Kaha与amq message store相似,都是基于文件的存储.相较而言,kaha的处理速度要高,但是可靠性降低.
4.3 存储于内存中
<broker brokerName="test-broker" persistent="false" xmlns="http://activemq.apache.org/schema/core">
只需要设置persistent=false,就会直接使用内存来存储消息.
但是需要注意设置JVM的大小和内存大小,来适应在高并发下能涉及到最大消息数据大小.
因为它不会主要缓存消息,一旦broker宕了,是无法恢复的.
五、caching message for consumers works (缓存消费者消息)
这个主要是针对publish/subscribe的topic进行消息缓存,以达到近似的real-time.
activemq.xml的片段
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" memoryLimit="5mb"/>
<policyEntry topic=">" memoryLimit="5mb">
<dispatchPolicy>
<strictOrderDispatchPolicy/>
</dispatchPolicy>
<subscriptionRecoveryPolicy>
<lastImageSubscriptionRecoveryPolicy/>
</subscriptionRecoveryPolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
subscriptionRecoveryPolicys 的类型有以下几种:
FixedSizeSubscriptionRecoveryPolicy在内存以固定大小缓存消息,默认使用.
FixedCountSubscriptionRecoveryPolicy 在内存以固定数量缓存消息,默认使用.
QueryBasedSubscriptionRecoveryPolicy
TimedSubscriptionRecoveryPolicy 过期时间
LastImageSubscriptionRecoveryPolicy 只缓存最后一条topic消息
NoSubscriptionRecoveryPolicy 不使用缓存
可以根据不同主题设置不同的缓存策略,配置多个policyEntry,并且可以使用通配符.
六、安全访问(securing)
6.1 简单的xml配置用户名和密码
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="admin" password="password" groups="admins,publishers,consumers"/>
<authenticationUser username="publisher" password="password" groups="publishers,consumers"/>
<authenticationUser username="consumer" password="password" groups="consumers"/>
<authenticationUser username="guest" password="password" groups="guests"/>
</users>
</simpleAuthenticationPlugin>
</plugins>
6.2 JAAS插件
http://java.sun.com/products/jaas/reference/docs/index.html
在activemq.xml中增加以下片段
<plugins>
<jaasAuthenticationPlugin configuration="activemq-domain" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<authorizationEntry topic="STOCKS.>" read="consumers" write="publishers" admin="publishers" />
<authorizationEntry topic="STOCKS.JAVA" read="guests" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="admins,publishers,consumers,guests" write="admins,publishers,consumers,guests" admin="admins,publishers,consumers,guests" />
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins
创建三个文件:login.config/users.properties/groups.properties
login.config
activemq {
org.apache.activemq.jaas.PropertiesLoginModule required
org.apache.activemq.jaas.properties.user="users.properties"
org.apache.activemq.jaas.properties.group="groups.properties";
};
users.properties
admin=password
publisher=password
consumer=password
guest=password
groups.properties
admins=admin
publishers=admin,publisher
consumers=admin,publisher,consumer
guests=guest
6.3 实现MessageAuthorizationPolicy接口的自定义类,来控制安全访问.
先编译此类,并将此包放到activemq的lib目录下
<messageAuthorizationPolicy>
<bean class="org.apache.activemq.book.ch5.AuthorizationPolicy" xmlns="" />
</messageAuthorizationPolicy>
6.4 继承BrokerFilter类,override相应的方法,来实现安全控制.
同时还需要一个实现BrokerPlugin接口的类.
编译此两个类,并放置于activemq的lib目录下
并配置activemq.xml
<bean id="ipAuthenticationPlugin" class="org.apache.activemq.book.ch5.IPAuthenticationPlugin">
<property name="allowedIPAddresses">
<list>
<value>127.0.0.1</value>
</list>
</property>
</bean>
如spring的注入一样配置javabean
同时需要在broker标签中增加plugns属性
<broker xmlns="http://activemq.org/config/1.0" brokerName="localhost" dataDirectory="${activemq.base}/data" plugins="#ipAuthenticationPlugin">
七、embedding the broker(自定义broker服务)
编程式
使用BrokerService 来配置broker,所有的参数都需要在java代码中体现.
使用BrokerFactory来生成BrokerService,所有参数通过配置文件来实现.
<broker xmlns="http://activemq.org/config/1.0" brokerName="localhost" dataDirectory="${activemq.base}/data">
<!-- The transport connectors ActiveMQ will listen to -->
<transportConnectors>
<transportConnector name="openwire" uri="tcp://localhost:61616" /> </transportConnectors>
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="admin" password="password" groups="admins,publishers,consumers"/>
<authenticationUser username="publisher" password="password" groups="publishers,consumers"/>
<authenticationUser username="consumer" password="password" groups="consumers"/>
<authenticationUser username="guest" password="password" groups="guests"/>
</users>
</simpleAuthenticationPlugin>
</plugins>
</broker>
xml schema引用地址:http://activemq.apache.org/xml-reference.html
spring整合
依赖包
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>4.5</version>
</dependency>
spring1.0整合
<beans>
<bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="file:src/main/resources/org/apache/activemq/book/ch5/activemq-simple.xml" />
<property name="start" value="true" />
</bean>
</beans>
spring2.0整合
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.14.5.xsd
">
<amq:broker brokerName="localhost" dataDirectory="${activemq.base}/data">
<amq:transportConnectors>
<amq:transportConnector name="openwire" uri="tcp://localhost:61616" />
</amq:transportConnectors>
<amq:plugins>
<amq:simpleAuthenticationPlugin>
<amq:users>
<amq:authenticationUser username="admin" password="password" groups="admins,publishers,consumers"/>
<amq:authenticationUser username="publisher" password="password" groups="publishers,consumers"/>
<amq:authenticationUser username="consumer" password="password" groups="consumers"/>
<amq:authenticationUser username="guest" password="password" groups="guests"/>
</amq:users>
</amq:simpleAuthenticationPlugin>
</amq:plugins>
</amq:broker>
</beans>
八、producer的使用
九、consumer的使用
十、activeMQ优化
注:
1.本文章使用的activeMQ版本是5.1.0;maven版本是3.3.3;ant版本是1.9.9;
2.activeMQ最新版本与5.1.0有较大的差别.但核心内容是一致的.
3.ant版本依赖于JDK的版本.1.10.0的ant版本要求是JDK1.8(反正本机学习是用1.7的版本无法使用).
参考地址:http://activemq.apache.org/
参考文档:activeMQ in action