RabbitMQ

来源:互联网 发布:云服务器搭建sql serv 编辑:程序博客网 时间:2024/05/01 14:08

一、rabbitMQ简介

1. 1、rabbitMQ的优点(适用范围)
  1. 基于erlang语言开发具有高可用高并发的优点,适合集群服务器。
  2. 健壮、稳定、易用、跨平台、支持多种语言、文档齐全。
  3. 有消息确认机制和持久化机制,可靠性高。
  4. 开源
  • 其他MQ的优势:
    1. Apache ActiveMQ曝光率最高,但是可能会丢消息。
    2. ZeroMQ延迟很低、支持灵活拓扑,但是不支持消息持久化和崩溃恢复。
1.2、几个概念说明
  • producer&Consumer
    producer指的是消息生产者,consumer消息的消费者。
  • Queue
    消息队列,提供了FIFO的处理机制,具有缓存消息的能力。rabbitmq中,队列消息可以设置为持久化,临时或者自动删除。
    设置为持久化的队列,queue中的消息会在server本地硬盘存储一份,防止系统crash,数据丢失
    设置为临时队列,queue中的数据在系统重启之后就会丢失
    设置为自动删除的队列,当不存在用户连接到server,队列中的数据会被自动删除Exchange

  • Exchange类似于数据通信网络中的交换机,提供消息路由策略。rabbitmq中,producer不是通过信道直接将消息发送给queue,而是先发送给Exchange。一个Exchange可以和多个Queue进行绑定,producer在传递消息的时候,会传递一个ROUTING_KEY,Exchange会根据这个ROUTING_KEY按照特定的路由算法,将消息路由给指定的queue。和Queue一样,Exchange也可设置为持久化,临时或者自动删除。

    Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别:

    • Direct
      直接交换器,工作方式类似于单播,Exchange会将消息发送完全匹配ROUTING_KEY的Queue
    • fanout
      广播是式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue。
    • topic
      主题交换器,工作方式类似于组播,Exchange会将消息转发和ROUTING_KEY匹配模式相同的所有队列,比如,ROUTING_KEY为user.stock的message会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列。( * 表是匹配一个任意词组,#表示匹配0个或多个词组)
    • headers
      消息体的header匹配(ignore)
  • Binding
    所谓绑定就是将一个特定的 Exchange 和一个特定的 Queue 绑定起来。Exchange 和Queue的绑定可以是多对多的关系。

  • virtual host
    在rabbitmq server上可以创建多个虚拟的message broker,又叫做virtual hosts (vhosts)。每一个vhost本质上是一个mini-rabbitmq server,分别管理各自的exchange,和bindings。vhost相当于物理的server,可以为不同app提供边界隔离,使得应用安全的运行在不同的vhost实例上,相互之间不会干扰。producer和consumer连接rabbit server需要指定一个vhost。
1.3、消息队列的使用过程
  1. 客户端连接到消息队列服务器,打开一个channel。
  2. 客户端声明一个exchange,并设置相关属性。
  3. 客户端声明一个queue,并设置相关属性。
  4. 客户端使用routing key,在exchange和queue之间建立好绑定关系。
  5. 客户端投递消息到exchange。
  6. exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里

二、CentOS 安装RabbitMq

  1. 安装erlang(版本:otp_src_17.1.tar.gz)
    默认安装目录/opt/下 :

    • 将准备好的otp_src_17.1.tar.gz放在/opt/
      [root@iZ235pdz8oaZ opt]# ll
      -rw-r–r– 1 root root 28182213 Feb 24 15:44 otp_sr_17.1.tar.gz
      drwxr-xr-x. 2 root root 4096 Nov 22 2013 rh

    • 解压otp_src_17.1.tar.gz
      [root@iZ235pdz8oaZ opt]# tar xzvf otp_src_17.1.tar.gz
      [root@iZ235pdz8oaZ opt]# ll
      drwxr-xr-x. 11 2011 uucp 4096 6月 24 2014 otp_src_17.1
      -rw-r–r–. 1 root root 66912681 3月 15 06:26 otp_src_17.1.tar.gz
      -rw-r–r–. 1 root root 4106510 3月 15 06:27 rabbitmq-server-3.3.5-1.noarch.rpm

    • 然后:
      [root@iZ235pdz8oaZ opt]# cd otp_src_17.1
      [root@iZ235pdz8oaZ otp_src_17.1]# ./configure

    • 没问题,再继续
      [root@iZ235pdz8oaZ otp_src_17.1]# make
      [root@iZ235pdz8oaZ otp_src_17.1]# make install

  2. 1.2. 安装RabbitMQ(版本:rabbitmq-server-3.3.5-1)
    默认安装目录/opt/下 :

    • 将准备好的rabbitmq-server-3.3.5-1.noarch.rpm放在/opt/
      [root@iZ235pdz8oaZ opt]# ll
      drwxrwxrwx. 11 2011 uucp 4096 3月 15 07:22 otp_src_17.1
      -rw-r–r–. 1 root root 66912681 3月 15 06:26 otp_src_17.1.tar.gz
      -rw-r–r–. 1 root root 4106510 3月 15 06:27 rabbitmq-server-3.3.5-1.noarch.rpm

    • 强制安装rabbitmq-server-3.3.5-1.noarch.rpm
      [root@iZ235pdz8oaZ opt]#
      rpm -i –force –nodeps rabbitmq-server-3.3.5-1.noarch.rpm

    • 开启插件rabbitmq_management
      [root@iZ235pdz8oaZ opt]# rabbitmq-plugins enable rabbitmq_management
    • 创建用户
      [root@iZ235pdz8oaZ opt]# rabbitmqctl add_user ddd ddd
    • 配置用户权限
      [root@iZ235pdz8oaZ opt]# rabbitmqctl set_user_tags ddd administrator
      安装了插件以后可以通过http://192.168.2.175:15672/#/查看

三、简单Java实例

  1. 首先是消息生产者和提供者的基类
    package com.kxtx.padserver.common.rabbit;

    import java.io.IOException;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;/** *  * 功能概要: EndPoint类型的队列 *  * @author linbingwen * @since  2016年1月11日 */public abstract class RabbitMQBase{    protected Channel channel;    protected Connection connection;    protected String endPointName;    public RabbitMQBase(String endpointName) throws IOException{         this.endPointName = endpointName;         //Create a connection factory         ConnectionFactory factory = new ConnectionFactory();         //hostname of your rabbitmq server         factory.setHost("192.168.2.175");         factory.setPort(5672);         factory.setUsername("ddd");         factory.setPassword("ddd");         //getting a connection         connection = factory.newConnection();         //creating a channel         channel = connection.createChannel();         //declaring a queue for this channel. If queue does not exist,         //it will be created on the server.         channel.queueDeclare(endpointName, false, false, false, null);    }    /**     * 关闭channel和connection。并非必须,因为隐含是自动调用的。     * @throws IOException     */     public void close() throws IOException{         this.channel.close();         this.connection.close();     }}
  2. 消息提供者

    package com.kxtx.padserver.common.rabbit;       import java.io.IOException;import java.io.Serializable;import org.apache.commons.lang.SerializationUtils;/** *  * 功能概要:消息生产者 *  * @author linbingwen * @since  2016年1月11日 */public class Producer extends RabbitMQBase{    public Producer(String endPointName) throws IOException{        super(endPointName);    }    public void sendMessage(Serializable object) throws IOException {        channel.basicPublish("",endPointName, null, SerializationUtils.serialize(object));    }  }
  3. 消息消费者

    package com.kxtx.padserver.common.rabbit;import java.io.IOException;import java.util.HashMap;import java.util.Map;import org.apache.commons.lang.SerializationUtils;import com.rabbitmq.client.AMQP.BasicProperties;import com.rabbitmq.client.Consumer;import com.rabbitmq.client.Envelope;import com.rabbitmq.client.ShutdownSignalException;/** *  * 功能概要:读取队列的程序端,实现了Runnable接口 *  * @author linbingwen * @since  2016年1月11日 */public class QueueConsumer extends RabbitMQBase implements Runnable, Consumer{    public QueueConsumer(String endPointName) throws IOException{        super(endPointName);           }    public void run() {        try {            //start consuming messages. Auto acknowledge messages.            channel.basicConsume(endPointName, true,this);        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * Called when consumer is registered.     */    public void handleConsumeOk(String consumerTag) {        System.out.println("Consumer "+consumerTag +" registered");        }    /**     * Called when new message is available.     */    public void handleDelivery(String consumerTag, Envelope env,            BasicProperties props, byte[] body) throws IOException {        Map map = (HashMap)SerializationUtils.deserialize(body);        System.out.println("Message Number "+ map.get("message number") + " received.");    }    public void handleCancel(String consumerTag) {}    public void handleCancelOk(String consumerTag) {}    public void handleRecoverOk(String consumerTag) {}    public void handleShutdownSignal(String consumerTag, ShutdownSignalException arg1) {}}
  4. 测试

    package com.kxtx.padserver.common.rabbit;import java.io.IOException;import java.sql.SQLException;import java.util.HashMap;/** *  * @author * @create:2016年3月28日 上午9:27:14 * @description: */public class RabbitMqTest {     public RabbitMqTest() throws Exception{            QueueConsumer consumer = new QueueConsumer("queue");            Thread consumerThread = new Thread(consumer);            consumerThread.start();            Producer producer = new Producer("queue");            for (int i = 0; i < 1000000; i++) {                HashMap message = new HashMap();                message.put("message number", i);                producer.sendMessage(message);                System.out.println("Message Number "+ i +" sent.");            }        }        /**         * @param args         * @throws SQLException         * @throws IOException         */        public static void main(String[] args) throws Exception{          new RabbitMqTest();        }}

四、Spring整合RabbitMQ

  1. RabbitMQ配置信息 rabbitMq.xml

    <?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:rabbit="http://www.springframework.org/schema/rabbit"    xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/rabbit     http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">    <!--配置connection-factory,指定连接rabbit server参数 -->    <rabbit:connection-factory id="connectionFactory"        username="ddd" password="ddd" host="192.168.2.175" port="5672" />    <!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成 -->    <rabbit:admin connection-factory="connectionFactory" />    <!--定义queue -->    <rabbit:queue name="queueTest" durable="true" auto-delete="false" exclusive="false" />    <!-- 定义direct exchange,绑定queueTest -->    <rabbit:direct-exchange name="exchangeTest" durable="true" auto-delete="false">        <rabbit:bindings>            <rabbit:binding queue="queueTest" key="queueTestKey"></rabbit:binding>        </rabbit:bindings>    </rabbit:direct-exchange>    <!--定义rabbit template用于数据的接收和发送 -->    <rabbit:template id="amqpTemplate"  connection-factory="connectionFactory"         exchange="exchangeTest" />    <!-- 消息接收者 -->    <bean id="messageReceiver" class="com.kxtx.padserver.common.spring.MessageConsumer"></bean>    <!-- queue litener  观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象-->    <rabbit:listener-container connection-factory="connectionFactory">             <rabbit:listener queues="queueTest" ref="messageReceiver"/>    </rabbit:listener-container></beans>
  2. Spring 配置文件

    <?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:context="http://www.springframework.org/schema/context"    xmlns:p="http://www.springframework.org/schema/p"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">    <import resource="classpath*:rabbitMq.xml" />    <!-- 扫描指定package下所有带有如@controller,@services,@resource,@ods并把所注释的注册为Spring Beans -->    <context:component-scan base-package="com.kxtx.padserver.common.spring" />    <!-- 激活annotation功能 -->    <context:annotation-config /></beans>
  3. 生产者

    package com.kxtx.padserver.common.spring;import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.amqp.core.AmqpTemplate;import org.springframework.stereotype.Service;/** * 功能概要:消息产生,提交到队列中去 *  * @author linbingwen * @since  2016年1月15日  */@Servicepublic class MessageProducer {    private Logger logger = LoggerFactory.getLogger(MessageProducer.class);    @Resource    private AmqpTemplate amqpTemplate;    public void sendMessage(Object message){      logger.info("to send message:{}",message);      amqpTemplate.convertAndSend("queueTestKey",message);    }}
  4. 消费者

    package com.kxtx.padserver.common.spring;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.amqp.core.Message;import org.springframework.amqp.core.MessageListener;/** * 功能概要:消费接收 *  * @author linbingwen * @since  2016年1月15日  */public class MessageConsumer implements MessageListener {    private Logger logger = LoggerFactory.getLogger(MessageConsumer.class);    @Override    public void onMessage(Message message) {        logger.info("receive message:{}",message);        System.out.println("hello world");    }}
  5. 测试

    package com.kxtx.padserver.common.spring;import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;/** *  * @author * @create:2016年3月28日 上午10:10:15 * @description: */@ContextConfiguration({ "classpath:application.xml" })public class SpringMqTest extends AbstractJUnit4SpringContextTests {    @Autowired    private MessageProducer messageProducer;    @Test    public void test(){        for(int i = 0; i < 100; i++){            messageProducer.sendMessage("hello world");        }    }}
0 0