高并发系统要使用消息队列的原因是:1、业务解耦;2、最终一致性;3、广播;4、错峰与流控。消息队列可以完成了异步解耦的过程,且保证了最终一致性,通过在队列中存放任务保证它最终一定会执行,消息队列有广播功能,利用消息队列可以转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候再处理这些消息。
本文由 项目管理工具PingCode 小编整理
一、为什么高并发系统要使用消息队列
1、业务解耦
成功完成了一个异步解耦的过程。短信发送时只要保证放到消息队列中就可以了,接着做后面的事情就行。一个事务只关心本质的流程,需要依赖其他事情但是不那么重要的时候,有通知即可,无需等待结果。每个成员不必受其他成员影响,可以更独立自主,只通过一个简单的容器来联系。
对于我们的订单系统,订单最终支付成功之后可能需要给用户发送短信积分什么的,但其实这已经不是我们系统的核心流程了。如果外部系统速度偏慢(比如短信网关速度不好),那么主流程的时间会加长很多,用户肯定不希望点击支付过好几分钟才看到结果。那么我们只需要通知短信系统“我们支付成功了”,不一定非要等待它处理完成。
2、最终一致性
主要是用记录和补偿的方式来处理;在做所有的不确定事情之前,先把事情记录下来,然后去做不确定的事,它的结果通常分为三种:成功,失败或者不确定;如果成功,我们就可以把记录的东西清理掉,对于失败和不确定,我们可以采用定时任务的方式把所有失败的事情重新做一遍直到成功为止。
保证了最终一致性,通过在队列中存放任务保证它最终一定会执行。
最终一致性指的是两个系统的状态保持一致,要么都成功,要么都失败。当然有个时间限制,理论上越快越好,但实际上在各种异常的情况下,可能会有一定延迟达到最终一致状态,但最后两个系统的状态是一样的。
业界有一些为“最终一致性”而生的消息队列,如Notify(阿里)、QMQ(去哪儿)等,其设计初衷,就是为了交易系统中的高可靠通知。
以一个银行的转账过程来理解最终一致性,转账的需求很简单,如果A系统扣钱成功,则B系统加钱一定成功。反之则一起回滚,像什么都没发生一样。
然而,这个过程中存在很多可能的意外:
- A扣钱成功,调用B加钱接口失败。
- A扣钱成功,调用B加钱接口虽然成功,但获取最终结果时网络异常引起超时。
- A扣钱成功,B加钱失败,A想回滚扣的钱,但A机器down机。
可见,想把这件看似简单的事真正做成,真的不那么容易。所有跨JVM的一致性问题,从技术的角度讲通用的解决方案是:
- 强一致性,分布式事务,但落地太难且成本太高。
- 最终一致性,主要是用“记录”和“补偿”的方式。在做所有的不确定的事情之前,先把事情记录下来,然后去做不确定的事情,结果可能是:成功、失败或是不确定,“不确定”(例如超时等)可以等价为失败。成功就可以把记录的东西清理掉了,对于失败和不确定,可以依靠定时任务等方式把所有失败的事情重新搞一遍,直到成功为止。
回到刚才的例子,系统在A扣钱成功的情况下,把要给B“通知”这件事记录在库里(为了保证较高的可靠性可以把通知B系统加钱和扣钱成功这两件事维护在一个本地事务里),通知成功则删除这条记录,通知失败或不确定则依靠定时任务补偿性地通知我们,直到我们把状态更新成正确的为止。
消息可能重复,注意消息的重复和幂等。
3、广播
如果没有消息队列,每当一个新的业务接入时,我们都需要连接一个新接口;有了消息队列,我们只需要关心消息是否送到到消息队列,新接入的接口订阅相关的消息,自己去做处理就行了。
4、错峰与流控
利用消息队列,转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候再处理这些消息。试想上下游对于事情的处理能力是不同的。比如,Web前端每秒承受上千万的请求,并不是什么神奇的事情,只需要加多一点机器,再搭建一些LVS负载均衡设备和Nginx等即可。但数据库的处理能力却十分有限,即使使用SSD加分库分表,单机的处理能力仍然在万级。由于成本的考虑,我们不能奢求数据库的机器数量追上前端。
这种问题同样存在于系统和系统之间,如短信系统可能由于短板效应,速度卡在网关上(每秒几百次请求),跟前端的并发量不是一个数量级。但用户晚上个半分钟左右收到短信,一般是不会有太大问题的。如果没有消息队列,两个系统之间通过协商、滑动窗口等复杂的方案也不是说不能实现。但系统复杂性指数级增长,势必在上游或者下游做存储,并且要处理定时、拥塞等一系列问题。而且每当有处理能力有差距的时候,都需要单独开发一套逻辑来维护这套逻辑。所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。
延伸阅读
一、什么是高并发
高并发是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。
高并发相关常用的一些指标有:
1、响应时间
响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间
2、吞吐量
吞吐量:单位时间内处理的请求数量。
3、每秒查询率QPS
QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。
4、并发用户数
并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。
二、什么是消息队列
消息是指在应用之间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。
消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取,消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在。