RabbitMQ(一)---入门

1. 概述

RabbitMQ是四大热门消息队列中间件(其他的分别是ActiveMQ/RocketMQ/ Kafka)之一,另外它严格遵循AMQP协议。消息队列简单点说就是一个生产者和消费者模型,主要负责接收、存储和投递消息。

2. 安装

这里讲解一下如何安装单机版的RabbitMQ,学习或者非生产环境使用。

2.1. Mac安装

打开终端,直接执行以下指令

brew install rabbitmq

通过以下指令启动RabbitMQ

brew services start rabbitmq

启动完成之后,打开浏览器访问:http://localhost:15672

2.2. Windows安装

安装RabbitMQ之前,需要先安装Erlang

  1. 先去官网下载Erlang的Windows的安装包,安装的过程就是一路next;
  2. 配置环境变量ERLANG_HOME

  1. 下载rabbitmq的windows安装包,一路next;
  2. 打开cmd,进入rabbitmq的安装目录下的sbin目录,执行rabbitmq-plugins enable rabbitmq_management,启动rabbitmq的管理插件,包括web控台;
  3. 浏览器进入http://localhost:15672/,默认用户名和密码:guest/guest,进入之后可以看到以下页面:

3. Hello World程序

3.1. 生产者

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.concurrent.TimeoutException;

public class Send {
    private final static String QUEUE_NAME = "hello.august";

    public static void main(String[] argv)
            throws java.io.IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");

        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(QUEUE_NAME,"fanout");
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME,QUEUE_NAME,"");
        String message = "hello 333";
        channel.basicPublish(QUEUE_NAME, QUEUE_NAME, null, message.getBytes());
        System.out.println("send message: " + message);

        channel.close();
        connection.close();
    }
}

生产者发送消息的流程

  1. 生产者连接到Broker,建立一个连接(Connection),开启一个信道(Channel);
  2. 生产者声明一个交换器,并设置相关属性,比如交换器类型,是否持久化等;
  3. 生产者声明一个队列并设置相关属性;
  4. 生产者通过路由键将交换器和队列绑定起来;
  5. 生产者发送消息到RabbitMQ Broker,其中包含路由键、交换器等信息;
  6. 相应的交换器根据接收到消息的路由键查找相匹配的队列,如果找到则投递到相应的队列中,如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者;
  7. 关闭信道;
  8. 关闭连接。

3.2. 消费者

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeoutException;

public class Recv {
    private final static String QUEUE_NAME = "hello.august";

    public static void main(String[] args) {
        try {
            consumer("consumer1");
            //consumer("consumer2");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void consumer(final String flag) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        Connection connection = connectionFactory.newConnection();

        final Channel channel = connection.createChannel();
        channel.exchangeDeclare(QUEUE_NAME,"fanout");
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME,QUEUE_NAME,"");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println("["+flag+"] Received '" + message + "'");

                channel.basicReject(envelope.getDeliveryTag(),true);
            }
        };
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

消费者消费消息的流程

  1. 消费者连接到RabbitMQ Broker,并建立一个连接(Connection),开启一个信道(Channel);
  2. 消费者向RabbitMQ Broker请求消费相应队列中的消息,可能会做一些队列声明、绑定关系的准备工作,以及设置相应的回调方法;
  3. 等待RabbitMQ Broker回调投递消息,消费者接收消息进行处理;
  4. 消费者向RabbitMQ Broker确认(ack)接收到的消息;
  5. RabbitMQ从队列中删除相应的已经被确认的消息;
  6. 关闭信道;
  7. 关闭连接。

4. 相关概念介绍

RabbitMQ当中涉及以下概念:

  • 生产者(Producer)
  • 消费者(Consumer)
  • 消息(Message)
  • Broker
  • 队列(Queue)
  • 交换器(Exchange)
  • 路由键(RoutingKey)
  • 绑定建(BindingKey)
  • 绑定(Binding)
  • 连接(Connection)
  • 通道(Channel)

4.1 消息(Message)

