RabbitMq

MQ消息队列:负责数据的传接受,存储和传递。性能要过于普通服务和技术

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lW0WwS9x-1659964424459)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716111756495.png)]

为什么消息中间件不直接使用http协议呢

  1. 因为http请求报文头和响应报文头是比较复杂的,包含了cookie,数据的加密解密,状态码,响应码等附加的功能,但是对于一个消息而言,我们并不需要这么复杂,也没有这个必要性,它其实就是负责数据传递,存储,分发就行,一定要追求的是高性能。尽量简洁,快速。
  2. 大部分情况下http大部分都是短链接,在实际的交互过程中,一个请求到响应很有可能会中断,中断以后就不会就行持久化,就会造成请求的丢失。这样就不利于消息中间件的业务场景,因为消息中间件可能是一个长期的获取消息的过程,出现问题和故障要对数据或消息就行持久化等,目的是为了保证消息和数据的高可靠和稳健的运行。

协议

AMQP协议

AMQP:(全称: Advanced Message Queuing Protocol)是高级消息队列协议。由摩根大通集团联合其他公司共同设计。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。

特性

  1. 分布式事务支持
  2. 消息的持久化支持
  3. 高性能和高可靠的消息处理优势。
MQTT协议

MQTT协议: (Message Queueing Telemetry Transport)消息队列是IBM开放的一个即时通讯协议,物联网系统架构中的重要组成部分。

特点:

  1. 轻量
  2. 结构简单
  3. 传输快,不支持事务
  4. 没有持久化设计。

应用场景:

  1. 适用于计算能力有限

  2. 低带宽

  3. 网络不稳定的场景。

Kafka协议

Kafka协议是基于TCP/IP的二进制协议。消息内部是通过长度来分割,由一些基本数据类型组成。

特点:

  1. 结构简单
  2. 解析速度快
  3. 无事务支持
  4. 有持久化设计

持久化方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQqSH9EB-1659964424461)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716112854360.png)]

消息的分发策略机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a32rGb95-1659964424462)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716113022608.png)]

安装

第一步下载erlang

1.下载erlang的gz包,tar -zxvf 解压erlang包

2.进入到erlang目录下,使用make install安装

报错解决方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKt3nJLL-1659964424463)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716132130091.png)]

解决方法:

yum install gcc-c++

错误:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KzkClLDL-1659964424463)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716132154446.png)]

解决方法:

yum install perl

错误:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ThDiO5De-1659964424464)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716132216606.png)]

解决方法:

yum -y install ncurses-devel

然后执行一次make编译

最后配置环境变量

erl -version查看是否安装上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2o7go2CQ-1659964424465)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716132343286.png)]

npm方式推荐

rpm -Uvh erlang-23.2.7-2.el8.x86_64.rpm

yum install -y erlang

erl -v 查看版本

第二步下载socat

yum install -y socat

第三步下载rabbitmq

rpm -Uvh rabbitmq-server-3.8.14-1.el8.noarch.rpm

yum install -y rabbitmq-server

启动 rabbitmq :systemctl start rabbitmq-server

查看 rabbitmq状态 : systemctl status rabbitmq-server

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VDEznyNb-1659964424466)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716175716625.png)]

在/etc文件下使用rabbitmq-plugins enable rabbitmq_management开启web端访问

添加用户

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-syZzW4fu-1659964424467)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716181120330.png)]

  • rabbitmqctl add_user 用户名 密码

  • set_user_tags 用户名 权限 设置用户权限

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChK8708c-1659964424467)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716181303859.png)]

​ change_password 用户 新密码

  • list_users 用户列表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T1TuHUKR-1659964424468)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220716184317302.png)]

  • 给用户赋予访问权限

​ rabbitmqctl set_permissions -p / admin ‘.’ '.’ ‘.*’

​ 给admin用户赋予‘/’目录的访问权限不然后续操作报错比如以下问题

​ com.rabbitmq.client.ShutdownSignalException: connection error;

java示例代码

依赖

  com.rabbitmq
  amqp-client
  5.10.0

public class Producer extends Thread{

