消息队列中间件学习笔记

中间件(Middleware)

根据维基百科的说法

  • 中间件(英语:Middleware)提供系统软件和应用软件之间连接的软件,以便于软件各部件之间的沟通,特别是应用软件对于系统软件的集中的逻辑,在现代信息技术应用框架如Web服务、面向服务的体系结构等中应用比较广泛。如数据库、Apache的Tomcat。

  • 中间件技术创建在对应用软件部分常用功能的抽象上,将常用且重要的过程调用、分布式组件、消息队列、事务、安全、连结器、商业流程、网络并发、HTTP服务器、Web Service等功能集于一身或者分别在不同品牌的不同产品中分别完成

  • 一般认为在商业中间件及信息化市场主要存在微软阵营、Java阵营、开源阵营。阵营的区分主要体现在对下层操作系统的选择以及对上层组件标准的制订


我此前对中间件的理解是对应用软件部分常用功能的抽象,它运行在操作系统之上,对外提供一种常用而抽象的服务,典型代表有数据库、缓存、消息队列

消息队列(Message queue)

我们同样引用维基百科

消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式.消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列互交。消息会保存在队列中,直到接收者取回它。

有了消息队列,事件可以异步地发生

实现

消息队列常常保存在链表结构中。拥有权限的进程可以向消息队列中写入或读取消息

优缺点

  • 很多情况下我们需要异步的通信协议。比如,一个进程通知另一个进程发生了一个事件,但不需要等待回应。但消息队列的异步特点,也造成了一个缺点,就是接收者必须轮询消息队列,才能收到最近的消息。

  • 和信号相比,消息队列能够传递更多的信息。与管道相比,消息队列提供了有格式的数据,这可以减少开发人员的工作量


ZeroMQ

是什么

所有网络交互所使用的API实际上是Berkeley套接字(BSD) 。这个源自1980年代早期的协议是TCP/IP协议的最原始实现。而且可以说,在当今各操作系统中,它是受到最广泛支持的API,也是这些操作系统的核心组件之一。人们对BSD套接字的了解较多的是点对点的连接。点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等。一旦你解决了以上所有问题,你就进入应用协议层(如HTTP)的世界了,这里需要的是组帧、缓存和处理逻辑等。换言之,编写高性能网络协议的应用程序一点儿也不复杂。 如果我们能对各种套接字类型、连接处理、帧、甚至路由的底层细节进行抽象,这不是件很好的事情吗?这正是ZeroMQ(ØMQ/ZMQ)网络库的由来:“它提供一些跨多种传输协议(如进程内通讯、IPC、TCP和广播)的套接字供你使用。你可使用多种方式实现N对N的套接字连接,譬如:扇出、发布订阅、任务分发以及请求响应。”

它更像是一个底层的网络通讯库,在Socket API之上做了一层封装,将网络通讯、进程通讯和线程通讯抽象为统一的API接口

这是个类似于Socket的一系列接口,他跟Socket的区别是:普通的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏蔽了这些细节,让你的网络编程更为简单。ZMQ用于node与node间的通信,node可以是主机或者是进程。

优势

  • TCP:ZeroMQ基于消息,消息模式,而非字节流。
  • RPC:ZeroMQ完全是异步的,你可以随时增加/删除参与者。
  • XMPP:ZeroMQ更简单、快速、更底层。Jabber可建在ØMQ之上。
  • AMQP:完成相同的工作,ZeroMQ要快100倍,而且不需要代理(规范更简洁——少278页)
  • IPC:ZeroMQ可以跨多个主机盒,而非单台机器。
  • CORBA:ZeroMQ不会将复杂到恐怖的消息格式强加于你。

三个基本模型

  • Request-Reply
  • Publisher-Subscriber
  • Parallel Pipeline

参考


RabbitMQ

RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种

ZeroMQ 和 RabbitMQ 都支持一个开源的消息协议:AMQP。AMQP的一个优点是它是一个灵活和开放的协议.不过ZeroMQ不支持消息持久化和崩溃恢复,RabbitMQ支持持久化。如果RabbitMQ死掉了,消息并不会丢失,当队列重启,一切都会回来

FAQ

  • 如何保证消息被某个消费者取得:当从队列当中取出一个消息的时候,RabbitMQ需要应用显式地回馈说已经获取到了该消息。如果一段时间内不回馈,RabbitMQ会将该消息重新分配给另外一个绑定在该队列上的消费者。另一种情况是消费者断开连接,但是获取到的消息没有回馈,则RabbitMQ同样重新分配
  • rabbitmq-server fails to start after hostname has changed for first time

RabbitMQ 中文文档摘记

  • 可以做什么
    • 消息系统允许软件、应用相互连接和扩展.这些应用可以相互链接起来组成一个更大的应用
    • 消息系统通过将消息的发送和接收分离来实现应用程序的异步和解偶
    • 或许你正在考虑进行数据投递,非阻塞操作或推送通知。或许你想要实现发布/订阅,异步处理,或者工作队列。所有这些都可以通过消息系统实现
    • RabbitMQ附带了一个易于使用的可视化管理工具
  • 安装
    • 默认用户访问:guest:guest
  • AMQP 0.9.1 模型解析
    • 消息代理(message brokers)从发布者(publishers)亦称生产者(producers)那儿接收消息,并根据既定的路由规则把接收到的消息发送给处理消息的消费者(consumers)。由于AMQP是一个网络协议,所以这个过程中的发布者,消费者,消息代理 可以存在于不同的设备上。
    • AMQP 0-9-1 模型简介:消息(message)被发布者(publisher)发送给交换机(exchange),交换机常常被比喻成邮局或者邮箱。然后交换机将收到的消息根据路由规则分发给绑定的队列(queue)。最后AMQP代理会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。
    • 当“消息确认”被启用的时候,消息代理不会完全将消息从队列中删除,直到它收到来自消费者的确认回执(acknowledgement)
    • 消费者
      • 将消息投递给应用 ("push API")
      • 应用根据需要主动获取消息 ("pull API")
    • AMQP连接通常是长连接
  • 应用教程(python版)
    • hello world:使用pika库
    • 列出所有队列:sudo rabbitmqctl list_queues
    • 发布、订阅:在我们的这个日志系统中,所有正在运行的接收方程序都会接受消息。我们用其中一个接收者(receiver)把日志写入硬盘中,另外一个接受者(receiver)把日志输出到屏幕上
      • 交换器和队列之间的联系我们称之为绑定(binding)
        • 列出所有绑定rabbitmqctl list_bindings
    • 远程过程调用:用celery吧

参考

选择

仔细分析应用程序的需求就能让更加清楚哪种交互机制才是解决问题的最佳之选

RabbitMQ in edx

configuration中的一些配置

详情参考rabbitmq/defaults/main.yml

EDXAPP_RABBIT_HOSTNAME: 'localhost'
rabbitmq_port: 5672
rabbitmq_management_port: 15672
rabbitmq_ip: "{{ ansible_default_ipv4.address }}"

XQUEUE_RABBITMQ_HOSTNAME: 'localhost'

在edx中RabbitMQ被当做服务使用,基本是透明的

一些有用命令

  • 查看帮助:sudo rabbitmqctl -h
  • 列出所有用户
    • admin[administrator]、celery [administrator]、edx [administrator]
  • 查看绑定:sudo rabbitmqctl list_bindings
  • 列出所有队列:sudo rabbitmqctl list_queues



Fork me on GitHub