RabbitMq笔记①——入门介绍(转载)

RabbitMq入门

概述

消息中间件介绍

我们用java来举例子, 打个比方 我们客户端发送一个下单请求给订单系统(order)订单系统发送了一个请求给我们的库存系统告诉他需要更改库存了, 我已经下单了, 这里, 每一个请求我们都可以看作一条消息。

但是我们客户端需要等待订单系统告诉我这条消息的处理结果(我到底有没有下单成功)。

可是订单系统不需要知道库存系统这条消息的处理情况,因为无论你库存有没有改动成功,我订单还是下了,因为是先下完了订单(下成功了)才去更改库存,库存如果更改出BUG了,那是库存系统的问题, 这个BUG不会影响订单系统。

如果这里你能理解的话,那么我们就能发现我们用户发送的这条消息(下订单),是需要同步的(我需要知道结果),订单发送给库存的消息,是可以异步的(我不想知道你库存到底改了没,我只是通知你我这边成功下了一个订单)那么如果我们还按原来的方式去实现这个需求的话, 那么结果会是这样:
在这里插入图片描述
这时我们可以启用线程去访问库存系统
在这里插入图片描述
使用线程池解决 确实可以, 但是也有他的缺点, 那么 到底怎么来完美解决这个问题呢?

下面这个消息系统, 就是我们的消息中间件
在这里插入图片描述

RabbitMq介绍

我们刚刚介绍了什么是消息中间件, 那么RabbitMq就是对于消息中间件的一种实现,市面上还有很多很多实现, 比如RabbitMq、ActiveMq、ZeroMq、kafka,以及阿里开源的RocketMQ等等,我们这节主要讲RabbitMq

想要了解RabbitMq就要先了解AMQP

AMQP

在这里插入图片描述
这里引用百度的一句话,再加以我的理解:AMQP 其实和Http一样,都是一种协议, 只不过 Http是针对网络传输的, 而AMQP是基于消息队列的。

AMQP中的基本概念
  • Broker:接收和分发消息的应用,我们在介绍消息中间件的时候所说的消息系统就是Message Broker。
  • Virtual host:出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建 exchange/queue 等。
  • Connection:publisher/consumer和broker之间的TCP连接。断开连接的操作只会在client端进行,Broker不会断开连接,除非出现网络故障或broker服务出现问题。
  • Channel:如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销将是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message broker识别channel,所以channel之间是完全隔离的。Channel作为轻量级的Connection极大减少了操作系统建立TCP connection的开销。
  • Exchange:message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
  • Queue:消息最终被送到这里等待consumer取走。一个message可以被同时拷贝到多个queue中。
  • Binding:exchange和queue之间的虚拟连接,binding中可以包含routing key。Binding信息被保存到exchange中的查询表中,用于message的分发依据。
Exchange的类型
  • direct

这种类型的交换机的路由规则是根据一个routingKey的标识,交换机通过一个routingKey与队列绑定 ,在生产者生产消息的时候指定一个routingKey,当绑定的队列的routingKey与生产者发送的一样,那么交换机会把这个消息发送给对应的队列。

  • fanout

这种类型的交换机路由规则很简单,只要与他绑定了的队列, 他就会把消息发送给对应队列(与routingKey没关系)。

  • topic

这种类型的交换机路由规则也是和routingKey有关,只不过topic可以根据*#*代表过滤一单词,#代表过滤后面所有单词, 用.隔开)来识别routingKey。

假设我绑定的routingKey有队列A和B,A的routingKey是*.user,B的routingKey是#.user

那么我生产一条消息routingKey为error.user那么此时 2个队列都能接受到, 如果改为topic.error.user那么这时候,只有B能接受到了。

  • headers

这个类型的交换机很少用到,他的路由规则 与routingKey无关 而是通过判断header参数来识别的, 基本上没有应用场景,因为上面的三种类型已经能应付了。

RabbitMQ

MQ:Message Queue 顾名思义是消息队列, 队列大家都知道, 存放内容的一个东西, 存放的内容先进先出, 消息队列, 只是里面存放的内容是消息而已。

RabbitMq是一个开源的,基于AMQP协议实现的一个完整的企业级消息中间件,服务端语言由Erlang(面向并发编程)语言编写对于高并发的处理有着天然的优势,客户端支持非常多的语言:

  • Python
  • Java
  • Ruby
  • PHP
  • C#
  • JavaScript
  • Go
  • Elixir
  • Objective-C
  • Swift
主流MQ对比
特性ActiveMQRabbitMQRocketMQKafka
单机吞吐量万级,比 RocketMQ、Kafka 低一个数量级同 ActiveMQ10 万级,支撑高吞吐10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景
topic 数量对吞吐量的影响topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topictopic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源
时效性毫秒级微秒级,这是 RabbitMQ 的一大特点,延迟最低毫秒级毫秒级
可用性高,基于主从架构实现高可用同 ActiveMQ非常高,分布式架构非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性有较低的概率丢失数据经过参数优化配置,可以做到 0 丢失同 RocketMQ
功能支持MQ 领域的功能极其完备基于 erlang 开发,并发能力很强,性能极好,延时很低MQ 功能较为完善,还是分布式的,扩展性好功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用