    @Override
    public void run() {
        //  创建连接工程
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("tencent");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        connectionFactory.setVirtualHost("/");//消息放在根结点上
        //  创建连接Connection
        Connection connection = null;
        //  通过连接创建通道Channel
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection("生产者");
            channel = connection.createChannel();

            // 通过通道创建交换机,声明队列,绑定关系,路由key,发送消息和接收消息

            final String EXCHANGE_NAME = "testfanout";
            //创建交换机
            /**
             * 1.exchange:交换机名称
             * 2.type:交换机的类型
             *      DIRECT("direct"):定向
             *      FANOUT("fanout"):广播
             *      TOPIC("topic"):通配符方式
             *      HEADERS("headers"):参数匹配
             * 3.durable:是否持久化
             * 4.autoDelete:自动删除
             * 5.internal:内部使用:false
             * 6.arguments:参数
             */
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT,false,false,false,null);
            String queueName = "queue6";
            String queueName2 = "queue7";
            /**
             * @param1 队列的名称
             * @param2 是否持久化 false,消息是否存盘
             * @param3 排他性,是否独占独立
             * @param4 是否自动删除,随着最后一个消费者消息完毕信息以后是否把队列自动删除
             * @param5 携带附属参数
             */
            channel.queueDeclare(queueName,true,false,false,null);
            channel.queueDeclare(queueName2,true,false,false,null);
            /**
             *
             * 绑定交换机和队列的关系
             * String queue, String exchange, String routingKey
             * 参数
             *   1.queue:队列名称
             *   2.exchange:交换机名称
             *   3.routingKey:路由键:绑定规则
             *   如果交换机的类型是FANOUT,那么路由键为空
             */
            channel.queueBind(queueName,EXCHANGE_NAME,"");
            channel.queueBind(queueName2,EXCHANGE_NAME,"");
            // 准备消息内容
            String message = "hello rabbitmq";
            //  发送消息给队列queue
            /**
             * @param1 交换机
             * @param2 队列,路由
             * @param3 消息的控制状态
             * @param4 消息主题
             * 不可能存在没有交换机的队列,虽然没有指定交换机但是一定会存在一个默认的交换机
             */
            channel.basicPublish(EXCHANGE_NAME,"", null,message.getBytes());
            System.out.println("消息发送成功");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            //      关闭通道
            if(channel!=null && channel.isOpen()){
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            //  关闭连接
            if(connection!=null && connection.isOpen()){
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) {
        new Thread(new Producer()).start();
        new Thread(new Producer()).start();
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8jUKYuC-1659964424468)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220719203629453.png)]

Rabbitmq核心组成部分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bh9tfEBL-1659964424469)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220719210243636.png)]

  • Server:又称Broker ,接受客户端的连接,实现AMQP实体服务。安装rabbitmq-server
  • Connection:连接,应用程序与Broker的网络连接TCP/IP/三次握手和四次挥手
  • Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道,客户可以建立对各Channel,每个Channel代表一个会话任务。
  • Message :消息:服务与应用程序之间传送的数据,由Properties和body组成,Properties可是对消息进行修饰,比如消息的优先级,延迟等高级特性,Body则就是消息体的内容。
  • Virtual Host 虚拟地址,用于进行逻辑隔离,最上层的消息路由,一个虚拟主机理由可以有若千个Exhange和Queueu,同一个虚拟主机里面不能有相同名字的Exchange
  • Exchange:交换机,接受消息,根据路由键发送消息到绑定的队列。(不具备消息存储的能力)Bindings: Exchange和Queue之间的虚拟连接,binding中可以保护多个routing key.
  • Routing key:是一个路由规则,虚拟机可以用它来确定如何路由一个特定消息。
  • Queue:队列:也成为Message Queue,消息队列,保存消息并将它们转发给消费者。

运行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K0bRxQGo-1659964424469)(C:\Users\OMEN\AppData\Roaming\Typora\typora-user-images\image-20220720172116371.png)]

Spring整合RabbitMq

xml方式
生产者配置
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:rabbitmq.properties"/>

    
    
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>
    
    
    <rabbit:admin connection-factory="connectionFactory"/>

    
    

    <rabbit:queue id="spring_queue" name="spring_queue"    auto-declare="true"/>

    
    
    <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true" />

    
    <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true"/>

    
    <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange"  auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding  queue="spring_fanout_queue_1"  />
            <rabbit:binding queue="spring_fanout_queue_2"/>
        rabbit:bindings>
    rabbit:fanout-exchange>


    
    <rabbit:queue id="spring_direct_queue" name="spring_direct_queue"  auto-declare="true"/>

    
    <rabbit:direct-exchange name="spring_direct_exchange" >
        <rabbit:bindings>
            
            <rabbit:binding queue="spring_direct_queue" key="info">rabbit:binding>
        rabbit:bindings>

    rabbit:direct-exchange>

    
    
    <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star"  auto-declare="true"/>
    
    <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/>

    
    <rabbit:topic-exchange id="spring_topic_exchange"  name="spring_topic_exchange" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding pattern="com.*"  queue="spring_topic_queue_star"/>
            <rabbit:binding pattern="wjh.#" queue="spring_topic_queue_well"/>
        rabbit:bindings>
    rabbit:topic-exchange>

    
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>

beans>
消费者配置
<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:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
    <context:property-placeholder location="classpath:rabbitmq.properties"/>

    
    
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}"
                               password="${rabbitmq.password}" virtual-host="${rabbitmq.virtual-host}"/>

    <bean id = "springQueueListener" class="com.wjh.rabbitmq.Listener"/>

    <rabbit:listener-container connection-factory="connectionFactory" >
        <rabbit:listener  queue-names="spring_queue"  ref="springQueueListener"/>
    rabbit:listener-container>