消息可以近似地看成是业务逻辑数据。之所以说近似,是因为消息一般包含2个部分:消息体(payload)和标签(Label),而业务逻辑数据只存放在消息体当中。消息的标签用来描述这条消息附加值,例如一个交换器的名称或一个路由键,RabbitMQ会根据标签把消息投递给感兴趣的消费者。

在消息路由的过程中,消息的标签会被丢弃,当消息到达队列中只会有消息体。即消费者只会消费到消息体。

4.2 生产者(Producer)

生产者就是生产消息,并将消息投递到RabbitMQ服务器中的一方。

4.3 消费者(Consumer)

消费者就是接收并处理消息的一方。多个消费者可以订阅同一个队列,默认采用轮询的方式进行处理。但是RabbitMQ默认不支持队列层面的消息广播。

4.4 Broker

消息中间件的服务节点,大多数情况下也可以将一个RabbitMQ Broker看作一台RabbitMQ服务器。

4.5 队列(Queue)

队列用于存储消息,RabbitMQ中消息只能存储在队列中。RabbitMQ的生产者生产消息并最终投递到队列中,消费者从队列中获取消息并消费。

4.6 交换器(Exchange)

通常情况下,RabbitMQ的生产者并不会直接将消息发送到队列中,而是先发送到交换器,然后由交换器路由到一个或多个队列中。如果交换器路由不到,或许可以返回给生产者,或许直接丢弃。

4.7 路由键(RoutingKey)

生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定消息的路由规则,而这个Routing Key需要与交换器类型和绑定键联合使用才能最终生效。

在交换器类型和绑定键固定的情况下,生产者在发送消息给交换器时,可以通过指定RoutingKey来决定消息流向哪个队列。

4.8 绑定建(BindingKey)

将交换器和队列关联起来的键,称之为绑定键。

4.9 绑定(Binding)

RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键,这样RabbitMQ就知道如何正确将消息路由到队列。

4.10 连接(Connection)

无论是生产者还是消费者,都需要和RabbitMQ Broker建立连接,这个连接就是一条TCP连接,也就是Connection。

4.11 通道(Channel)

创建完Connection之后,还需要创建Channel。RabbiMQ处理的每条AMQP指令都是通过Channel完成的。

Channel的出现是为了复用Connection的TCP连接,我们知道创建和销毁Tcp连接都比较耗费资源

Connection可以用来创建多个Channel实例,但是Channel实例不能在线程间共享,应用程序应该为每个线程开辟一个Channel。

5. 交换器类型

RabbitMQ常用的交换器类型有fanout、direct、topic和headers四种。除了这四种之外,AMQP协议还支持两种类型:System和自定义,不过RabbitMQ没有对其进行支持。

  • fanout

它会把所有发送到该交换器的消息路由到所有与此交换器绑定的队列中


fanout
  • direct

direct类型的交换器会把消息路由到那些BindingKeyRoutingKey完全匹配队列中。

direct

按照图示,如果在发送消息的时候设置路由键为“black”或者“green”,消息会路由到队列Q2。如果设置消息的路由键为“orange”,则会路由到队列Q1。否则,消息会被丢弃或者返回给生产者

  • topic

topic类型的交换器在direct类型之上做了升级,direct要求BindingKeyRoutingKey等值匹配,而topic只需BindingKeyRoutingKey模糊匹配即可。具体规则如下:

  1. BindingKey和RoutingKey均是一个点号“.”分割的字符串。如,“cn.zgc.rabbitmq”;
  2. BindingKey中允许两种特殊的字符“*”和“#”,其中星号“*”用于匹配一个单词,“#”用于匹配0或多个单词
topic

以上图的配置为例:
a. 路由键为“lazy.orange.rabbit”的消息会同时路由到Q1和Q2;
b. 路由键为“lazy.q1”的消息只会路由到Q2;
c. 路由键为“cn.orange.red”的消息只会路由到Q1;
d. 路由键为“cn.zgc”的消息由于没有匹配的信息,将会被丢弃或者返回给生产者。

  • headers

headers类型的交换器根据发送的消息内容中的headers属性来进行匹配。在绑定队列和交换器时指定一组键值对,当Exchange接收到消息时,会获取该消息的headers,然后和绑定时的比较。

headers类型的交换器性能比较差且不实用,所以很少应用于实际开发中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容