RabbitMQ实战:可用性分析和实现

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记。

上一篇介绍了各种场景下的最佳实践,大部分场景可以使用「发后即忘」的模式,不需要响应,如果需要响应,可以使用RabbitMQ的RPC模型。

RabbitMQ以异步的方式解耦系统间的关系,调用者将业务请求发送到Rabbit服务器,就可以返回了,Rabbit会确保请求被正确处理,即使遇到网络异常、Rabbit服务器崩溃、整个机房断电等特殊场景,针对这些场景,Rabbit提供了各种机制确保其可用性。

本篇通过总结可能出现的特殊场景,对Rabbit提供的可用性保证进行分析,学习它的实现方式,你会了解到:

  • 总结异常场景
  • 集群并处理失败
  • 连接丢失和故障转移
  • 主/备方式
  • 跨机房复制

异常场景

在实际工作中,有很大一部分时间用在解决各种异常情况,比如针对用户输入的验证,JDK中提供的各种异常类,网络异常等,这些相对来说比较好解决。

Rabbit服务作为调用者和处理者的桥梁,至关重要,如果因为网络异常、单台服务器崩溃、机房瘫痪等原因导致Rabbit服务不可用,会影响所有依赖的业务系统。

网络异常

处理者和服务端是通过长连接交互的,这样可以将消息实时推送,网络异常可能会导致长连接断开,如果客户端无法感知,处理者将接收不到任何消息,这种情况称为「连接丢失」。

通过捕获连接异常,进行重连,可以解决这种问题,另外,Rabbit客户端进行了封装,很容易处理这种问题。

服务器崩溃

如果只有一台服务器服务,服务器崩溃将导致服务不可用,一般会使用集群将多个服务器看成一个整体对外提供服务,这样,单台服务器崩溃不会影响整体的服务。

使用集群后,就要考虑一些问题:

  • 客户端连接到哪台服务器是随机的,而一个队列只会在某个服务器中,所以,每台服务器都要保存队列元数据(类似索引),并且可从其他服务器获取实际的队列数据;
  • 服务器崩溃,会导致非持久化的队列、交换器丢失,客户端端重连后,要再次进行创建,但未消费的消息将无法恢复;
  • 如果队列、交换器、消息等是持久化的,如何进行恢复呢,Rabbit提供了几种方式进行处理,后面会详细介绍;
  • 订阅者也需要重新建立连接,进行监听;
机房瘫痪

如果考虑机房瘫痪,就要建多个数据中心,RabbitMQ提供了一种机制,可以方便地在不同数据中心的Rabbit间复制消息。

集群并处理失败

RabbitMQ最优秀的功能之一就是其内建集群,主要用于完成2个目标:

  • 允许消费者和生产者在Rabbit节点崩溃的情况下继续运行;
  • 通过添加更多的节点线性扩展消息通信的吞吐量;
集群架构

RabbitMQ会始终记录四种类型的内部元数据(类似索引):

  • 队列元数据:队列名称和它的属性;
  • 交换器元数据:交换器名称、类型和属性;
  • 绑定元数据:一张简单的表格展示了如何将消息路由到队列;
  • vhost元数据:为vhost内的队列、交换器和绑定提供命名空间和安全属性;

当引入集群时,就需要追踪新的元数据类型:集群节点位置,以及节点与已记录的其他类型元数据的关系。

不是每个节点都有所有队列的完全拷贝,如果在集群中创建队列,只会在单个节点上创建完整的队列信息(元数据、状态、内容),所有其他节点只知道队列的元数据和指向该队列的节点指针。

如果节点崩溃了,附加在队列上的消费者也就无法接收新的消息了。可以让消费者重连到集群并重新创建队列,这种做法仅当队列没设置持久化时才可行,这是为了确保当失败的节点恢复后加入集群,节点上的队列消息不会丢失。

为什么不将队列内容和状态复制到所有节点:第一,存储空间,如果每个集群节点都拥有所有队列的完全拷贝,添加新节点不会带来更多存储空间;第二,性能,消息的发布者需要将消息复制到每一个集群节点,对于持久化消息,网络和磁盘复制都会增加。

而交换器只是一张查询表,而非实际的消息路由器,因此将交换器在整个集群中进行复制会更加简单

可以把每个队列想象成节点上运行的进程,每个进程拥有自己的进程ID,交换器只是路由模式列表和匹配消息应发往的队列进程ID列表。

每个Rabbit节点,要么是内存节点,要么是磁盘节点,单节点系统只运行磁盘类型的节点,在集群中,可以选择配置部分节点为内存节点。

在集群中声明队列、交换器或绑定的时候,这些操作直到所有集群节点都成功提交元数据变更后才返回。

RabbitMQ只要求集群中至少有一个磁盘节点,如果只有一个磁盘节点,刚好又崩溃了,集群可以继续路由消息,但不能创建队列、交换器、绑定、添加用户、更改权限等操作。所以,建议设置两个磁盘节点,当内存节点重启后,会连接到预先配置的磁盘节点,下载当前集群元数据拷贝,所以要将所有磁盘节点告诉内存节点。

镜像队列

前面提到,队列只会在集群中的一个节点,节点崩溃后,队列消息就会丢失,RabbitMQ2.6版本之后,提供了镜像队列,一旦主队列不可用,从队列将被选举为新的主队列。

对于镜像队列,除了将消息按照路由绑定规则投递到合适的队列,也会将消息投递到镜像队列的从拷贝。

对于发送方确认消息,Rabbit会在所有队列和队列的从拷贝安全地接收到消息时,才会通知发送方。

另外,使用镜像队列时,有一个问题:如果主拷贝节点发送故障,从队列会选举Wie主队列,所有该队列的消费者需要重新附加并监听新的队列主拷贝。对于通过故障节点进行连接的消费者,可以通过丢失到节点的TCP连接检测到,但对于那些通过节点附加到镜像队列且正常运行的消费者将无法检测到。

Rabbit通过给消费者发送一个消费者取消通知,告知不再附加在队列主拷贝了,需要重新连接。

连接丢失和故障转移

这一小节主要讨论消费者如何检测连接丢失,并进行重连操作。

处理到集群的重连有多重策略,比较好的一种方式是使用负载均衡,不仅可以减少应用程序处理节点故障代码的复杂性,又能确保在集群中连接的平均分配。

关于负载均衡,网上介绍的比较多了,这里就不再过多介绍了,主要看看如何感知故障,并进行重连操作。

感知故障比较简单,当长连接断开时,会抛出异常,捕获对应的异常即可。

当集群节点出现故障时,应用程序需要考虑:下一个该连向哪里?这个工作已经交由负载均衡器决定。

关于重连处理,要考虑:

  • 如果重连到新的服务器,信道以及其上的所有消费循环都会失效,需要对他们进行重建;
  • 当进行重连时,所有的队列、绑定有可能都不存在了,需要重新构造队列和绑定。

主/备方式

当对可用性要求特别高时,不允许消息丢失,需要将队列、交换器、消息设置成持久化,如果一个节点崩溃了,在恢复之前,将无法转发消息,因为默认的群集架构不允许在集群其他节点创建队列,防止故障节点恢复后,历史消息丢失。

可以通过构建主/备机的独立RabbitMQ,也就是warren模式,解决这个问题。一个warren是指一对主/备独立服务器,并前置一套负载均衡器来处理故障转移。

主服务器和备用服务器之间没有协作,只有当主服务器崩溃时,备用服务器才会处理消息。可以保证,主节点故障后,通过备用节点重新创建队列、交换器继续服务,故障节点恢复后,可以继续消费主节点未消费的消息。

跨机房复制

在只有一个数据中心的时候,RabbitMQ集群对于提升消息通信性能来说是很棒的方案,但需要把消息从一个程序路由到另一个城市的时候,就比较麻烦了,可以通过Shovel解决。

Shovel是RabbitMQ的一个插件,可以使你能够定义RabbitMQ上的队列和另一个RabbitMQ上的交换器之间的复制关系。说白了就是生产者和消费者离得比较远。

通过在机房1创建一个新的队列,用于接收网站发布的消息,然后让shovel消费这些消息并重新将消息通过WAN连接发布到机房2上的交换器。

这样对于用户来说,只要发布到机房1的队列即可返回,减少了响应时间。机房1可以持续将消息发布到机房2上。

通过上面的介绍可以看到,保证高可用需要做很多工作,可以根据业务对可用性的要求,选择不同的架构方式。

下一篇重点介绍RabbitMQ管理界面和监控。

欢迎扫描下方二维码,关注我的个人微信公众号 ~

原文地址:http://blog.51cto.com/13714880/2116094

时间: 2024-11-06 16:55:50

RabbitMQ实战:可用性分析和实现的相关文章

RabbitMQ实战:界面管理和监控

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记. 上一篇总结了可能出现的异常场景,并对RabbitMQ提供的可用性保证进行了分析,在出现服务器宕机后,仍然可以正常服务.另外,需要尽快恢复异常的服务器,重新加入集群,推送未消费的消息,通过监控可第一时间接收到错误并进行处理. 另外,我们想主动了解消息堆积和消费的情况,以及服务器节点的压力,RabbitMQ提供了几种方式便捷.直观的了解,包括Web管理插件.REST API.rabbitmqadmin脚本. 通过介绍,你会了解

