消息中间件 RabbitMQ 入门篇

五月君 K8S中文社区 今天
 

作者:五月君,来源:Nodejs技术栈

从不浪费时间的人,没有工夫抱怨时间不够。—— 杰弗逊

RabbitMQ 是一套开源(MPL)的消息队列服务软件,是由 LShift 提供的一个 Advanced Message Queuing Protocol (AMQP) 的开源实现,由以高性能、健壮以及可伸缩性出名的 Erlang 写成。

作者简介:五月君,Nodejs Developer,慕课网认证作者,热爱技术、喜欢分享的 90 后青年,欢迎关注 Nodejs技术栈 和 Github 开源项目 https://www.nodejs.red

通过本篇能学到什么?

  • 为什么要使用 RabbitMQ?

  • RabbitMQ 应用场景?

  • MQ 的空间与时间解耦是什么?

  • 常用的主流消息中间件都有哪些?

  • 如何安装、启动一个 RabbitMQ 服务?

  • 如何构建一个简单的生产者与消费者模型?

为什么要使用 RabbitMQ?

近两年谈的很多的一个概念微服务,在一个大型业务系统架构中,会被拆分成很多小的业务系统,这些业务系统之间如何建立通信呢?大家熟知的 HTTP、RPC 可以实现不同系统、不同语言之间的通信,除了这些往往还会使用消息队列(RabbitMQ、ActiveMQ、Kafafa 等)将这些系统链接起来,达到各系统间的解耦

另外,在后端使用 Node.js 哪怕开发一个稍微大点的系统,消息队列这些知识也是值得你去关注学习的。例如,生产端我可以使用 Node.js 生产一些数据放到队列中,另一段完全可以根据需要我使用 Python 或者其它语言去实现。

RabbitMQ 应用场景

1. 同步转异步

在项目中对于一些没必要同步处理的,可以借助 MQ 进行异步处理,例如,我们的短信发送就可以通过 MQ 队列来做。

2. 应用解耦

例如商城业务场景中,订单系统与库存系统,下单的同步可能也要去减少库存,将原本耦合在一块的逻辑可以通过消息队列进行,订单系统发布消息,库存系统订阅消息,这样的好处是一般库存系统出现问题也不会影响到订单系统。

3. 流量削峰

流量削峰在一些营销活动、秒杀活动场景中应用还是比较广泛的,如果短时间流量过大,可以通过设置阀值丢弃掉一部分消息或者根据服务的承受能力设置处理消息限制,也就是限流,之后也会单独进行讲解。

MQ 的空间与时间解耦

从空间上来看,消息的生产者无需提前知道消费者的存在,反之消费者亦是,两者之间得到了解耦,不会强依赖,从而实现空间上的解耦

从时间上来看,消息的生产者只负责生产数据将数据放入队列,之后无需关心消费者什么时间去消费,消费则可以根据自己的业务需要来选择实时消费还是延迟消费,两者都拥有了自己的生命周期,从而实现了时间上的解耦

主流消息中间件一览

  • ActiveMQ:Apache 出品,早起很流行主要应用于中小企业,面对大量并发场景会有阻塞、消息堆积问题。

  • Kafka:是由 Apache 软件基金会开发的一个开源流处理平台,由 Scala 和 Java 编写,是一种高吞吐量的分布式发布订阅消息系统,支持单机每秒百万并发。最开始目的主要用于大数据方向日志收集、传输。0.8 版本开始支持复制,不支持事物,因此对消息的重复、丢失、错误没有严格的要求。

  • RocketMQ:阿里开源的消息中间件,是一款低延迟、高可靠、可伸缩、易于使用的消息中间件,思路起源于 Kafka。最大的问题商业版收费,有些功能不开放。

  • RabbitMQ:是一个由 erlang(有着和原生 Socket 一样低的延迟)语言开发基于 AMQP 协议的开源消息队列系统。能保证消息的可靠性、稳定性、安全性。

安装指南

Mac版安装