RabbitMQ服务端部署

在介绍消息中间件的时候所提到的“消息系统”便是我们这节的主题。RabbitMq如同redis一样,他也是采用c/s架构,由服务端与客户端组成,我们现在我们计算机上部署他的服务端。

  • 安装Erlang和RabbitMQ

由于我们刚刚介绍过了RabbitMQ服务端是由Erlang语言编写所以我们这里先下载Erlang语言的环境。

注意:如果是在官网下的RabbitMQ服务端的话 Erlang语言的版本不能太低, 不然要卸载掉旧的去装新的, 我们这里下载OTP21.0版本直接从外网下载会很慢, 我这里直接贴上百度网盘的地址(因为这个东西还是有点大的)。

https://pan.baidu.com/s/1pZJ8l2f3omrgnuCm9a8DVA

我们再去官网下载RabbitMq的服务端安装包

http://www.rabbitmq.com/download.html

在这里插入图片描述

注意需要先下载Erlang再下载安装包安装, 不然安装RabbitMQ服务端的时候会提示你本地没有Erlang环境。

  • 启动RabbitMQ

在系统-服务中找到如下即可
在这里插入图片描述

  • 启动RabbitMQ管理工具

RabbitMQ安装会附带一个管理工具(方便我们能直观的查看整个RabbitMQ的运行状态和详细数据等,有点像Navicat 对应Mysql的关系) 值得一提的是, 管理工具和RabbitMQ是两码事,希望不要混稀了。

到你们安装的RabbitMQ Server\rabbitmq_server-3.7.12\sbin目录下面执行一条cmd命令

rabbitmq-plugins enable rabbitmq_management

当然也可以配置一个环境变量或者在我们的开始菜单栏中找到下面这个Command
在这里插入图片描述

然后就可以访问http://127.0.0.1:15672管理页面
在这里插入图片描述
存在默认的账号,密码和账号都是guest
在这里插入图片描述
下面演示一下如何删除和添加用户

  1. 首先点击admin页签, 在下面找到Add User
    在这里插入图片描述
  2. 然后输入账号 密码 确认密码 这个Tags其实是一个用户权限标签, 关于他的介绍可以看官方介绍(点旁边那个小问号就好了,我这里直接翻译他的介绍)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. 填写完之后点击AddUser 就可以添加一个用户了, 添加完用户之后还要给这个用户添加对应的权限(注:Targ不等于权限),比如说刚刚添加了一个jojo角色
    在这里插入图片描述
  4. 点击这个jojo可以进去给他添加权限,这个权限可以是 Virtual host 级别的,也可以是交换机级别的,甚至是细化到某一个读写操作,这里就给他添加一个Virtual host权限
    在这里插入图片描述
    这里 我们给了他 testhost这个Virtual host的权限 正则匹配都是* 也就是所有权限
    然后点击set添加完毕。

RabbitMq客户端

这里简单介绍一下java代码如何连接RabbitMq和使用RabbitMq的。而且在消息系统中存在两个角色,生产者和消费者,顾名思义,一个负责生产信息,将信息放到RabbitMq消息队列中,而另一个则是从RabbitMq消息队列中拿到想要的信息。

下面会分别介绍两种角色是如何通过java代码使用完成自己的工作的。

引入依赖

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.1.2</version>
</dependency>

连接工具类

不论是生产者还是消费者都需要和RabbitMq连接,而且两者连接的代码都是一样的,因为两者都属于是RabbitMq的客户端。

public class ConnectionUtil {

    public static final String QUEUE_NAME  = "testQueue";

    public static  final  String EXCHANGE_NAME = "exchange";

    public static Connection getConnection() throws Exception{
        //创建一个连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //设置rabbitmq 服务端所在地址 我这里在本地就是本地
        connectionFactory.setHost("127.0.0.1");
        //设置端口号,连接用户名,虚拟地址等
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("jojo");
        connectionFactory.setPassword("jojo");
        connectionFactory.setVirtualHost("testhost");
        return connectionFactory.newConnection();
    }
}

生产者

public class Producer {

    public static void sendByExchange(String message) throws Exception {

        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(ConnectionUtil.QUEUE_NAME,true,false,false,null);
        // 声明exchange
        channel.exchangeDeclare(ConnectionUtil.EXCHANGE_NAME, "fanout");
        //交换机和队列绑定
        channel.queueBind(ConnectionUtil.QUEUE_NAME, ConnectionUtil.EXCHANGE_NAME, "");
        channel.basicPublish(ConnectionUtil.EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println("发送的信息为:" + message);
        channel.close();
        connection.close();
    }
}

消费者

public class Consumer {
    public static void getMessage() throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
//        channel.queueDeclare(ConnectionUtil.QUEUE_NAME,true,false,false,null);
        DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(new String(body, "UTF-8"));
            }
        };
        channel.basicConsume(ConnectionUtil.QUEUE_NAME, deliverCallback);
    }

    public static void main(String[] args) {
        try {
            getMessage();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值