系统设计基础3:异步执行和消息队列
本文将主要介绍系统设计中的异步执行和消息队列。这里假设读者已经有了一部分这方面的知识,一些概念的介绍不会过于深入,而会将重点放在各种实现方式的优劣比较上。
异步执行
客户端和服务器端的交互方式通常有两种:同步执行和异步执行。其中互联网应用普遍采用的是异步执行,异步执行可以极大的提高系统的处理能力。
以下为两种交互方法的示意图:
同步执行的方式 异步执行的方式不要使用数据库
采用异步执行的方式,需要至少在客户端维护一个消息列表,接收由客户端发送来的消息。这个消息列表很容易的可以想到由数据库来实现,在数据库中记录每条消息本身及其状态,服务器端从数据库中获取待执行的任务并执行,同时进行消息的状态的更新。
但我们说,数据库并不适合异步处理的场景。原因有以下三点:
-
需要频繁读数据库。服务器端需要以一个固定的时间间隔,不断从数据库中获取新的消息。如果间隔设置的很小,将在数据库中产生大量的查询请求,会影响数据库对写入和更新的处理;如果间隔设置的较大,会给异步执行带来一定的处理延迟,对延迟敏感的系统来说是影响很大的。
-
手动清理。对于已经处理过的消息,是需要清理掉的。因此又需要定期对数据库进行删除操作,增加了数据库的负担。
-
可扩展性不佳。如果消息量过大,数据库性能下降时,扩展的工作将会很复杂。
需要特殊注意的是,PostgreSQL是提供对异步执行的支持的,也是通过消息队列的方式,因此对于少量或中等的消息量来说,是可以用PostgreSQL的。
消息队列
消息队列是连接消息发送方和消费方的中间件,它的几个特点是:
- 可以处理海量的并发消息;
- 消息通知采用推送的方式,而不是定期拉取的方式;
- 消息持久化,服务中断时消息不会丢失;
- 过期消息会自动清理;
- 不用担心死锁和竞态的问题。
消息队列的一大特点是消息的拓扑结构可以任意设计,比如一个topic可以对应1个consumer,或多个consumer,如下图所示。
消息队列的应用模型消息队列协议
消息队列协议,随着协议的发展出现了很多,比如STOMP、AMQP、JMS等,其中AMQP是出现的比较晚的,相对技术更先进一些。由于不是本文的重点,这里不展开介绍了。
消息队列协议消息队列中间件的选择
目前开源的消息队列有RabbitMQ、ActiveMQ等,它们除了协议不同外,在实际使用时并没有明显的选择倾向性。通常来说,ActiveMQ和JVM的结合性更高,适合于Java应用;RabbitMQ适合于Ruby、Python的应用。
消息队列除了做系统间的通信外,还可以作为系统内部的任务队列,实现任务的异步执行。此时选择哪种消息队列,更多的考虑的是消息队列的轻量级、易使用和易维护等方面。
小结
本文介绍了在异步执行中进行消息通信的方式,使用数据库的方式在许多场景并不是最好的,但在一些消息量小的情况也是可以使用的,更通用的做法是使用消息队列的方式,消息队列本身的特性,为异步执行提供了很多支持。
欢迎大家订阅专题,其中包含了系统设计基础系列的全部文章:System Design
- 参考文献: