rabbitmq - (消息队列) 的基本原理介绍
介绍
MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,它是消费-生产者模型的一个典型的代表,producer往消息队列中不断写入消息,而另一端consumer则可以读取或者订阅队列中的消息。RabbitMQ是MQ产品的典型代表,是一款基于AMQP协议可复用的企业消息系统
系统架构
Rabbitmq系统最核心的组件是Exchange和Queue,Exchange和Queue是在rabbitmq server(又叫做broker)端,producer和consumer在应用端。
原理大致图(MQ:Message Queue):
Queue
消息队列,提供了FIFO的处理机制,具有缓存消息的能力。rabbitmq中,队列消息可以设置为持久化,临时或者自动删除。
- 设置为持久化的队列,queue中的消息会在server本地硬盘存储一份,防止系统crash,数据丢失
- 设置为临时队列,queue中的数据在系统重启之后就会丢失
- 设置为自动删除的队列,当不存在用户连接到server,队列中的数据会被自动删除
Exchange
Exchange类似于数据通信网络中的交换机,提供消息路由策略。rabbitmq中,producer不是通过信道直接将消息发送给queue,而是先发送给Exchange。一个Exchange可以和多个Queue进行绑定,producer在传递消息的时候,会传递一个ROUTING_KEY,Exchange会根据这个ROUTING_KEY按照特定的路由算法,将消息路由给指定的queue。和Queue一样,Exchange也可设置为持久化,临时或者自动删除。
Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别:
- Direct直接交换器,工作方式类似于单播,Exchange会将消息发送完全匹配ROUTING_KEY的Queue
- fanout广播是式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue
- topic主题交换器,工作方式类似于组播,Exchange会将消息转发和ROUTING_KEY匹配模式相同的所有队列,比如,ROUTING_KEY为user.stock的Message会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列。( * 表是匹配一个任意词组,#表示匹配0个或多个词组)
- headers消息体的header匹配(ignore)
Binding
所谓绑定就是将一个特定的 Exchange 和一个特定的 Queue 绑定起来。Exchange 和Queue的绑定可以是多对多的关系
通信过程
假设P1和C1注册了相同的Broker,Exchange和Queue。P1发送的消息最终会被C1消费。基本的通信流程大概如下所示:
- P1生产消息,发送给服务器端的Exchange
- Exchange收到消息,根据ROUTINKEY,将消息转发给匹配的Queue1
- Queue1收到消息,将消息发送给订阅者C1
- C1收到消息,发送ACK给队列确认收到消息
- Queue1收到ACK,删除队列中缓存的此条消息
Consumer收到消息时需要显式的向rabbit broker发送basic.ack消息或者consumer订阅消息时设置auto_ack参数为true。在通信过程中,队列对ACK的处理有以下几种情况:
- 如果consumer接收了消息,发送ack,rabbitmq会删除队列中这个消息,发送另一条消息给consumer。
- 如果cosumer接受了消息, 但在发送ack之前断开连接,rabbitmq会认为这条消息没有被deliver,在consumer在次连接的时候,这条消息会被redeliver。
- 如果consumer接受了消息,但是程序中有bug,忘记了ack,rabbitmq不会重复发送消息。
- rabbitmq2.0.0和之后的版本支持consumer reject某条(类)消息,可以通过设置requeue参数中的reject为true达到目地,那么rabbitmq将会把消息发送给下一个注册的consumer。
php 生产者、消费者示例
先用 composer 加载 mq 拓展文件
{
"require": {
"php-amqplib/php-amqplib": "2.7.*" //增加这行
}
}
class RabbitMq extends Command
{
protected $config = [
'host' => '192.168.1.18',
'port' => '5672',
'user' => 'admin',
'pwd' => '123456',
'vhost'=> '/',
]; protected $exchangeName = 'kd_sms_send_ex'; //交换机名
protected $queueName = 'kd_sms_send_q'; //队列名称
protected $routingKey = 'sms_send'; //路由关键字(也可以省略) protected function configure()
{
$this->setName('mq')
->addOption('type', null, Option::VALUE_REQUIRED, 'date yyyymmdd', 'con') // pro
->setDescription('Mq test');
} protected function execute(Input $input, Output $output)
{
$type = $input->getOption('type'); if ($type=='con') {
// 消费
$this->consumption();
}elseif ($type=='pro'){
// 生产
$this->production();
} echo 'mq test end' .PHP_EOL;
} // 消费
protected function consumption()
{
//连接RabbitMQ
$conn = new AMQPStreamConnection(
$this->config['host'],
$this->config['port'],
$this->config['user'],
$this->config['pwd']
);
// 开启一个通道
$channel = $conn->channel(); // 对于正在繁忙的客户端,没得到回应之前,不向其发送新消息
$channel->basic_qos(null,1,null); // 声明一个队列 第三个参数为声明队列持久性
$channel->queue_declare($this->queueName, false, true, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
$callback = function ($msg){
echo date('Y-m-d H:i:s') . ' body is '. $msg->body ."\n";
};
// 开始队列消费 第四个参数表示通知服务端消费情况
$channel->basic_consume($this->queueName, '', false, true, false, false, $callback); while (count($channel->callbacks)) {
$channel->wait();
} // 关闭通道
$channel->close();
// 关闭连接
$conn->close();
} // 生产
protected function production()
{
//建立生产者与mq之间的连接
$conn = new AMQPStreamConnection(
$this->config['host'],
$this->config['port'],
$this->config['user'],
$this->config['pwd']
);
//在已连接基础上建立生产者与mq之间的通道
$channel = $conn->channel(); //声明初始化交换机
$channel->exchange_declare($this->exchangeName, 'direct', false, true, false);
//声明初始化一条队列 第三个参数为声明队列持久性
$channel->queue_declare($this->queueName, false, true, false, false);
//将队列与某个交换机进行绑定,并使用路由关键字
$channel->queue_bind($this->queueName, $this->exchangeName, $this->routingKey); //生成消息
$msgBody = serialize(["name" => "dxx", "age" => 18]);
$param = [
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, // 消息设为持久化
];
$msg = new AMQPMessage($msgBody, $param);
//推送消息到某个交换机
$channel->basic_publish($msg, $this->exchangeName, $this->routingKey); // 关闭通道
$channel->close();
// 关闭连接
$conn->close();
} }
rabbitmq - (消息队列) 的基本原理介绍的更多相关文章
- RabbitMQ消息队列+安装+工具介绍
1.MQ为Message Queue,消息队列是应用程序和应用程序之间的通信方法 2. 多种开发语言支持,其实就是一个驱动,如连接数据库的mysql驱动,oracle驱动等. 3. 4.采用以下语言开 ...
- C# .net 使用rabbitmq消息队列——EasyNetQ插件介绍
EasyNetQ 是一个简洁而适用的RabbitMQ .NET类库,本质上是一个在RabbitMQ.Client之上提供服务的组件集合.
- RabbitMQ消息队列(一): Detailed Introduction 详细介绍
http://blog.csdn.net/anzhsoft/article/details/19563091 RabbitMQ消息队列(一): Detailed Introduction 详细介绍 ...
- RabbitMQ消息队列1: Detailed Introduction 详细介绍
1. 历史 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有 ...
- (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- RabbitMQ消息队列应用
RabbitMQ消息队列应用 消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是 ...
- RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- 使用EasyNetQ组件操作RabbitMQ消息队列服务
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现,是实现消息队列应用的一个中间件,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合, ...
- RabbitMQ消息队列系列教程(二)Windows下安装和部署RabbitMQ
摘要 本篇经验将和大家介绍Windows下安装和部署RabbitMQ消息队列服务器,希望对大家的工作和学习有所帮助! 目录 一.Erlang语言环境的搭建 二.RabbitMQ服务环境的搭建 三.Ra ...
随机推荐
- [翻译] ASP.NET Core 2.2 正式版发布
本文为翻译,原文地址:https://blogs.msdn.microsoft.com/webdev/2018/12/04/asp-net-core-2-2-available-today/ 我(文章 ...
- 程序员如何避免996、icu?欢迎来讨论一下。
最近996icu火了,我以前就被996害了.现在还没缓过来,可能是自己体质比较弱吧. 以前的事就不说了,说说现在的想法吧.那么程序员如何才能避免996icu呢? 有两个基本因素: 1. 实现一个功能, ...
- C语言函数的格式
#include <stdio.h>#include <stdlib.h>extern int addf(int a,int b);//函数能多次声明//int addf(in ...
- MySQL在windows上多次安装失败
Mysql首次安装: 1.官网下载mysql安装包 2.安装选择自定义,custom 3.更换路径,然后按需求选择,选择标准就行 Mysql重复安装需要注意的问题: 1.程序和功能下,需要卸载MySQ ...
- 简单数论之整除&质因数分解&唯一分解定理
[整除] 若a被b整除,即a是b的倍数,那么记作b|a("|"是整除符号),读作"b整除a"或"a能被b整除".b叫做a的约数(或因数),a ...
- H(X|Y)的推到过程
- SpringMVC model 多余字段 忽略
spring-mybaits的model中如何通过注解忽略非数据库字段?——CSDN问答频道https://ask.csdn.net/questions/643534 ObjectMapper忽略多余 ...
- 一入OI深似海 2 —— 初中三年,颓废PJ
初中,OI似乎没有真正进入我的生活. 三年PJ在我的生活中占比很少. 每天都是平淡无奇的文化课,晚上在写完作业之后还能休息一会儿. 每周六下午的OI课很短暂, 大部分时间我还是把我的重心放在学习上. ...
- Kafka如何保证消息的顺序性
1. 问题 比如说我们建了一个 topic,有三个 partition.生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到 ...
- vue cli使用融云实现聊天
公司有个项目要实现一个聊天功能,需求如下图,略显随意 公司最终选择融云这个吊炸天的即时通信,文档详细的一匹,刚开始看文档感觉很详细实现起来也不麻烦,有很多开源的demo可以在线演示和下载 不过我们的项 ...