一、为何要用消息队列
场景举例
某天产品人员说:系统要增加一个用户注册功能,注册成功后用户能受到邮件通知。
方案一:提供一个注册页面,点击按钮提交之后保存用户的注册信息,然后发送邮件,最后返回用户注册成功
问题:点击注册按钮之后响应有点慢,开发人员想到的优化方案是保存注册信息与发送邮件分开执行。
方案二:单独启动线程来做发送邮件的事情
问题:注册操作的响应是快乐,但有用户反映没收到注册成功的邮件,能不能再在发送邮件的时候先保存发送邮件的内容,如果邮件发送失败了则进行补发
方案三:提供一个类似于邮局信箱的东西,直接往这个信箱里写上发送邮件的地址、标题和内容,平台部门从信箱里取信息,向所填写的邮件地址发送响应邮件
这个场景就是消息队列的典型场景——异步处理。消息队列还可用于解决解耦、流量削峰、日志收集、事务最终一致性等问题。
1.1 解耦
在大型系统的开发过程中,随需求的叠加,各模块之间逐渐变成互相调用的关系,这种模块间紧密关联的关系就是紧耦合。紧耦合带来的问题是对一个模块的功能变更讲到是其关联模块发生变化,因此各个模块难以独立演化。
要解决这个问题,可以在模块之间调用时增加一个中间层来实现解耦,这也方便以后的扩展。所谓解耦,简单得讲,就是一个模块只关心自己的核心流程,而依赖该模块执行结果的其他模块如果做的不是很重要的事情,有通知即可,无需等待结果。换句话说,基于消息队列的模型,关心的是通知,而非处理。
1.2 流量削峰
当访问量剧增时系统依然可以继续使用,该怎么做呢?首先想到的是购买更多的服务器进行扩展,以增强系统处理并发请求的能力。但对于很多公司来说,突发流量状况其实并不常见,如果都以能处理此类流量峰值为标准投入大量资源随时待命无疑是很多的浪费。在业界的诸多实践中,常见的是使用消息队列,先将短时间高并发的请求持久化,然后逐步处理,从而削平高峰期的并发流量,改善系统的性能。
1.3 日志收集
利用消息队列产品在接受和持久化消息方面的高性能,引入消息队列快速接受日志消息,避免因为写入日志时的某些故障导致业务系统访问阻塞、请求延迟等。所以很多公司会选择构建一个日志收集系统,由它来统一收集业务日志数据,供离线和在线的分析系统使用。
1.4 事务最终一致性
现在从系统设计的角度来思考从支付宝账户向余额宝账户转账的问题。这个场景中,最简单的情况时至少存在两个账户表:
- 支付宝账户表:A(id,userId,amount)
- 余额宝账户表:B(id,userId,amount)
假设从支付宝账户转1000元到余额宝账户,至少要分两步操作。
- 支付宝账户表扣除1000
- 余额宝账户表增加1000
如果这两个账户表在同一个数据库中,那么处理起来就很简单,使这两步操作在同一个事务中。
如果支付宝系统和余额宝系统需要分开建设,导致由两套单独的数据库,此时通过数据库提供的事务处理方式则无法解决问题。这就是很多人听说过的分布式事务问题。
在业界的很多时间方案中,都可以借助消息队列来处理此问题。例如,在支付宝账户扣钱的同时发送一条让余额宝账户加钱的消息到消息队列,余额宝系统一旦接收到该消息九操作数据库在自己的账户中价钱。