消息中间件 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. Odoo字段类型详解

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826099.html   一:基本字段类型 Binary:二进制类型,用于保存图片.视频.文件.附件等,在 ...

  2. Httpd服务入门知识-Httpd服务常见配置案例之修改监听的IP和Port

    Httpd服务入门知识-Httpd服务常见配置案例之修改监听的IP和Port 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看默认配置 [root@node101.yinzh ...

  3. JAVA构造器,重载与重写

    1. java构造器 构造器也叫构造方法(constructor), 用于对象初始化. 构造器是一个创建对象时被自动创建的特殊方法,目的是对象的初始化. 构造器 的名称与类的名称一致. JAVA通过n ...

  4. C#常用的图片处理方法-图片剪切、图片压缩、多图合并代码

    /// <summary> /// 图片转成圆角方法二 /// </summary> private Bitmap WayTwo(Bitmap bitmap) { //usin ...

  5. js动画--封装透明度

    这一章我将讲述一些如何将透明度的变化也封装到调用函数中,对于前面几节课的介绍,已经将基本的属性封装到函数中了,宽,长等属性.关于透明度的变化还是有一点区别的,这一章我将封装透明度 先创建一个div & ...

  6. 后端将Long类型数据传输到前端出现精度丢失的问题

    当将超过16位的数字传输到前端的时候,就会出现精度丢失的问题,然后我按照网上的几种方法实验的时候,只有一种方法成功了.可能是因为环境等方面的问题. 我这里成功是因为:最后使用的是配置mvc的方式,然后 ...

  7. eclipse解决中文字体太小问题(转载)

    最近新装了Win7,打开eclipse3.7中文字体很小,简直难以辨认.在网上搜索发现这是由于Eclipse 3.7 用的字体是 Consolas,显示中文的时候默认太小了.   解决方式有两种:一. ...

  8. live555 基本框架

    (转) 从程序的结构来看,live项目包括了四个基本库.程序入口类(在mediaServer中)和一些测试代码(在testProgs中).四个基本库是UsageEnvironment,BasicUsa ...

  9. CSS Cross-Browser Inline-Block

    低版本的IE,火狐 不支持  Inline-Block 属性,想要达到目的我们需要多做一些额外的工作 , 参考页面为:https://blog.mozilla.org/webdev/2009/02/2 ...

  10. 20180523模拟赛T2——前缀!

    简化版题面 jyt毒瘤,写了超长的题面,要看完整题面的翻到最后-- 定义\(f_0(x) = A_x\),\(f_n(x) = \sum^x_{i = 1} f_{n-1}(i)\).给出长度为\(N ...