直接通过 HomeBrew 安装,执行以下命令

  1. brew install rabbitmq

启动 rabbitmq

  1. # 进入安装目录

  2. $ /usr/local/Cellar/rabbitmq/3.7.8

  3. # 启动

  4. $ sbin/rabbitmq-server

浏览器输入 http://localhost:15672/#/ 默认用户名密码 guest

Linux系统安装

安装依赖

  1. apt-get install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz lsof

获取安装包

rabbitmq和erlang安装包一定要对应,具体可以查看对应关系,官网有说明RabbitMQ Erlang Version Requirements

  • 获取erlang安装包

  1. sudo wget http://www.rabbitmq.com/releases/erlang/erlang-18.3-1.el6.x86_64.rpm

  • 获取socat安装包

socat支持多协议,用于协议处理、端口转发,rabbitmq依赖于此。

  1. sudo wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm

  • 获取rabbitmq-server安装包 rabbitmq-server 安装包列表

  1. sudo wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm

开始安装

  • Centos rpm 一键安装

这里采用rpm一键安装,centos 执行命令 rpm-ivh erlang-18.3-1.el6.x86_64.rpm,在 ubuntu 中不支持此命令 rpm,使用 rpm 提示如下信息:

  1. rpm: RPM should not be used directly install RPM packages, useAlien instead!

  2. rpm: However assuming you know what you are doing...

  3. error: Failed dependencies:

  • ubuntu 系统 rpm 一键安装解决方案

  1. 安装 alien,执行命令 sudo apt-getinstall alien

  2. 转换 rpm 包为 .deb 格式,执行命令 sudo alienpackage.rpm 其中 package.rpm 为你的包名

  3. 通过dpkg安装, sudo dpkg-ipackage.deb

  • 以下顺序安装(以下是基于 CentOS 系统安装)

  1. rpm -ivh erlang-18.3-1.el6.x86_64.rpm

  2. rpm -ivh socat-1.7.3.2-5.el7.lux.x86_64.rpm

  3. 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">>]}, // 修改为 {loopback_users, [guest]},

运行与启动

  • 开启 rabbitmq

  1. rabbitmqctl start_app

  • 开启管理插件

  1. rabbitmq-plugins enable rabbitmq_management

  • 检查状态

  1. $ lsof -i:5672# 看到以下提示则开启成功

  2. COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

  3. beam 4678 rabbitmq 49uIPv62941580t0 TCP *:amqp (LISTEN)

  • 开启管理通知台 终端更多操作命令,以下有说明,浏览区输入 http://host:15672 打开管理控制台

  • 几个端口区别说明

    • 5672:通信默认端口号

    • 15672:管理控制台默认端口号

    • 25672:集群通信端口号

注意: 阿里云 ECS 服务器如果出现 RabbitMQ 安装成功,外网不能访问是因为安全组的问题没有开放端口 解决方案

操作命令

以下列举一些在终端常用的操作命令

  • whereis rabbitmq:查看 rabbitmq 安装位置

  • rabbitmqctl start_app:启动应用

  • whereis erlang:查看erlang安装位置

  • rabbitmqctl start_app:启动应用

  • rabbitmqctl stop_app:关闭应用

  • rabbitmqctl status:节点状态

  • rabbitmqctl add_user username password:添加用户

  • rabbitmqctl list_users:列出所有用户

  • rabbitmqctl delete_user username:删除用户

  • rabbitmqctl add_vhost vhostpath:创建虚拟主机

  • rabbitmqctl list_vhosts:列出所有虚拟主机

  • rabbitmqctl list_queues:查看所有队列

  • rabbitmqctl -p vhostpath purge_queue blue:清除队列里消息

构建一个简单的生产者与消费者模型

生产者-消费者模型是指一方生产数据一方消费数据。两者之间会有一个缓冲区做为中介,生产者把数据放入缓冲区,消费者从缓冲区取出数据。另外,生产者消费者模式也是是面向过程编程其中的一种设计模式。

