队列用于在大规模分布式系统中有效地管理请求。在具有最小处理负载和小型数据库的小型系统中,写入可以很快;但是,在更复杂和更大的系统中,写入可能需要几乎不确定的长时间。例如,数据可能必须写在不同服务器或索引上的不同位置,或者系统可能只是处于高负载下。在个别写入(或任务)可能需要很长时间的情况下,实现高性能和可用性需要系统的不同组件以异步方式工作;一种常见的方法是使用队列。
让我们假设一个系统,其中每个客户端都在请求在远程服务器上处理任务。这些客户端中的每一个都将其请求发送到服务器,服务器尝试尽快完成任务以将结果返回给相应的客户端。在小型系统中,一台服务器可以像它们一样快地处理传入请求,这种情况应该可以正常工作。但是,当服务器获得的请求数超出其处理能力时,则会强制每个客户端等待其他客户端的请求完成,然后才能生成响应。
这种同步行为会严重降低客户的性能;客户端被迫等待,无法继续做别的工作,直到其请求得到响应。添加额外的服务器以解决高负载也无法解决问题;即使有效的负载平衡到位,也很难确保最大化客户绩效所需的公平和均衡的工作分配。此外,如果处理请求的服务器不可用或失败,则上游客户端也将失败。有效地解决这个问题需要在客户端的请求和为服务它而执行的实际工作之间建立一个抽象。
处理队列就像听起来一样简单:所有传入的任务都被添加到队列中,只要任何工作人员有能力处理,他们就可以从队列中获取任务。这些任务可以表示对数据库的简单写入,也可以表示为生成文档的缩略图预览图像这样复杂的任务。
队列是在异步通信协议上实现的,这意味着当客户端向队列提交任务时,不再需要等待结果;相反,他们只需要确认请求已被正确接收。此确认凭证可以在用户需要这个计算的结果时,用这个凭证去拿结果。队列对可在单个请求中传输的数据大小以及可能在队列中保持未完成的请求数具有隐式或显式限制。
队列还用于容错,因为它们可以提供一些服务中断和故障保护。例如,我们可以创建一个高度健壮的队列,可以重试由于瞬态系统故障而失败的服务请求。最好使用队列来强制执行服务质量保证,而不是直接将客户端暴露给间歇性服务中断,这需要复杂且经常不一致的客户端错误处理。
队列在分布式通信中起着至关重要的作用。有很多方法可以实现它们,还有很多可用的队列开源实现,如RabbitMQ,ZeroMQ,ActiveMQ和BeanstalkD。
总结, 队列2个好处。
在分布式系统中,让客户端和服务端,请求变成异步。这样可以解放客户端的计算机资源用来做别的事。
第二个好处就是,可以容错,故障保护。比如一个服务器临时断网了。队列失败后,会过段时间去重试。这样可以为客户端节约很多维护失败的逻辑。同时如果服务器全挂了,这样任务依然保存在队列里,等有服务器好了,也可以继续做下去。最后,如果客户端请求过快,队列满了后可以实现拒绝策略,防止压垮服务器。