分布式消息队列-RabbitMQ

RabbitMQ核心API

在这里插入图片描述

Exchange属性

  • name:Exchange名称
  • type:Exchange类型
    • direct
    • topic
    • fanout
    • headers
  • durability:是否持久化
  • auto delete:当最后一个绑定到Exchange上的Queue删除后,自动删除该Exchange
  • internal:当前Exchange是否用于RabbitMQ内部使用,默认为false
  • arguments:扩展参数,用于扩展AMOP协议自定化使用

Direct Exchange

所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue

在这里插入图片描述

Topic Exchange

  • 所有发送到Topic Exchange的消息被转发到所有关心的RouteKey中指定Topic的Queue上

  • Exchange将RouteKey和某Topic进行模糊匹配,此时Queue需要绑定一个Topic

  • 可以使用通配符进行模糊匹配

    "#":匹配一个或多个词
    "*":匹配一个词
    例如:
    	"log.#"匹配"log.info.oa"
    	"log.*"匹配"log.erro"
    

    在这里插入图片描述

Fanout Exchange

  • 不处理RouteKey,只需要简单的将Queue绑定到Exchange上
  • 发送到Exchange的消息都会被转发到与该Exchange绑定的Queue上
  • Fanout Exchange转发消息是最快的

在这里插入图片描述

Binding-绑定

  • Exchange和Exchange、Exchange和Queue之间的连接关系
  • Binding中可以包含RouteKey或者参数

Queue-消息队列

  • 消息队列,实际存储消息数据
  • Durability:是否持久化,Durable-是,Transient-否
  • Auto Delete:入选yes,但最后一个监听被移除后,该Queue会自动被删除

Message-消息

  • 服务器和应用程序之间传送的数据
  • 本质上就是一段数据,由Properties和Payload组成
  • 常用属性:delivery mode、headers(自定义属性)
  • 其他属性:content_type、content_encoding、priority,correlation_id、reply_to、expiration、message_id,timestamp、type、user_id、app_id、cluster_id

Virtual host-虚拟主机

  • 虚拟地址,用于进行逻辑隔离,最上层的消息路由
  • 一个Virtual host里可以有若干个Exchange和Queue
  • 同一个Virtual host里不能有相同名称的Exchange和Queue

RabbitMQ高级特性

生产端可靠性投递与消费端幂等性

如何保障消息100%投递成功

什么是生产端的可靠性投递?

  • 保障消息的成功发出
  • 保障MQ节点的成功接收
  • 发送端收到MQ节点(Broker)确认应答
  • 完善的消息补偿机制

生产端-可靠性投递

如何保障

  • 消息落库,对消息状态进行打标

  • 消息信息落库,对消息状态进行打标

    在这里插入图片描述

消费端-幂等性保障

海量订单业务高峰,如何避免消息重复消费

  • 消费端实现幂等性,消息不会消费多次,即使收到多条一样的消息

如何保障

  • 业务唯一ID或指纹码机制,利用数据库主键去重

Confirm-确认消息

  • 消息的确认,是指生产者投递消息后,如果Broker收到消息,则会给我们生产者一个应答

  • 生产者进行接收应答,用来确定这条消息是否正常的发送到Broker,这种方式也是消息的可靠性投递的核心保障
    在这里插入图片描述

如何实现

  1. 在channel上开启确认模式:channel.confirmSelect()
  2. 在channel上添加监听:addConfirmListener,监听成功和失败的返回结果,根据结果进行消息的重新发送或记录日志等处理

Return消息机制

Return Listener用于处理一些不可路由的消息

一般情况下,消息生产者通过指定一个Exchange和RouteKey,把消息送达某一队列中,让后消费者监听队列,进行消费处理;但在某些情况下,如果在发送消息的时候,当前的Exchange不存在或指定的RouteKey路由不到,这时候要监听这种不可达的消息,就要使用Return Listener

如何实现

  • Mandatory:如果为true,则监听器会接收到路由不可达的消息,然后处理,如果为false,则broker端自动删除该消息

    在这里插入图片描述

消费端特性-流控、ACK与重回队列

TTL消息、死信队列

RabbitMQ基础组件封装

  • 基础组件封装设计-迅速消息发送
  • 基础组件封装设计-确认消息发送
  • 基础组件封装设计-延迟消息发送

基础组件实现功能点

在这里插入图片描述

环境搭建

  1. 首先在Linux上进行一些软件的准备工作,yum下来一些基础的软件包
yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
配置好主机名称:/etc/hosts /etc/hostname
  1. 下载RabbitMQ所需软件包
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-1.1.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
  1. 安装服务命令
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm 
rpm -ivh socat-1.7.3.2-1.1.el7.x86_64.rpm
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
  1. 修改用户登录与连接心跳检测,注意修改
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
修改点1:loopback_users 中的 <<"guest">>,只保留guest (用于用户登录)
修改点2:heartbeat 为10(用于心跳连接)
  1. 安装管理插件

    5.1 首先启动服务(后面 | 包含了停止、查看状态以及重启的命令)

    /etc/init.d/rabbitmq-server start | stop | status | restart
    

    5.2 查看服务有没有启动: lsof -i:5672 (5672是Rabbit的默认端口)

    rabbitmq-plugins enable rabbitmq_management
    

    5.3 可查看管理端口有没有启动:

    lsof -i:15672 或者 netstat -tnlp | grep 15672
    
  2. 一切OK 我们访问地址,输入用户名密码均为 guest :

    http://你的ip地址:15672/
    

示例代码

示例代码(Hello World)

Sender.java

import java.util.HashMap;
import java.util.Map;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Sender {
    
    

	
	public static void main(String[] args) throws Exception {
    
    
		
		//	1 创建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.0.71");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//	2 创建Connection
		Connection connection = connectionFactory.newConnection();
		//	3 创建Channel
		Channel channel = connection.createChannel();  
		//	4 声明
		String queueName = "test001";  
        //	参数: queue名字,是否持久化,独占的queue(仅供此连接),不使用时是否自动删除, 其他参数
		channel.queueDeclare(queueName, false, false, false, null);
		
		Map<String, Object> headers = new HashMap<String, Object>();
		
		AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
		.deliveryMode(2)
		.contentEncoding("UTF-8")
		.headers(headers).build();
		
		
		for(int i = 0; i < 5;i++) {
    
    
			String msg = "Hello World RabbitMQ " + i;
			channel.basicPublish("", queueName , props , msg.getBytes()); 			
		}
	}
	
}

Receiver.java

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Receiver {
    
    

	public static void main(String[] args) throws Exception {
    
    
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.0.71");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
        
        String queueName = "test001";  
        //	durable 是否持久化消息
        channel.queueDeclare(queueName, false, false, false, null);  
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //	参数:队列名称、是否自动ACK、Consumer
        channel.basicConsume(queueName, true, consumer);  
        //	循环获取消息  
        while(true){
    
      
            //	获取消息,如果没有消息,这一步将会一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

猜你喜欢

转载自blog.csdn.net/tolmanlau/article/details/105864687