构建生产者与消费者步骤

以下列举一下生产者与消费者模型在实现时的一些步骤,各语言在实现的过程中也都是大同小异的。

生产者步骤

  • 创建链接工厂

  • 通过链接工厂创建链接

  • 通过链接创建通道(channel)

  • 通过 channel 发送数据

  • 关闭链接

消费者步骤

  • 创建链接工厂

  • 通过链接工厂创建链接

  • 通过链接创建通道(channel)

  • 声明一个队列

  • 创建消费者

  • 设置 channel

Node.js 版本

amqplib 客户端

Github: https://github.com/squaremo/amqp.node

  1. $ npm install amqplib

构建生产者

生产者发消息的时候必须要指定一个 exchange,若不指定 exchange(为空)会默认指向 AMQPdefault 交换机, AMQPdefault 路由规则是根据 routingKey 和 mq 上有没有相同名字的队列进行匹配路由。

  1. const amqp = require('amqplib');

  2. async function producer() {

  3. // 1. 创建链接对象

  4. const connection = await amqp.connect('amqp://localhost:5672');

  5. // 2. 获取通道

  6. const channel = await connection.createChannel();

  7. // 3. 声明参数

  8. const routingKey = 'helloworldQueue';

  9. const msg = 'hello world';

  10. for(let i=0; i<5; i++) {

  11. // 4. 发送消息

  12. await channel.publish('', routingKey, Buffer.from(`${msg} 第${i}条消息`));

  13. }

  14. // 5. 关闭链接

  15. await channel.close();

  16. }

  17. producer();

构建消费者

  1. const amqp = require('amqplib');

  2. async function consumer() {

  3. // 1. 创建链接对象

  4. const connection = await amqp.connect('amqp://localhost:5672');

  5. // 2. 获取通道

  6. const channel = await connection.createChannel();

  7. // 3. 声明参数

  8. const queueName = 'helloworldQueue';

  9. // 4. 声明队列,交换机默认为 AMQP default

  10. await channel.assertQueue(queueName);

  11. // 5. 消费

  12. await channel.consume(queueName, msg => {

  13. console.log('Consumer:', msg.content.toString());

  14. channel.ack(msg);

  15. });

  16. }

  17. consumer();

Node.js 示例代码

  1. 源码地址如下:

  2. https://github.com/Q-Angelo/project-training/tree/master/rabbitmq/helloworld

Java 版本

添加 maven 依赖

SpringBoot 项目的 pom.xml 文件中引入 amqp-client 启动器

  1. <dependency>

  2. <groupId>com.rabbitmq</groupId>

  3. <artifactId>amqp-client</artifactId>

  4. <version>5.6.0</version>

  5. </dependency>

构建生产者

  1. package com.may.rabbitmq.helloworld;

  2. import com.rabbitmq.client.Channel;

  3. import com.rabbitmq.client.Connection;

  4. import com.rabbitmq.client.ConnectionFactory;

  5. publicclassProducer{

  6. publicstaticvoid main(String[] args) throwsException{

  7. // 1. 创建链接工厂

  8. ConnectionFactory connectionFactory = newConnectionFactory();

  9. connectionFactory.setHost("127.0.0.1");

  10. connectionFactory.setPort(5672);

  11. connectionFactory.setVirtualHost("/");

  12. // 2. 通过链接工厂创建链接

  13. Connection connection = connectionFactory.newConnection();

  14. // 3. 通过链接创建通道(channel)

  15. Channel channel = connection.createChannel();

  16. // 4. 通过 channel 发送数据

  17. // exchange:交换机,如果不传默认为 AMQP default

  18. channel.basicPublish("", "helloworldQueue", null, "hello world".getBytes());

  19. // 5. 关闭链接

  20. channel.close();

  21. connection.close();

  22. }

  23. }

