rabbitmq详解

MQ的概念

  1. 概念

Message Queue是用于存储消息的容器,多用于分布式系统之间的通信。
引入中间件

  1. 优势
  • 解耦在这里插入图片描述
    不同系统之间的耦合度越高,容错性和可维护性就越低。
    在这里插入图片描述引入中间件可以降低不同系统之间的耦合度,提高容错和可维护性。
  • 异步提速
    在这里插入图片描述
    不引入MQ时,一个订单操作需要等待库存、支付、物流等系统的返回结果最后数据库完成交互,假设其耗时如上共需920ms。
    在这里插入图片描述
    在引入MQ做异步提速后(提高了用户体验和系统吞吐量),订单系统只需和MQ、DB进行交互,就用户体验而言仅需25ms即可获得响应,其余操作通过异步的方式执行。
  • 削峰填谷
    削峰填谷
    当请求数量突增时,有可能超过系统的处理能力时,如果拒绝消息会造成系统接下来一段时间的空闲,可以将其积压在MQ中(削峰),在高发时期过后(积压的消息还未消费完时),系统可以去消费积压在MQ中的消息(填谷),使系统的并发数量保持在较高水平,可以提高系统的稳定性。
  1. 劣势
    在这里插入图片描述
    系统在添加了MQ之后,业务全部依赖于MQ,一旦MQ宕机或者出现其他故障,就会对业务造成影响(降低了系统的稳定性),因此如何保证MQ的高可用、如何保证消息的不丢失也是一大问题。
  • 如何保证MQ的高可用
  • 如何保证消息不丢失
  1. 常见的 MQ 产品
    在这里插入图片描述

1.安装rabbitmq

待补充。

2.快速入门

RabbitMQ中的相关概念:
在这里插入图片描述
Broker:接收和分发消息的应用,RabbitMQ Server就是 Message Broker

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

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

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

2.1简单模式

  1. 首先创建一个项目,在pom文件中添加rabbitmq客户端依赖。

<dependencies>
//rabbitmq客户端依赖
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
</dependencies>
  1. 编写生产者发送消息

// 创建rabbitmq工具类,发送者发送消息之前,用于建立与rabbitmq服务器之间的链接。
public class RabbitUtils {
    private static ConnectionFactory connectionFactory = new ConnectionFactory();

    static {
//        rabbitmq的服务器地址
        connectionFactory.setHost("127.0.0.1");
//        5672是RabbitMQ的默认端口号
        connectionFactory.setPort(5672);
//        登录用户的名称
        connectionFactory.setUsername("guest");
//        登录用户的密码
        connectionFactory.setPassword("guest");
//        VirtualHost(“选择数据库:可以理解为mysql使用表格之前需要先创建数据库。”)
        connectionFactory.setVirtualHost("/test");
    }

    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = connectionFactory.newConnection();
            return conn;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}


//创建生产者(简单模式)
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //获取TCP长连接
        Connection conn = RabbitUtils.getConnection();
        //创建通信“通道”,相当于TCP中的虚拟连接
        Channel channel = conn.createChannel();
        //创建队列,声明并创建一个队列,如果队列已存在,则使用这个队列
        //第一个参数:队列名称ID
        //第二个参数:是否持久化,false对应不持久化数据,MQ停掉数据就会丢失
        //第三个参数:是否队列私有化,false则代表所有消费者都可以访问,true代表只有第一次拥有它的消费者才能一直使用,其他消费者不让访问
        //第四个:是否自动删除,false代表连接停掉后不自动删除掉这个队列
        //其他额外的参数, null
        channel.queueDeclare("helloworld",false, false, false, null);
        String message = "firstMessage";
        //四个参数
        //exchange 交换机,暂时用不到,在后面进行发布订阅时才会用到
        //队列名称
        //额外的设置属性
        //最后一个参数是要传递的消息字节数组
        channel.basicPublish("", RabbitConstant.QUEUE_HELLOWORLD, null,message.getBytes());
        channel.close();
        conn.close();
        System.out.println("===发送成功===");

    }
}
  1. 编写消费者消费消息

public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {

         Connection conn = RabbitUtils.getConnection();
         Channel channel = conn.createChannel();
channel.queueDeclare(RabbitConstant.QUEUE_HELLOWORLD,false, false, false, null);

        //从MQ服务器中获取数据
        //创建一个消息消费者
        //第一个参数:队列名
        //第二个参数代表是否自动确认收到消息,false代表手动编程来确认消息,这是MQ的推荐做法
        //第三个参数要传入DefaultConsumer的实现类()
        channel.basicConsume("helloworld", false, new Reciver(channel));


    }
}


class  Reciver extends DefaultConsumer {

    private Channel channel;
    //重写构造函数,Channel通道对象需要从外层传入,在handleDelivery中要用到
    public Reciver(Channel channel) {
        super(channel);
        this.channel = channel;
    }

    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

         String message = new String(body);
         System.out.println("消费者接收到的消息:"+message);

         System.out.println("消息的TagId:"+envelope.getDeliveryTag());
        //false只确认签收当前的消息,设置为true的时候则代表签收该消费者所有未签收的消息
         channel.basicAck(envelope.getDeliveryTag(), false);
    }
}

实现效果
在这里插入图片描述

在这里插入图片描述
这里需要注意:生产者在发送消息之后channel.close();conn.close();关闭了通道链接和客户端链接。而消费者不关闭。

持续更新中

2.2工作模式

  • 工作模式
  • 订阅模式
  • 路由模式
  • 通配符模式
  • 消息确认机制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值