• RabbitMQ基础简介


    简介:

        rabbitMQ是一个消息服务的具体实现,那么什么是消息服务?

         消息服务就是两个程序时间进行通讯的标准。这里我介绍两种消息服务。一种是JMS(Java Message Service)java消息服务,通过统一的java API层面的标准,使得多个消息客户端通过JMS进行交互。另一种是AMQP(Advanced Message Queueing Protocol)高级消息队列,是协议层面的规范,因此是可以跨平台的。

        ActiveMQ是基于JMS标准实现的(两种消息发布模型:点对点和发布者订阅者模式),RabbitMQ是基于AMQP实现的,他们也称消息队列,是进程或线程之间的一种异步通信的方式。如果使用消息队列的话,消息生产者会将消息保存到消息队列里面,直到消费者消费。生产者和消费者不需要同时和消息队列交互。实现了解耦,提高系统的可靠性和可扩展性。

    应用场景:

    1. 异步处理:假设用户注册信息到数据库后,需要发送短信和邮箱通知,这是三个操作当这三个操作都执行完,在响应给用户。而当引用了消息队列的时候,最重要的是用户注册。而发送邮箱和短信只是一个通知,不影响数据的改变,因此将这两个不是必须业务逻辑异步处理。也就是放到消息队列中去。由消息队列统一分发。
    2. 应用解耦:假设用户下单后,订单通知库存系统,传统的做法就是订单系统调用库存系统的接口,如果库存系统挂了。那么订单就会失效。所以订单和库存是高度耦合的。而使用消息队列,用户下单后,完成订单系统持久化处理,将消息写入消息队列,返回用户下单成功。库存系统订阅下单消息,获取下单消息,进行库操作。就算库存出现故障,消息队列也能保证消息的可靠性。
    3. 流量削峰:假设一个秒杀活动,如果流量上亿,就会导致系统崩溃,使用消息队列,将用户请求写入消息队列中,加入消息队列长度超过最大值,控制订阅人数,当人数达到一定程度,就将请求直接丢弃或返回错误信息。减缓了短时间的高流量压垮服务器。

    基础概念:

    • Queue(队列):它的作用是用来存储消息。特征是先进先出。生产者最终将消息送到RabbitMQ的内部对象消息队列中。而消费者从消息队列中去取消息。生产者发送的消息被传送到消息队列中,消费者发现消息队列中有订阅的消息。就会将消息取出进行业务操作。这是一个消费者对应一个队列。也可以有多个消费者同时订阅一个队列,但是如果消费者对消息的处理时间不同,就会导致某些消费者一直在忙碌,有些则一直处于空闲,因此可以限制每次发送消息的个数。
    • Exchange(消息交换机):它指定消息按什么规则,路由到哪个队列。假设生产者a和b,当它发消息的时候不知道发的消息是给队列a还是给队列b,所以需要一个规则来告诉它。这里有用到了Exchange。生产者发送消息到队列要经过Exchange,由Exchange将消息路由到一个或多个队列。如果不符合路由规则的将直接丢弃。Exchange有四种类型,不同类型有不同的策略,不同的策略决定绑定的队列不同,例如生产者发送了一条消息,Routing Key的规则是A,那么生产者会将这个key为A的消息推送到Exchange中,Exchange会根据对应的规则删选生产者发的消息。如果对应上了,就推送到对应的队列中去。那么Exchange的规则有哪些呢?
    • 规则一:fanout类型,它会将所有消息路由到所有与他绑定的Queue中。
    • 规则二: direct类型的Exchange路由规则是把消息路由到那些binding key与routing key完全匹配的Queue中。
    • 规则三:topic这个规则就是模糊匹配,可以通过通配符满足一部分规则就可以传送。direct规则是严格意义上的匹配,Routing Key必须与Binding Key相匹配的时候才将消息传送给Queue。
    • 规则四:headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。
    • Connection,是RabbitMQ的Socket链接,封装了socket协议和部分逻辑,它会建立一个TCP连接,生产者和消费者同过tcp连接到RabbitMQ服务上。
    • ConnectionFactory:是Connection的制造工厂,用于生产Connection
    • Channel是RabbitMQ的重要一个接口,大部分业务操作在它里面完成,包括定义队列,消息交换机,绑定Queue和Exchange,发布消息等。它是虚拟连接,建立在Connection,tcp连接的基础上,来进行数据流动,为什么不直接建立在tcp上进行数据流动,是因为,频繁的创建和关闭tcp,对系统的性能有很大的影响,而且tcp连接是有限制的,这也限制了处理高并发的能力。

    代码实现direct类型的Exchange路由规则:

    一:创建Spring Boot项目,勾选rabbitMQ依赖,配置Rabbitmq的连接信息

    spring.rabbitmq.host=localhost
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest
    spring.rabbitmq.port=5672

    二:创建dierct配置类:

    package com.zl.rabbitmq.config;
    
    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.DirectExchange;
    import org.springframework.amqp.core.Queue;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    
    
    @Configuration
    public class rabbitDirectConfig {
        //ctrl+shift+u=小写替换成大写
        private final static String DIRECTNAME="zl";
    
    //队列
        @Bean
        Queue queue() {
    
          return new Queue("hello ,zl");
        }
    
        @Bean
        DirectExchange directExchange(){
            //重启后是否有效
            //长期未使用是否删除
           return new DirectExchange(DIRECTNAME,true,false);
        }
        //将队列和DirectExchange绑定到一起
        Binding binding(){
            return BindingBuilder.bind(queue()).to(directExchange()).with("direct");
            }
    }

          三:创建消费者:

    package com.zl.rabbitmq.receiver;
    
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    //消费者
    @Component
    public class DirecReceiver {
        @RabbitListener(queues = "hello ,zl")
        public void handler(String msg){
    
            System.out.println("handler"+msg);
        }
    }

    四:发送消息:

    package com.zl.rabbitmq;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class RabbitmqApplicationTests {
    @Autowired
    RabbitTemplate rabbitTemplate;
        @Test
        void contextLoads() {
            rabbitTemplate.convertAndSend("hello ,zl","hello zll");
        }
    
    }

    五:测试:

    2020-04-11 12:14:05.442  INFO 32 --- [           main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [localhost:5672]
    2020-04-11 12:14:05.474  INFO 32 --- [           main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#4e558728:0/SimpleConnection@43effd89 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 50208]
    2020-04-11 12:14:05.567  INFO 32 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2020-04-11 12:14:05.621  INFO 32 --- [           main] com.zl.rabbitmq.RabbitmqApplication      : Started RabbitmqApplication in 3.968 seconds (JVM running for 12.158)
    handlerhello zll

    流程:当消息到达DirectExchange的时候,会被转发到和该条消息的routing key相同的队列中去。

    消息发送者发送一条"hello zll"的消息,并指定rountingkey为"hello ,zl"。然后消息到达DirectExchange中,由binding将Exchange和队列绑定在一起,将这个消息转发到和该条消息的routing key相同的队列中。然后消费者监听这个routing key的队列。当有消息时,就打印出来。

    六:在实际应用场景中的使用:

    本篇参考我的下一篇博客 RabbitMQ在java中的使用

  • 相关阅读:
    encode 与 decode
    pthon_flask小汇总
    jquery 动态添加标签而且指定样式
    设置Myeclipse中的代码格式化、及保存时自动格式化
    a href="javascript:void(0)" 是什么意思?与 a href="#" 加不加上有什么区别?
    String类 与StringBuffer类
    Java中的String类与StringBuffer类
    获取系统的当前时间
    switch 中可以使用字符串当判断条件
    关于接口的那些事
  • 原文地址:https://www.cnblogs.com/javazl/p/12678030.html
Copyright © 2020-2023  润新知