RabbitMQ Learning (II): Basic Concepts of RabbitMQ

RabbitMQ related concepts

  • RabbitMQ is an Erlang development of the AMQP (Advanced Message Queuing Protocol, Advanced Message Queuing Protocol) is an open source implementation. Is an open standard application-layer protocol for message-oriented middleware design. Message middleware mainly for decoupling between the components, sender of the message without knowing the user's presence message.
  • Main features
    1. Reliability: Persistence, confirm the transfer, release confirmation mechanisms to ensure reliability.
    2. Scalability: supports dynamic expansion of the cluster nodes
    3. High Availability: The queue can set up a mirror in a cluster, some problems remain available node
    4. Multi-protocol: AMQP protocol, STOMP, MOTT other messaging middleware protocols
    5. Multi-language: java, Python, Ruby, PHP, C #, JavaScript, Go, Object-C, etc.
    6. Supports plug-ins: If the web management side.
  • Message queue has three basic concepts: the sender, message queues, consumer. RabbitMQ on this basic concept, do a layer of abstraction between the person and the message queue, the added switch (Exchange). Such a message and message queue is no direct link, in turn, becomes a message by the message to the switch, the switch forwards to the message queue then the message according to the scheduling policy. A message producer does not directly send messages to the message queue, instead, sends the message to the Exchange Exchange by establishing the Channel. Exchange according to the routing rules, forwards the message to the designated message queue. Message queue message storage, message waiting consumer withdraws. Consumers, get messages from the message queue by creating a message queue coupled to the Channel.

RabbitMQ Application Models

Here Insert Picture Description

    // 获取MQ的连接  下面代码获取连接都是使用的这个工具类
    public static Connection newConnection() throws IOException, TimeoutException {
        // 1.创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        // 2.设置连接地址
        factory.setHost("192.168.100.150");
        // 3.设置用户名称
        factory.setUsername("admin");
        // 4.设置用户密码
        factory.setPassword("admin");
        // 5.设置amqp协议端口号
        factory.setPort(5672);
        // 6.设置VirtualHost地址
        factory.setVirtualHost("adminDemo");
        Connection connection = factory.newConnection();
        return connection;
    }
  • Simple mode
    Here Insert Picture Description
    • Message generation message, the message on the queue
    • Consumers message (consumer) listen (while) the message queue, the queue if there are messages, they consumed, the message is taken away automatically deleted from the queue.
    • Demo Demonstration
    private static String QUEUE_NAME = "demo_hello";
      //获取连接
        Connection connection = MQConnectionUtils.newConnection();
        //创建通道
        Channel channel = connection.createChannel();
        // 创建一个队列:队列名称,是否持久化,是否自动删除队列,是否排外
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        for (int i = 1; i <= 25; i++) {
            // 创建 msg
            String msg = "生成 ---" + i;
            // 生产者发送消息者     MessageProperties.PERSISTENT_TEXT_PLAIN 设置消息的持久化(消息没有接收到也不会丢失)
            channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes("UTF-8"));
        }
        // 关闭通道和连接
        channel.close();
        connection.close();

Here Insert Picture Description

    private static String QUEUE_NAME = "demo_hello";
     	 //获取连接
        Connection connection = MQConnectionUtils.newConnection();
       	 //创建通道
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
                DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            // 监听获取消息
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
            }
        };
        // 设置应答模式 如果为true情况下 表示为自动应答模式 false 表示为手动应答
        channel.basicConsume(QUEUE_NAME, true, defaultConsumer);

Here Insert Picture Description

  • work queues (mode of operation)
    Here Insert Picture Description
    • More consumers can subscribe to the same queue, then the messages in the queue will be apportioned equally to more consumers are processed, but not every consumer
      who will receive all messages and handle.
    • Then if the processing time for each message is different, it may cause some consumers have been busy, but under some other consumers will soon finish the work at hand and has been idle. We can set prefetchCount each Queue to restrict the number of messages sent to each consumer, such as we set prefetchCount = 1, then sends a message to each Queue each consumer; Consumers finished processing the message will Queue give the consumer sends a message.
    • Demo demo
      work queue just to the top of consumers to copy a bit on it.
      If the discovery message may be provided to distribute unevenly
        /**
         * 公平队列原理:队列服务器向消费者发送消息的时候,消费者采用手动应答模式,
         * 队列服务器必须要收到消费者发送ack结果通知,才会继续发送一下一个消息
         * 此处设置一次只消费1个
         */
        channel.basicQos(1);

