写点什么

关于 RabbitMQ,多么希望当初有人告诉我们这些

  • 2022-10-11
    北京
  • 本文字数:2520 字

    阅读完需:约 8 分钟

关于RabbitMQ,多么希望当初有人告诉我们这些

我的手表嗡嗡作响,在黎明前的昏沉中,我不知道这是闹钟响了还是来电话了。现在是凌晨 4 点 45 分。我回过神来,才意识到这是一个陌生号码来电——这可不是什么好兆头。我接通电话,是我的一个同事——他负责我们的支持团队,为我们的客户处理所有的生产问题。“Ryan,抱歉吵醒你,现在还很早。我们最大的客户报告说,他们发出的请求需要两个多小时才能返回结果。我们认为是我们的信息系统出问题了,但我们不确定接下来该怎么做。我们需要你的帮助。请加入我们的电话会议。”过了一会儿,我的手表又响了,这次是闹钟。今天早上的早起可不是为了锻炼。


我们已经在生产环境中运行RabbitMQ将近三年了,99.5%的时间都没有问题。在此期间,我们扩展到了 200 多个运行在数十个虚拟机上的并发消费者客户端,并处理来自我们.NET 应用程序的数亿条消息。我们的主要业务场景是通过 HTTP 调用 Web 服务,获取 JSON 数据或下载 PDF 文档。我会推荐使用 RabbitMQ,因为我们就用了。在大多数情况下,它都很棒,在我们的系统中表现良好。但这里有一个很大的问题,我们在做架构决策时并不知道。


我们使用RabbitMQ来轮询调度作业的执行结果。一般的操作顺序是这样的:用户通过 Web 应用程序提交请求,后端在处理请求时向 RabbitMQ 中添加消息,消费者客户端获取消息并通过 HTTP 调用另一个 Web 服务,将请求提交给实际处理业务逻辑的服务。然后,轮询逻辑开始接管,队列中的后续消息用于轮询处理结果。如果作业还没有执行结果,消费者将消息放回队列,等待下一次轮询尝试(等待时间可由客户配置)。等待的延迟逻辑使用了存活时间(Time-To-Live,TTL)和死信队列。


我们的非生产集群使用两个或三个节点,生产集群使用三个节点。每个集群都有一个负载均衡器,应用程序的流量严格流经负载均衡器。在运行时,发布者和消费者使用相同的负载均衡器。


你应该知道的


在使用 RabbitMQ 三年后,如果再要写与 RabbitMQ 交互相关的代码,我一定会这样告诉我自己。


一开始就请专家帮忙


你可以大概花 2000 到 3000 美元从 RabbitMQ 咨询公司找来专家,利用这个机会审查和验证你的假设和计划、提出问题、获取建议并进行尽职调查,这样就可以减少可能在未来出现的问题。从长远来看,现在做出正确的决策,最有可能在未来帮你节约成本。或者你也可以像我们一样,在遇到麻烦时找专家帮忙。


我们使用了 EasyNetQ 或 NServiceBus


我们的应用程序使用了 RabbitMQ.Client 库,一些抽象库(如 EasyNetQ 和 NServiceBus)也使用了它。这些抽象库比我更了解 RabbitMQ 的底层交互。RabbitMQ 的驱动程序相对底层,所以你需要了解 RabbitMQ 的底层细节。如果这是你第一次使用 RabbitMQ,我保证你不会对它有任何溢美之词。


如果你想知道“为什么不使用包装器库”,我可以告诉你,最初的开发人员在实现接近尾声时离开了公司,他已经使用了 RabbitMQ.Client ,而这个项目最后落到了我的手上。我没有足够的时间重构(我也没想到要把它换成包装器库)。


网络分区是个大问题


RabbitMQ 一般被部署成集群,集群由一个或多个节点组成,节点是运行 RabbitMQ 实例的服务器或容器。集群中所有的节点都必须运行完全相同版本的 RabbitMQ。


RabbitMQ 提供了一种叫作聚簇(Clustering)的机制,这样你就可以将多个 RabbitMQ 实例链接起来,成为一个逻辑 Broker。你可以将请求发送给集群中的任意一个节点,节点会合作发布消息或将消息发送给消费者。


节点之间通过交换关于消息、队列等的信息不断相互通信。如果通信中断,即使只是几毫秒,RabbitMQ 也会进入分区状态,然后它们会根据配置文件中配置的内容决定如何处理通信中断。默认的处理策略是 ignore,也就是直接进入分区状态,并在这种“脑裂”模式下继续运行,从而使集群陷入完全的混乱。这对我们来说简直就是地狱(对我来说更是如此)。退出分区状态的唯一方法是重启分区一侧的节点,然后重新连接另一侧,并丢弃从集群发生分区时积累的数据。


我经历过两种方式的网络分区:通过 Windows 更新和防火墙规则同时更新集群中所有的节点。


对于这个话题,我可以无休止地咆哮,所以我不得不让自己消停一下。正确的配置应该是将 partition_handling 策略设置为 pause_minority。当集群发生分区时,分区的一侧应该将自己关闭,避免发生脑裂。被关闭的一方继续监控集群,等待恢复通信,并在恢复时重新加入。现在你所要做的就是确保你的代码能够正确地处理断开的连接,这样你就有了一个相当健壮的队列解决方案。


根据 CAP 定理,ignore 策略意味着牺牲一致性换取可用性,而 pause_minority 意味着牺牲可用性换取一致性。如果你问我的话,我认为后者是值得的。


你打算如何升级 RabbitMQ


