RabbitMQ(一)helloworld

本文介绍了RabbitMQ的基本概念,包括作为消息中间件的作用、使用MQ解决流量削峰、应用解耦和异步处理问题。还详细讲解了RabbitMQ的选择,以及如何通过RabbitMQ实现简单的生产者消费者模式。

1.1 MQ的相关概念

1.1.1 什么是MQ

MQ,从字面意思上看,本质是个队列,FIFO先入先出,只不过队列中存放的内容是message而已,还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中,MQ是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通信机制。使用了MQ之后,消息发送上游只需要依赖MQ,不用依赖其他服务。

1.1.2 为什么要使用MQ

  • 流量削峰

    • 举个例子,如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单绰绰有余,但是在高峰期,有两万次下单系统处理不了,只能限制不允许下单。使用消息队列做缓存,可以取消这个限制,把1秒内下的订单分散成一段时间处理。

  • 应用解耦

    • 以电商应用为例,应用中有订单系统、库存系统、物流系统、支付系统。用户创建订单后,如果耦合调用,任何一个子系统出了故障,都会造成下单操作异常。当转变成基于消息队列的方式后,系统间调用的问题会减少很多,比如物流系统发送故障,需要几分钟来修复。在这几分钟的时间,物流系统要处理的数据被缓存在消息队列中,用户的下单操作可以正常完成。当物流系统恢复后,继续处理消息。

  • 异步处理

    • 有些服务是异步的,例如A调用B,B需要花很长时间,但是A需要知道B什么时候执行完。以前一般有两种方式,a过一段时间调用b的api去查询,或者A提供一个callback方法。但是这样不太优雅。我们可以B处理完后,发送一条消息给A服务,A可以及时的得到异步处理的消息。

 

1.1.3 RabbitMQ基本介绍

2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。

由于erlang语言的高并发特性,性能较好;吞吐量到万级,MQ功能比较完备,健壮、稳定、易用、跨平台、支持多种语言。社区活跃度高,更新频率相当高。

1.1.4 MQ的选择

  1. Kafka

    KafKa主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的互联网服务的数据收集业务。

  2. RocketMQ

    天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量的交易涌入时,后端可能无法及时处理的情况。

  3. RabbitMQ

    结合erlang语言本身的并发优势,性能好时效性微秒级,社区活跃度也比较高,管理界面用起来十分方便,如果你的数据量没那么大,中小型公司优先选择功能比较完备的RabbitMQ。

1.2 RabbitMQ

1.2.1 基本概念

RabbitMQ是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放在快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑RabbitMQ是一个快递站,一个快递员帮你传递快件。RabbitMQ与快递站的主要区别在于,它不处理快件而是接收,存储和转发消息数据。

 

1.2.2 核心部分

 

1.2.3 各个名词解释

 

Broker:接收和分发消息的应用,RabbitMQ Server就是Message Broker

Virtual host:处于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建 exchange/queue等

Connection:publisher/consumer和broker之间的TCP连接

Channel:如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message broker识别channel,所以channel之间是完全隔离的。

Exchange:message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue中。常用的类型有:direct(point-to-point),topic(publish-subscribe)and fanout(multicast)

Queue:消息最终被送到这里等待consumer取走

Binding:exchange和queue之间的虚拟连接,binding可以包含routing key,Binding信息被保存在exchange中的查询表中,用户message的分发依据

1.2.4 安装

1)官网地址

https://rabbitmq.com/download.html

2)文件上传

上传到 /usr/local/software目录下

3)安装文件

rpm -ivh erlang-21.3-1.el7.x86_64.rpm
yum install socat -y
rpm -ivh rabbitmq-server-3.8.8-1.el7.noarch.rpm

4)常用命令

# 添加开机启动RabbitMQ服务
chkconfig rabbitmq-server on
# 启动服务
/sbin/service rabbitmq-server start
# 查看服务状态
/sbin/service rabbitmq-server status
# 停止服务
/sbin/service rabbitmq-server stop
# 开启web管理插件
rabbitmq-plugins enable rabbitmq_management

访问:http://xxx.xxx.xxx.xxx:15672/

初始化帐号和密码为:guest/guest

我们发现权限不足,无法访问

 

1.2.6 添加一个新的帐号

#当前用户和角色
rabbitmqctl list_users
​
# 创建帐号
rabbitmqctl add_user admin 123
# 设置用户角色
rabbitmqctl set_user_tags admin administrator
​
# 设置用户权限
set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
# 设置用户admin具有/vhost1这个virtual host中所有资源的配置、写、读权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"

此时我们用刚添加的admin/123登陆

 

2. Hello world

在下图中,“P”是我们的生产者,“C”是我们的消费者,中间的框是一个队列-RabbitMQ,代表使用者保留的消息缓冲区

 

2.1 引入依赖

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <!--rabbitmq 依赖客户端-->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.8.0</version>
        </dependency>
        <!--操作文件流的一个依赖-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

2.2 生产者

public class Producer {
    private final static String QUEUE_NAME = "hello";
    public static void main(String[] args) throws Exception {
        //创建一个连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("xxx.xxx.xxx.xxx");
        factory.setUsername("admin");
        factory.setPassword("123");
        //channel 实现了自动 close 接口 自动关闭 不需要显示关闭
        try(Connection connection = factory.newConnection(); Channel channel =
                connection.createChannel()) {
            /**
             * 生成一个队列
             * 1.队列名称
             * 2.队列里面的消息是否持久化 默认消息存储在内存中
             * 3.该队列是否只供一个消费者进行消费 是否进行共享 true 可以多个消费者消费
             * 4.是否自动删除 最后一个消费者端开连接以后 该队列是否自动删除 true 自动删除
             * 5.其他参数
             */
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);
            String message="hello world";
            /**
             * 发送一个消息
             * 1.发送到那个交换机
             * 2.路由的 key 是哪个
             * 3.其他的参数信息
             * 4.发送消息的消息体
             */
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            System.out.println("消息发送完毕");
        }
    }
}

我们执行以下生产者,发送一条消息。

可以发现rabbit管理页面对应的队列中有一条消息处于准备消费的状态。

 

2.3 消费者

public class Consumer {
    private final static String QUEUE_NAME = "hello";
​
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("xxx.xxx.xxx.xxx");
        factory.setUsername("admin");
        factory.setPassword("123");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        System.out.println("等待接收消息....");
        //推送的消息如何进行消费的接口回调
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody());
            System.out.println(message);
        };
        //取消消费的一个回调接口 如在消费的时候队列被删除掉了
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println("消息消费被中断");
        };
        /**
         * 消费者消费消息
         * 1.消费哪个队列
         * 2.消费成功之后是否要自动应答 true 代表自动应答 false 手动应答
         * 3.消费者未成功消费的回调
         * 4.消费者取消消息的回调
         */
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, cancelCallback);
    }
}

可以看到刚生产的消息被消费了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值