RabbitMQ实战:理解消息通信

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记. 前段时间总结完了「深入浅出MyBatis」系列,对MyBatis有了更全面和深入的了解,在掘金社区也收到了一些博友的喜欢,很高兴.另外,短暂的陪产假就要结束了,小宝也二周了,下周二就要投入工作了,希望自己尽快调整过来,加油努力. 从本篇开始总结「RabbitMQ实战」系列的阅读笔记,RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,可以将作业排队以便让分布式服务进行处理. 本篇

RabbitMQ消息可靠性分析

消息中间件的可靠性是指对消息不丢失的保障程度:而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量.不存在绝对的可靠性只能尽量趋向完美.并且通常可靠性也意味着影响性能和付出更大的成本,因此实际应用时还要根据业务需求,对真正关键的信息来做可靠性保证,并要从生产者.消息队列.消费者三个维度来努力. 1.生产者发送信息的可靠性  生产者客户端发送出去之后可以发生网络丢包.网络故障等造成消息丢失.一般情况下如果不采取措施,生产者无法感知消息是否已经正确无误的发送到交换器中.如果消息在传

rabbitMQ实战(一)---------使用pika库实现hello world

rabbitMQ实战(一)---------使用pika库实现hello world 2016-05-18 23:29 本站整理 浏览(267) pika是RabbitMQ团队编写的官方Python AMQP库.需要先安装pika:pip3 install pika有较详细的注释,就不再详细说明了生产者代码:hello_world_producer.py: import pika,sys #connect to the rabbitmq,use the default vhost credent

揪出“凶手”——实战WinDbg分析电脑蓝屏原因

http://www.appinn.com/blue-screen-search-code/ 蓝屏代码查询器 – 找出蓝屏的元凶 11 文章标签: windows / 系统 / 蓝屏. 蓝屏代码查询器可以帮你查出引起蓝屏的故障原因并可以到微软知识库中查询解决方案,和之前的 BlueScreenView 配合是很好的蓝屏故障排除组合.@Appinn 使用时只需填入错误代码的简写即可,另外在支持中心中有关于蓝屏原因分析的文章链接,有兴趣的童鞋可以去看看..  官方网站 | 来自小众软件 http:/

Openstack中RabbitMQ RPC代码分析

在Openstack中,RPC调用是通过RabbitMQ进行的. 任何一个RPC调用,都有Client/Server两部分,分别在rpcapi.py和manager.py中实现. 这里以nova-scheduler调用nova-compute为例子. nova/compute/rpcapi.py中有ComputeAPI nova/compute/manager.py中有ComputeManager 两个类有名字相同的方法,nova-scheduler调用ComputeAPI中的方法,通过底层的R

RabbitMQ实战:消息通信模式和最佳实践

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记. 通过前2篇的介绍,了解了消息通信的主要元素和交互过程,以及如何运行和管理RabbitMQ,这篇将站在开发模式的角度理解「面向消息通信」带来的好处,以及在各种场景下的最佳实践. 通过介绍,你会了解到: 面向消息通信的好处 发后即忘模型 用RabbitMQ实现RPC 面向消息通信的好处 主要从异步状态思维.处理能力扩展性.集成复杂度方面,说明面向消息通信的好处. 异步状态思维 当将消息通信集成到应用程序时,开发模式将从同步模型

Java SpringBoot集成RabbitMq实战和总结

目录 交换器.队列.绑定的声明 关于消息序列化 同一个队列多消费类型 注解将消息和消息头注入消费者方法 关于消费者确认 关于发送者确认模式 消费消息.死信队列和RetryTemplate RPC模式的消息(不常用) 关于消费模型 关于RabbitMq客户端的线程模型 在公司里一直在用RabbitMQ,由于api已经封装的很简单,关于RabbitMQ本身还有封装的实现没有了解,最近在看RabbitMQ实战这本书,结合网上的一些例子和spring文档,实现了RabbitMQ和spring的集成,对着

RabbitMQ实战应用技巧

1. RabbitMQ实战应用技巧 1.1. 前言 由于项目原因,之后会和RabbitMQ比较多的打交道,所以让我们来好好整理下RabbitMQ的应用实战技巧,尽量避免日后的采坑 1.2. 概述 RabbitMQ有几个重要的概念:虚拟主机,交换机,队列和绑定 虚拟主机:一个虚拟主机持有一组交换机.队列和绑定,我们可以从虚拟主机层面的颗粒度进行权限控制 交换机:Exchange用于转发消息,它并不存储消息,如果没有Queue队列绑定到Exchange,它会直接丢弃掉生产者发来的数据. 交换机还有个