By default, rabbitmq opened the autoresponder message. In this case, once rabbitmq distribute messages to the consumer, the message will be deleted from memory. In this case, if the consumer is doing is to "kill" or "collapse", you will lose the message being processed. If you want to make sure that the message is not lost, we need to set the message answering mode to manual answer. After the hand-set answer, consumer acceptance and processed a message, it sends a reply to rabbitmq, rabbitmq after receiving the response, the article will be deleted from the message memory. If a consumer in the course of processing a message in the "collapse", rabbitmq no response is received, then the "collapse" message before being processed will be re-distributed to other consumers.

        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                // 手动应答 模式 告诉给队列服务器 已经处理成功
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        // 4.设置应答模式 如果为true情况下 表示为自动应答模式 false 表示为手动应答
        channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
  • publish / subscribe (publish-subscribe)
    Here Insert Picture Description
    • A producer, multiple consumers. Each customer has its own queue. Producers do not directly send messages to the queue, but is transmitted to the switch. Each queue to be bound to the switch. Message sent by the producer, the queue after the switch to achieve the object is acquired a plurality of message consumers
    • X (Exchanges) receives the message sent by the producer. We know how to process the message, for example, to submit to a particular queue, submitted to all queues, or to discard the message.
    • This mode does not require RouteKey
    • Demo Demonstration
//生产者
	private static final String DESTINATION_NAME = "rabbitMq_fanout";
	// 1. 建立mq连接
		Connection connection = MQConnectionUtils.newConnection();
		// 2.创建通道
		Channel channel = connection.createChannel();
		// 3.生产者绑定交换机 参数1:交换机名称 参数2:交换机类型
		channel.exchangeDeclare(DESTINATION_NAME, "fanout");
		// 4.创建消息
		String msg = "rabbitMq_fanout";
		System.out.println("生产者投递消息:" + msg);
		// 5.发送消息
		channel.basicPublish(DESTINATION_NAME, "",null , msg.getBytes());
		// 6.关闭通道 和连接
		channel.close();
		connection.close();
//消费者
 // 交换机名称
    private static final String DESTINATION_NAME = "rabbitMq_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1. 建立mq连接
        Connection connection = MQConnectionUtils.newConnection();
        // 2.创建通道
        Channel channel = connection.createChannel();
        System.out.println("短信消费者启动");
        FanoutConsumer.smsConsumer(channel);
        System.out.println("邮件消费启动");
        FanoutConsumer.emailConsumer(channel);
    }
    private static final String SMS_QUEUE = "Sms";
    public static void smsConsumer(Channel channel) throws IOException {
        // 3.消费声明队列
        channel.queueDeclare(SMS_QUEUE, false, false, false, null);
        // 4.消费者队列绑定交换机
        channel.queueBind(SMS_QUEUE, DESTINATION_NAME, "");
        // 5.消费监听消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("短信消费者获取生产消息:" + msg);
            }
        };
        channel.basicConsume(SMS_QUEUE, true, defaultConsumer);
    }
    private static final String EMAIL_QUEUE = "Email";
    public static void emailConsumer(Channel channel) throws IOException {
        // 3.消费声明队列
        channel.queueDeclare(EMAIL_QUEUE, false, false, false, null);
        // 4.消费者队列绑定交换机
        channel.queueBind(EMAIL_QUEUE, DESTINATION_NAME, "");
        // 5.消费监听消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("邮件消费者获取生产消息:" + msg);
            }
        };
        //自动应答
        channel.basicConsume(EMAIL_QUEUE, true, defaultConsumer);
    }
  • routing (routing mode)
    Here Insert Picture Description
    • Handles the routing key. A queue needs to be bound to the switch, and requires that a particular message routing keys exact match. This is a complete match. If a queue is bound to claim routing keys "dog" on the switch, only marked as "dog" messages are forwarded, does not forward dog.puppy, it does not deliver dog.guard, only forward dog.
    • Direct Exchange to send any message will be forwarded to RouteKey specified Queue .
    • Generally you can use rabbitMQ comes Exchange: "" (the name of the Exchange is an empty string, called the default Exchange below).
    • Exchange is not necessary to carry out this mode no binding (Binding) operation.
    • Requires a "RouteKey" message is transmitted, it can be simply understood as the name of the queue to be sent.
    • If the queue name RouteKey vhost specified does not exist, then the message will be discarded.
    • Demo Demonstration
//生产者
	// 交换机名称
	private static final String DESTINATION_NAME = "rabbitMq_direct";
		// 1. 建立mq连接
		Connection connection = MQConnectionUtils.newConnection();
		// 2.创建通道
		Channel channel = connection.createChannel();
		// 3.生产者绑定交换机 参数1 交换机名称 参数2 交换机类型
		channel.exchangeDeclare(DESTINATION_NAME, "direct");
		//这个是路由键的名称,方便测试
		String s1="sms";
		// 4.创建消息
		String msg = "rabbitMq_direct---:" +s1;
		System.out.println("生产者投递消息:" + msg);
		// 5.发送消息  routingKey:email
		channel.basicPublish(DESTINATION_NAME, s1, null, msg.getBytes());
		// 6.关闭通道 和连接
		channel.close();
		connection.close();