你的 RabbitMQ 版本总归会有过时的那一天。到时候你会怎么做?继续使用不受支持的版本?创建一个新的集群?你计划怎样将流量从遗留集群迁移到新集群?之前已经提到,集群中的所有节点都应该是相同的版本。如果你的计划是进行就地升级,你就会知道这将是多么棘手。


我留给你的只有问题,没有答案。因为每一个决策都高度依赖具体的组织和运营策略。换句话说,每个人可能都有不同的方法来解决这些问题。


如果 RabbitMQ 的消息全部丢失,你该怎么办


如果 RabbitMQ 中所有(或者三分之一)的消息丢失了,你会有多惨?RabbitMQ 是你用来保存记录的系统吗?你有让应用程序回到正常状态的恢复策略吗?如果你把本地服务器迁移到云端,如何让你的 RabbitMQ 消息再次流动起来?


让发布者和消费者使用不同的连接地址


在未来的某个时刻(可能是在升级期间),你希望能够灵活地向不同的集群或负载均衡器发布消息或读取消息。这是一种零风险高回报的模式,你可以尽早在应用程序中使用这种模式,未来的你会因此感谢现在的你。


不断增长的日志文件将占用几十 GB 的磁盘空间


随着时间的推移,RabbitMQ 的日志文件会增长到占用几十 GB 的磁盘空间。我们可以使用 rabbitmqctl rotate_logs 来滚动这些文件,不过也要努力使这个过程自动化,避免因“磁盘空间不足”导致停机。


结论


RabbitMQ 是我们基础设施的一个稳固的组件,选择它可能是一个正确的决定。但你也应该认真对待我在本文中提出的那些问题,至少应该与你的同事和利益相关者沟通,看看应该试着解决哪些痛点。


原文链接:https://ryanrodemoyer.github.io/what-i-wish-someone-would-have-told-me-about-using-rabbitmq-before-it-was-too-late/


2022-10-11 17:555302

评论 1 条评论

发布
用户头像
写了个寂寞
2022-10-21 23:35 · 广东
回复
没有更多了
发现更多内容

针对 MySQL IO 特点进行的存储优化揭秘

焱融科技

MySQL 技术 分布式 高性能 文件存储

教你两招,解决数据膨胀

华为云开发者联盟

数据 GaussDB(DWS) VACUUM 数据膨胀 FSM

校友会小程序开发笔记三:数据库设计

CC同学

小程序云开发 校友录小程序 校友会小程序

详解 Go 程序的启动流程,你知道 g0,m0 是什么吗?

煎鱼

Java php 后端 Go 语言

618 技术特辑(一)不知不觉超预算3倍,你为何买买买停不下来?

华为云开发者联盟

电商 图数据库 知识图谱 618 图引擎服务

MySQL中的pid与socket是什么?

Simon

MySQL

Bzz节点分币系统开发,云算力矿机租赁系统搭建

🌏【架构师指南】分布式技术知识点总结(上)

洛神灬殇

分布式 raft协议 paxos协议 6月日更

PO 就是Scrum中的产品经理?别再搞不清啦

万事ONES

项目管理 Scrum 敏捷开发 PO ONES

【LeetCode】石子游戏Java题解

Albert

算法 LeetCode 6月日更

6月26日,HarmonyOS开发者日将于杭州举办

科技汇

JavaScript 学习(三)

空城机

JavaScript 大前端 6月日更

开发者如何构建技术影响力

不脱发的程序猿

程序人生 开发者如何构建技术影响力 技术影响力

快来,这里有23种设计模式的Go语言实现

华为云开发者联盟

线程 设计模式 单例模式 Go 语言

并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

MetaThoughts

Java 多线程 并发 并发王者

JAVA笔记(三)--变量及运算符

加百利

Java 程序员 后端 6月日更

用EasyRecovery“监控硬盘”功能检测硬盘问题的方法

淋雨

数据恢复 EasyRecovery 文件恢复

拍乐云受邀2021亚太CDN峰会,技术创新赋能行业新价值

拍乐云Pano

RTC

阿里云视频云 Retina 多媒体 AI 体验馆开张啦!

阿里云视频云

阿里云 短视频 视频处理 媒体处理 视频制作

请阐述vue的diff算法

法医

Vue 大前端 6月日更

校友会小程序开发笔记一:背景与技术方案的选型

CC同学

小程序云开发 校友录小程序 校友会小程序

可视化协助矿山,打造“高效率运营战略”,年降成本500W

一只数据鲸鱼

数据可视化 工业4.0 智慧矿山

pprof排查Golang服务内存问题

循环智能

pprof 性能分析 Go 语言

测试工程师如何收拾交接项目的烂摊子

陈磊@Criss

测试

译文 | AI产品经理:如何打造一款SaaS+AI的优质产品

LigaAI

产品经理 研发管理

校友会小程序开发笔记二:功能需求设计

CC同学

小程序云开发 校友录小程序 校友会小程序

校友会小程序开发笔记四:UI基本元素设计

CC同学

小程序云开发

缓存的世界 Redis(二)-持久化

卢卡多多

redis redis持久化 配置文件持久化 6月日更

项目经理如何有效管理需求变更?

万事ONES

需求管理 ONES 项目经理

618 技术特辑(二)几百万人同时下单的秒杀,为什么越来越容易抢到了

华为云开发者联盟

数据库 服务器 流量 618 弹性负载均衡

关于RabbitMQ,多么希望当初有人告诉我们这些_开源_Ryan Rodemoyer_InfoQ精选文章