你是否正在寻找一个排队系统?
或许,你正在寻找一个更优的方案? 这里汇集了你需要的所有相关信息!
排队系统,堪称后端开发领域中一个深藏不露的秘密。
我无意在此对排队系统进行过分赞美,但我想说,一位初级后端开发人员一旦掌握了将队列集成到系统中的方法,他便会立刻晋升为中级后端开发人员。队列能显著提升用户体验(我们稍后会详细阐述),降低复杂性,同时提高系统的可靠性。
当然,对于那些流量几乎为零的极其简单的Web应用以及宣传册类型的网站,队列可能显得有些多余(在典型的共享主机环境下,你甚至可能无法安装)。然而,对于重要的应用而言,引入队列系统将带来诸多益处,而大型应用则更是离不开队列的支持。
在我们深入探讨之前,我想先声明一点:如果你已经对排队系统非常熟悉,只是想比较各种不同的选项,那么接下来的介绍部分可能会让你感到有些乏味。🙂所以请随意跳过。 介绍部分主要面向那些对排队系统仅有模糊概念或者只是偶尔听说过这个名词的人。
什么是排队系统?
让我们首先了解一下队列的本质。
队列是计算机科学中的一种数据结构,它模拟了我们日常生活中所见的排队场景。举例来说,当你去售票窗口购票时,你会发现自己必须站到队伍的末尾,而排在队伍最前面的人则会先拿到票。这便是我们常说的“先到先得”原则。在计算机科学领域,我们可以编写程序,将任务按照这种方式存储在队列中,并按照相同的“先到先得”顺序逐个处理它们。
需要注意的是,队列本身并不执行任何实际的处理操作。它仅仅是一个临时存储区域,任务在此等待被其他程序或服务提取并处理。如果这些听起来有些抽象,请不必担心。这是一个抽象的概念,但我们将在后续章节中通过具体示例来进行说明。🙂
为什么我们需要排队系统?
简而言之,之所以需要排队系统,主要是为了应对后台处理、并行执行以及故障恢复等问题。让我们通过实例来进一步理解这些方面:
后台处理
设想你正在进行一场时间敏感的电商促销活动,你的应用被设计为在用户完成支付后立即发送确认邮件并显示“感谢”页面。如果此时你所连接的邮件服务器出现故障,页面将会崩溃,从而严重影响用户体验。
想象一下,你可能会因此收到大量的支持请求!在这种情况下,最佳方案是将发送邮件的任务放入作业队列,然后直接向用户展示成功的页面。
并行执行
许多开发者,特别是那些主要开发简单、低流量应用的开发者,习惯于使用定时任务(cron job)进行后台处理。这种方法在处理少量数据时效果不错,但一旦数据量增大,便会难以应对。例如,假设你有一个定时任务,用于编译分析报告并通过邮件发送给用户,你的系统每分钟能处理100份报告。
当你的应用规模扩大,每分钟接收到的请求超过100个时,系统就会开始逐渐积压,最终无法完成所有任务。
而在排队系统中,你可以通过设置多个工作进程来解决这个问题。每个工作进程可以从队列中获取一个任务(每个任务包含100份待处理的报告),并并行执行,从而更快地完成所有任务。
从故障中恢复
作为Web开发人员,我们往往不会过多考虑故障。我们理所当然地认为服务器和我们使用的API会始终在线。但现实并非如此——网络中断是家常便饭,而且你所依赖的优质API也可能因为基础设施问题而宕机(在你说“这绝不会发生在我身上!”之前,别忘了亚马逊S3的大规模中断)。那么,回到报告的例子,如果报告生成过程需要连接支付API,而连接中断了2分钟,那么这200份失败的报告该如何处理?
不过,排队系统确实会带来一些额外的开销。当你进入一个全新的领域时,学习曲线会非常陡峭,你的应用和部署的复杂性也会随之增加,而且队列中的任务并非总能得到100%的精确控制。尽管如此,在某些情况下,构建没有队列的应用几乎是不可能实现的。
接下来,让我们一起看看当今后端/系统排队领域的一些常见选择。
Redis
Redis 通常被视为一个键值存储系统,它主要用于存储、更新和检索字符串数据,而不关心数据的具体结构。虽然早期可能是这样,但如今的Redis已经拥有了高效且非常有用的数据结构,例如列表、排序集合甚至是发布-订阅系统,这使得它非常适合用于实现队列。
Redis的优势包括:
- 完全基于内存的数据库,读写速度极快。
- 高效:能够轻松支持每秒超过100,000次的读写操作。
- 高度灵活的持久化方案。你可以在发生故障时以可能丢失数据为代价追求最高性能,也可以设置为完全保守模式,以牺牲性能来保持数据一致性。
- 开箱即用的集群支持
需要注意的是,Redis本身并没有消息传递/队列/恢复等抽象概念,因此你需要使用现有的软件包或者自己构建一个轻量级的系统。例如,Redis是Laravel PHP框架的默认队列后端,框架的开发者已经实现了一个调度器。
学习Redis 并不困难。
RabbitMQ
Redis和RabbitMQ之间存在一些细微差别,所以让我们先将这些差异阐述清楚。
首先,RabbitMQ的角色更加专业和明确,它的设计目标就是消息传递。换句话说,它最擅长的领域是作为两个系统之间的中间人,而Redis则更多地扮演数据库的角色。因此,RabbitMQ提供了一些Redis所不具备的功能,例如消息路由、重试以及负载均衡等。
如果你仔细思考,任务队列也可以被视为一个消息传递系统,其中调度器、工作进程和任务“提交者”都可以被视为消息传递的参与者。
RabbitMQ的优势包括:
- 提供更高级的消息传递抽象,如果你需要消息传递功能,可以减少应用层的工作量。
- 比Redis更具有电源故障和断电恢复能力(至少默认情况下)。
- 支持分布式部署的集群和联合。
- 提供用于管理和监控部署的实用工具。
- 支持几乎所有主要的编程语言。
- 可以通过你选择的工具(例如Docker、Chef、Puppet等)进行部署。
何时应该使用RabbitMQ? 我认为,当你明确需要异步消息传递功能,但又不想立即处理此列表中其他一些排队选项的巨大复杂性时(详见下文),它是一个很好的选择。
ActiveMQ
如果你身处企业领域(或正在构建高度分布式和大规模的应用),并且不想重复造轮子(并且在这个过程中犯错),那么ActiveMQ 值得你考虑。
ActiveMQ的优势在于:
- 使用Java实现,因此与Java的集成非常简单(遵循JMS标准)。
- 支持多种协议:AMQP、MQTT、STOMP、OpenWire等。
- 开箱即用地处理安全、路由、消息过期、分析等功能。
- 内置对流行的分布式消息传递模式的支持,为你节省时间和避免代价高昂的错误。
这并不是说ActiveMQ仅适用于Java。它拥有Python、C/C++、Node、.Net和其他生态系统的客户端,因此你不必担心未来可能会遇到的兼容性问题。此外,ActiveMQ建立在完全开放的标准之上,因此构建自己的轻量级客户端应该很容易。
需要注意的是,ActiveMQ仅仅是一个代理,并不包含后端。你仍然需要使用受支持的后端之一来存储消息。我之所以把它包含在这里,是因为它不依赖于特定的编程语言(不像Celery、Sidekiq等其他流行的解决方案)。
Amazon MQ
Amazon MQ 值得在此快速但重要地提及。如果你认为ActiveMQ是满足你需求的理想解决方案,但又不想自己处理构建和维护基础设施,Amazon MQ提供了一项托管服务来实现这个目标。它支持ActiveMQ的所有协议,功能上完全没有差别,因为它在底层使用了ActiveMQ本身。
它的优点在于,它是一项托管服务,因此你无需担心使用它之外的任何事情。对于在AWS上部署的应用来说,这更有意义,因为你可以直接从部署中利用其他服务和产品(例如,更快的数据传输)。
Amazon SQS
我们不能指望亚马逊在关键基础设施领域无所作为,不是吗? 🙂
所以我们有了Amazon SQS,这是一个由知名巨头AWS提供的完全托管的简单队列服务(名副其实)。再次强调,细微的差别很重要,所以请注意,SQS并没有消息传递的概念。与Redis类似,它是一个简单的后端,用于在队列中接受和分发任务。
那么,你会在什么情况下使用Amazon SQS?以下是一些原因:
- 你是AWS的忠实拥趸,不愿尝试其他任何东西(老实说,很多人都是如此,我认为这没什么问题)。
- 你需要一个托管解决方案,以确保故障率为零,并且不会丢失任何任务。
- 你不想自己构建集群并且必须自己监控它。或者更糟糕的是,你不想花费宝贵的时间去构建监控工具,而原本你可以利用这些时间进行高效的开发。
- 你已经在AWS平台上进行了大量投入,并且保持锁定状态对你来说具有商业意义。
- 你需要一个集中、简单的排队系统,而不需要消息传递、协议等额外功能。
总而言之,对于那些希望将任务队列集成到系统中,但又不想担心自己安装/监控的人来说,Amazon SQS是一个不错的选择。
Beanstalkd
Beanstalkd 已经存在很长时间了,它是一个久经考验、快速且简单的任务队列后端。Beanstalkd的一些特性使其与Redis有很大不同:
- 它严格意义上是一个任务排队系统,仅此而已。 你将任务放入其中,然后这些任务会被工作进程提取。因此,如果你的应用对消息传递的需求很小,那么你应避免使用Beanstalkd。
- 没有诸如集合、优先级队列等高级数据结构。
- Beanstalkd是先进先出(FIFO)队列。没有办法对任务进行优先级排序。
- 没有集群选项。
尽管如此,Beanstalkd为在单个服务器上运行的简单项目提供了一个灵活而快速的队列系统。对很多人来说,它比Redis更快、更稳定。所以,如果你在使用Redis时遇到问题,并且无论如何都无法解决,而你的需求又很简单,那么Beanstalkd值得一试。
结论
如果你已经读到这里(或只是快速浏览了下内容😉),那么你很有可能对排队系统感兴趣或需要使用它。如果真是这样,那么本页上的列表将对你大有裨益,除非你正在寻找特定于语言/框架的队列系统。
我希望我能告诉你排队系统很简单并且100%可靠,但事实并非如此。它可能很复杂,因为所有操作都在后台发生并且速度非常快(错误可能被忽视并变得代价高昂)。尽管如此,队列仍然非常必要,你会发现它们是你武器库中的强大工具(甚至可能最强大的工具)。祝你好运!🙂