beans>
生产者代码
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void shouldAnswerWithTrue() throws JsonProcessingException {
    ObjectMapper objectMapper =new ObjectMapper();
    Student s = new Student();
    s.setAge(1);
    s.setName("wjh");
    String msg = objectMapper.writeValueAsString(s);
    rabbitTemplate.convertAndSend("spring_queue",msg);//往队列里面发送消息
}
消费者代码
public class Listener implements MessageListener {
    @Override
    public void onMessage(Message message) {
        //打印消息
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            Student student = objectMapper.readValue(message.getBody(),Student.class);
            System.out.println(student);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

boot整合RabbitMq

生产者配置
spring:
  rabbitmq:
    host: tencent
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    //开启手动应答,回调函数
    publisher-confirm-type: correlated
    publisher-returns: true

Exchange:
  topicName: boot_Exchange

Queue:
  name: boot_Queue
消费者配置
spring:
  rabbitmq:
    host: tencent
    port: 5672
    username: admin
    password: admin
    virtual-host: /

Exchange:
  topicName: boot_Exchange

Queue:
  name: boot_Queue
spring.rabbitmq.listener.simple.auto-startup=true: 是否启动时自动启动容器
spring.rabbitmq.listener.simple.acknowledge-mode: 表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
spring.rabbitmq.listener.simple.concurrency: 最小的消费者数量
spring.rabbitmq.listener.simple.max-concurrency: 最大的消费者数量
spring.rabbitmq.listener.simple.prefetch: 一个消费者最多可处理的nack消息数量,如果有事务的话,必须大于等于transaction数量.
spring.rabbitmq.listener.simple.transaction-size: 当ack模式为auto时,一个事务(ack间)处理的消息数量,最好是小于等于prefetch的数量.若大于prefetch, 则prefetch将增加到这个值
spring.rabbitmq.listener.simple.default-requeue-rejected: 决定被拒绝的消息是否重新入队;默认是true(与参数acknowledge-mode有关系)
spring.rabbitmq.listener.simple.missing-queues-fatal=true 若容器声明的队列在代理上不可用,是否失败; 或者运行时一个多多个队列被删除,是否停止容器
spring.rabbitmq.listener.simple.idle-event-interval: 发布空闲容器的时间间隔,单位毫秒
spring.rabbitmq.listener.simple.retry.enabled=false: 监听重试是否可用
spring.rabbitmq.listener.simple.retry.max-attempts=3: 最大重试次数
spring.rabbitmq.listener.simple.retry.max-interval=10000ms: 最大重试时间间隔
spring.rabbitmq.listener.simple.retry.initial-interval=1000ms:第一次和第二次尝试传递消息的时间间隔
spring.rabbitmq.listener.simple.retry.multiplier=1: 应用于上一重试间隔的乘数
spring.rabbitmq.listener.simple.retry.stateless=true: 重试时有状态or无状态

spring.rabbitmq.listener.direct.acknowledge-mode= ack模式
spring.rabbitmq.listener.direct.auto-startup=true 是否在启动时自动启动容器
spring.rabbitmq.listener.direct.consumers-per-queue= 每个队列消费者数量.
spring.rabbitmq.listener.direct.default-requeue-rejected= 默认是否将拒绝传送的消息重新入队.
spring.rabbitmq.listener.direct.idle-event-interval= 空闲容器事件发布时间间隔.
spring.rabbitmq.listener.direct.missing-queues-fatal=false若容器声明的队列在代理上不可用,是否失败.
spring.rabbitmq.listener.direct.prefetch= 每个消费者可最大处理的nack消息数量.
spring.rabbitmq.listener.direct.retry.enabled=false  是否启用发布重试机制.

TTL

整个队列消息的存活时间

@Bean("bootQueue")
public Queue bootQueue(){
    return QueueBuilder.durable(Queue_Name).ttl(30000).build();//设置ttl,单位ms
}

单个消息的存活时间

MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setExpiration("3000");//消息过期时间
        return message;
    }
};
rabbitTemplate.convertAndSend(Exchange_Name,"boot.haha","boot mq hello",messagePostProcessor);

两者都设置了时间以时间短的为准
n(“bootQueue”)
public Queue bootQueue(){
return QueueBuilder.durable(Queue_Name).ttl(30000).build();//设置ttl,单位ms
}


单个消息的存活时间

```java
MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setExpiration("3000");//消息过期时间
        return message;
    }
};
rabbitTemplate.convertAndSend(Exchange_Name,"boot.haha","boot mq hello",messagePostProcessor);

两者都设置了时间以时间短的为准

你可能感兴趣的:(java-rabbitmq,rabbitmq,java)