一、简介

    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