//消费者
   // 交换机名称
    private static final String DESTINATION_NAME = "rabbitMq_direct";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = MQConnectionUtils.newConnection();
        // 2.创建通道
        Channel channel = connection.createChannel();
        System.out.println("短信消费者启动");
        DirectConsumer.smsConsumer(channel);
        System.out.println("邮件消费者启动");
        DirectConsumer.emailConsumer(channel);
    }
    private static final String SMS_QUEUE = "Sms_msg";
    public static void smsConsumer( Channel channel) throws IOException {
        // 3.消费声明队列
        channel.queueDeclare(SMS_QUEUE, false, false, false, null);
        // 4.消费者队列绑定交换机 绑定路由键
        channel.queueBind(SMS_QUEUE, DESTINATION_NAME, "sms");
        // 5.消费监听消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("短信消费者获取生产消息--:" + msg);
            }
        };
        channel.basicConsume(SMS_QUEUE, true, defaultConsumer);
    }
    
    private static final String EMAIL_QUEUE = "Email_msg";
    public static void emailConsumer( Channel channel) throws IOException {
        // 3.消费声明队列
        channel.queueDeclare(EMAIL_QUEUE, false, false, false, null);
        // 4.消费者队列绑定交换机 绑定路由键,可以设置多个
        channel.queueBind(EMAIL_QUEUE, DESTINATION_NAME, "email");
        // 5.消费监听消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("邮件消费者获取生产消息-----:" + msg);
            }
        };
        channel.basicConsume(EMAIL_QUEUE, true, defaultConsumer);
    }

  • topic (theme)
    Here Insert Picture Description
    • Topic Exchange - the routing keys and a pattern matching. At this time, a queue needs to be bound to the model. "#" Symbol matches one or more words, the symbol "*" matches a word more, no less. So "audit. #" Can be matched to "audit.irs.corporate", but "audit. *" Only matches to "audit.irs"
    • Any messages sent to the Topic Exchange will be forwarded to all concerned RouteKey specified topics Queue
    • This model is more complex, in simple terms, is that each has its own interest in the topic queue, all messages are presented with a "Title" (RouteKey), Exchange will forward the message to all the interesting topic of energy fuzzy matching and RouteKey queue.
    • This model requires RouteKey, perhaps to bind the Exchange Queue advance.
    • During binding, the queue to provide a topic of concern, such as "# .log. #" Indicates that the queue care of all the messages involved in log (a RouteKey as "MQ.log.error" message will be forwarded to the queue).
    • "#" Represents 0 or several keywords, "*" indicates a keyword. As ". Log *" can match "log.warn", can not match the "log.warn.timeout"; but ". Log #" to match with both.
    • Similarly, if Exchange can not find a match with RouteKey Queue, the message will be discarded.
    • Demo Demonstration
// 交换机名称   生产者
	private static final String DESTINATION_NAME = "rabbitMq_topic";
		// 1. 建立mq连接
		Connection connection = MQConnectionUtils.newConnection();
		// 2.创建通道
		Channel channel = connection.createChannel();
		// 3.生产者绑定交换机 参数1 交换机名称 参数2 交换机类型
		channel.exchangeDeclare(DESTINATION_NAME, "topic");
		//routingKey
		String s1="log.sms.test.demo";
		// 4.创建消息
		String msg = "rabbitMq_msg_topic:"+s1 ;
		System.out.println("生产者投递消息:" + msg);
		// 5.发送消息  routingKey:email
		channel.basicPublish(DESTINATION_NAME, s1, null, msg.getBytes());
		// 6.关闭通道 和连接
		channel.close();
		connection.close();

 // 交换机名称
    private static final String DESTINATION_NAME = "rabbitMq_topic";
    public static void main(String[] args) throws Exception {
        // 1. 建立mq连接
        Connection connection = MQConnectionUtils.newConnection();
        // 2.创建通道
        Channel channel = connection.createChannel();
        System.out.println("短信消费者启动");
        TopicConsumer.smsConsumer(channel);
        System.out.println("邮件消费者启动");
        TopicConsumer.maileConsumer(channel);
    }
    private static final String SMS_QUEUE = "topic_sms";
    public static void smsConsumer(Channel channel) throws IOException {
        channel.queueDeclare(SMS_QUEUE, false, false, false, null);
        channel.queueBind(SMS_QUEUE, DESTINATION_NAME, "log.sms");
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("短信消费者获取生产消息----:" + msg);
            }
        };
        channel.basicConsume(SMS_QUEUE, true, defaultConsumer);
    }
    private static final String MAILE_QUEUE = "topic_email";
    public static void maileConsumer(Channel channel) throws IOException {
        // 3.消费声明队列
        channel.queueDeclare(MAILE_QUEUE, false, false, false, null);
        // *只要前缀相同都能收到
		//channel.queueBind(SMS_QUEUE, DESTINATION_NAME, "log.*");
        //可以匹配后面所有的词
        channel.queueBind(MAILE_QUEUE, DESTINATION_NAME, "log.#");
        // 5.消费监听消息
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("邮件消费者获取生产消息--------:" + msg);
            }
        };
        channel.basicConsume(MAILE_QUEUE, true, defaultConsumer);
    }


  • RPC
    Here Insert Picture Description
    this model have heard a little, I did not go about this mode. If you encounter will come back later to add.

Guess you like

Origin www.cnblogs.com/yangk1996/p/12663602.html