1 引言

  • 什么是MQ

消息总线(Message Queue),是一种跨进程、异步的通信机制,用于上下游传递消息。由消息系统来确保消息的可靠传递。

  • 常用的MQ中间件有哪些

RabbitMQ:实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ:服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端

Kafka:一种高吞吐量的分布式发布订阅消息系统。

ActiveMQ、RocketMQ等

  • 安装

安装地址:https://www.rabbitmq.com/install-windows.html

先下载Erlang语言的安装环境,再下Rabbit的服务版本

2 RabbitMQ基础部分

  • 基本概念

Connect:是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。

Channel:是我们与RabbitMQ打交道的最重要的一个接口。如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销将是巨大的,大减少了操作系统建立TCP connection的开销。

VirtualHost:管理各自的exchange,和bindings

Exchange:类似于数据通信网络中的交换机,提供消息路由策略。rabbitmq中,producer不是通过信道直接将消息发送给queue,而是先发送给Exchange。一个Exchange可以和多个Queue进行绑定,producer在传递消息的时候,会传递一个ROUTING_KEY,Exchange会根据这个ROUTING_KEY按照特定的路由算法,将消息路由给指定的queue。

Queue:用于存储消息队列,并将它们转发给消费者

Producer:生产者

consumer:消费者

  • 工作模型

  • 使用场景

应用解耦、异步、流量削锋、日志收集等等...

3 RabbitMQ核心部分

  • 五大类型

helloWorld、work queues、publish/subscirbe(fanout)、routing(direct)、topic

  • 代码示例
/**********准备工作:安装包RabbitMQ.Client************/
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Exceptions;
//创建连接对象
var factory = new ConnectionFactory()
{
	UserName = "kkbm",
	Password = "kkbm1234",
	HostName = "172.18.10.189",
	Port = 5672,  //RabbitMQ默认的端口
};
using var conn = factory.CreateConnection();
var channel = conn.CreateModel();
//定义队列
channel.QueueDeclare("workqueue", true, false, false, null);

//发送消息
for (int i = 0; i < 10; i++)
{
	var message = "发送消息:" + i;
	var body = Encoding.UTF8.GetBytes(message);

	var properties = channel.CreateBasicProperties();
	properties.Persistent = true;

	channel.BasicPublish(exchange: "",
											 routingKey: "workqueue",
											 basicProperties: properties,
											 body: body);
	Thread.Sleep(i * 100);
}           
/**********准备工作:安装包RabbitMQ.Client************/
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Exceptions;
//创建连接对象工厂
var factory = new ConnectionFactory()
{
	UserName = "kkbm",
	Password = "kkbm1234",
	HostName = "172.18.10.189",
	Port = 5672,
};
var conn = factory.CreateConnection();
var channel = conn.CreateModel();
//绑定队列
channel.QueueDeclare(queue: "workqueue",
										 durable: true,
										 exclusive: false,
										 autoDelete: false,
										 arguments: null);

channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
var consumer = new EventingBasicConsumer(channel);
//接受消息
consumer.Received += (model, ea) =>
{
	var body = ea.Body;
	var message = Encoding.UTF8.GetString(body.ToArray());
	WriteColorLine($"{DateTime.Now.ToString()}工作队列接收到的消息:【{message}】",ConsoleColor.Blue);
	//消息确认
	channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: "workqueue",
										 autoAck: false,
										 consumer: consumer);

4 RabbitMQ进阶

  • 消息丢失

1)、消息发出后,中途网络故障,服务器没收到;

2)、消息发出后,服务器收到了,还没持久化,服务器宕机;

解决方案:确认消息是否发到RabbitMQ Server,如果生产者收到ACK不需要处理,收到Nack需要重新发送消息。

  • 消息重复

1)、消息消费成功,事务已提交,签收时结果服务器宕机或网络原因导致签收失败,消息状态会由unack转变为ready,重新发送给其他消费方;

2)、消息消费失败,由于retry重试机制,重新入队又将消息发送出去。

解决方案:消费者做好幂等性处理

  • 消息积压

1)、消费方的服务挂掉,导致一直无法消费消息;

2)、消费方的服务节点太少,导致消费能力不足,从而出现积压,这种情况极可能就是生产方的流量过大导致。

解决方案:增加消费者节点;持久化到数据库后处理

posted on 2022-10-20 14:58  叶子牛牛  阅读(158)  评论(0编辑  收藏  举报