构建消费者

  1. package com.may.rabbitmq.helloworld;

  2. import com.rabbitmq.client.*;

  3. import java.io.IOException;

  4. import java.util.concurrent.TimeUnit;

  5. publicclassConsumer{

  6. publicstaticvoid main(String[] args) throwsException{

  7. // 1. 创建链接工厂

  8. ConnectionFactory connectionFactory = newConnectionFactory();

  9. connectionFactory.setHost("127.0.0.1");

  10. connectionFactory.setPort(5672);

  11. connectionFactory.setVirtualHost("/");

  12. // 2. 通过链接工厂创建链接

  13. Connection connection = connectionFactory.newConnection();

  14. // 3. 通过链接创建通道(channel)

  15. Channel channel = connection.createChannel();

  16. // 4. 声明一个队列

  17. String queueName = "helloworldQueue";

  18. channel.queueDeclare(queueName, true, false, false, null);

  19. // 5. 创建消费者

  20. // springboot 从 1.5.9 升级到 2.0.0,QueueingConsumer 报错(Cannot resolve symbol 'QueueingConsumer')没有这个类,改为使用 DefaultConsumer

  21. DefaultConsumer consumer = newDefaultConsumer(channel) {

  22. @Override

  23. publicvoid handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throwsIOException{

  24. super.handleDelivery(consumerTag, envelope, properties, body);

  25. String message = newString(body, "UTF-8");

  26. System.out.printf("in consumer B (delivery tag is %d): %s\n", envelope.getDeliveryTag(), message);

  27. // System.out.printf("d%: s%\n", envelope.getDeliveryTag(), message);

  28. try{

  29. TimeUnit.MILLISECONDS.sleep(200);

  30. } catch(InterruptedException e) {

  31. }

  32. channel.basicAck(envelope.getDeliveryTag(), false);

  33. }

  34. };

  35. // 6. 设置 channel

  36. channel.basicConsume(queueName, false, consumer);

  37. System.out.println("消费端启动成功!");

  38. }

  39. }

运行测试

Java 示例代码

  1. 小项目大思想 — SpringBoot实战系列

  2. https://github.com/Q-Angelo/SpringBoot-Course

  3. 源码地址如下:

  4. https://github.com/Q-Angelo/SpringBoot-Course/tree/master/chapter8/chapter8-1

在上面的这个 生产者-消费者 例子中,也需你会感到疑惑生产者和消费者之间的消息是如何进行匹配传递的?在之后的一节 RabbitMQ 的交换机详解 中会介绍,它们是如何进行消息的匹配投递工作。

总结

通过本文学习,希望你能掌握什么场景下会应用到 MQ、可以自己尝试下安装一下 MQ 服务并构建一个简单的生产者-消费者模型。因为它很重要,通常也是互联网企业必备的基础组件之一,因此后续也打算写一个系列文章,包含不同交换机的消息投递机制、限流、延迟队列、重试、高可用设计等等敬请关注本公众号 “Nodejs技术栈” 获取最新消息

消息中间件 RabbitMQ 入门篇的更多相关文章

  1. javaweb消息中间件——rabbitmq入门

    概念:RabbitMQ是一款开源的消息中间件系统,由erlang开发,是AMQP的实现. 架构图大概如上. broker是消息队列的服务器,比如在linux上,我们安装的rabbitmq就是一个bro ...

  2. RabbitMq学习一入门篇(hello world)

    简介 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java,也是众多消息队列中表现不俗的一员,作用就是提高系统的并发 ...

  3. .NET 环境中使用RabbitMQ RabbitMQ与Redis队列对比 RabbitMQ入门与使用篇

    .NET 环境中使用RabbitMQ   在企业应用系统领域,会面对不同系统之间的通信.集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越发重要.其次,系统中一般会有很多对实时性要求不高的 ...

  4. 消息中间件——RabbitMQ(五)快速入门生产者与消费者,SpringBoot整合RabbitMQ!

    前言 本章我们来一次快速入门RabbitMQ--生产者与消费者.需要构建一个生产端与消费端的模型.什么意思呢?我们的生产者发送一条消息,投递到RabbitMQ集群也就是Broker. 我们的消费端进行 ...

  5. RabbitMQ入门与使用篇

    介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非常的优秀 ...

  6. 分布式系统消息中间件——RabbitMQ的使用基础篇

    分布式系统消息中间件——RabbitMQ的使用基础篇

  7. 分布式系统消息中间件——RabbitMQ的使用思考篇

    分布式系统消息中间件--RabbitMQ的使用思考篇 前言     前面的两篇文章分布式系统消息中间件--RabbitMQ的使用基础篇与分布式系统消息中间件--RabbitMQ的使用进阶篇,我们简单介 ...

  8. 分布式系统消息中间件——RabbitMQ的使用进阶篇

    分布式系统消息中间件--RabbitMQ的使用进阶篇 前言     上一篇文章 (https://www.cnblogs.com/hunternet/p/9668851.html) 简单总结了分布式系 ...

  9. RabbitMQ入门看这一篇就够了

    一文搞懂 RabbitMQ 的重要概念以及安装 一 RabbitMQ 介绍 这部分参考了 <RabbitMQ实战指南>这本书的第 1 章和第 2 章. 1.1 RabbitMQ 简介 Ra ...

随机推荐

  1. 宝塔面板1G内存安装mysql5.7提示“至少需要XX兆内存”的解决办法

    打开文件:/www/server/panel/class/panelPlugin.py 搜索关键词:“至少” (可能在134行) 然后把这行if语句注释掉,如下图:

  2. delay timer的wrap around

    span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...

  3. js事件3-事件对象

    对于每次点击一个事件,都会产生一个事件对象,这个事件对象中包含了这个事件的很多信息 我们来看看事件对象具体有哪些信息 Object.onclick=function(e){ ..... }其中的参数e ...

  4. [图解]Windows下使用Zend Studio 10和XAMPP 1.8搭建开发环境,ZendFramework 2 HelloWorld

    1.下载并安装 ZendStudio,搜一个破解版 XAMPP,官网下载:https://www.apachefriends.org/index.html 2.打开ZendStudio新建一个php项 ...

  5. python+ddt+unittest+excel+request实现接口自动化

    接口自动化测试流程:需求分析-用例设计--脚本开发--测试执行--结果分析1.获取接口文档,根据文档获取请求方式,传输协议,请求参数,响应参数,判断测试是否通过设计用例2.脚本开发:使用request ...

  6. git 学习笔记 —— 获取远端分支并修改后提交至远端仓库

    笔者最近进行开发过程中,所有参与者的代码需要通过 git 上传到远端仓库中,不同的模块对应不同的 git 分支,不同模块的数据需要从远端仓库中获取.这里记录下笔者从远端仓库中获取分支数据,进行修改,最 ...

  7. 没有内置小鹤双拼的rime输入法就是差劲

    没有内置小鹤双拼的rime输入法就是差劲,还特立独行,搞什么繁体~ 没有内置小鹤双拼的rime输入法就是差劲,还特立独行,搞什么繁体~ 没有内置小鹤双拼的rime输入法就是差劲,还特立独行,搞什么繁体 ...

  8. The difference between Virtual DOM and DOM

    dom是结构化的文本信息的抽象,是结构化的文本信息在内存中的表示 是操作结构化文本信息的api. Follow: Follow React attacks us with the virtual DO ...

  9. 一个项目设置两个git地址,并最终实现一次性同时推送到到两个git地址上的方法总结

    基于多处备份的想法,确保自己的代码不丢失.或者是代码的git本身搭建在自己公司的服务上,而你为了保险起见,想把项目同时放在码云或者github上面. 这样,你就需要让一个项目同时备份在两个云端,这样即 ...

  10. python函数 | 匿名函数lambda

    匿名函数:lambda 表达式.普通函数有且只有返回值的函数才能用匿名函数进行简化成一行函数. 匿名函数不单独使用,一般和内置函数结合使用.内置函数中,可加入函数的有min.max.sorted.ma ...