1、异步处理:
优点:可以更快地返回结果;减少等待,自然实现了步骤之间的并发,提升系统总体的性能。
实例:如何设计一个秒杀系统?
秒杀系统需要解决的核心问题是,如何利用有限的服务器资源,尽可能多地处理短时间内的海量请求。
步骤:风险控制 ---> 库存锁定 ---> 生成订单 ---> 短信通知 ---> 更新统计数据
如果没有任何优化,正常的处理流程是:客户端将请求发送给网关,一次调用上述5个流程,然后将结果返回给客户端。对于这5个步骤来说,能否决定秒杀成功,实际上只有风险控制和库存锁定这2个步骤。只要用户的秒杀请求通过风险控制,并在服务端完成库存锁定,就可以给用户返回秒杀结果,对于后续的3个步骤,并不一定要在秒杀请求中处理完成。
所以,当服务端完成前2个步骤,确定本次请求的秒杀结果后,就可以马上给用户返回响应,然后把请求的数据放入消息队列中,由消息队列异步地进行后续的操作。
这样处理一个秒杀请求,从5个步骤减少为2个步骤,这样不仅响应速度更快,并且在秒杀期间,我们可以把大量的服务器资源用来处理秒杀请求。秒杀结束后再把资源用于处理后面的步骤,充分利用有限的服务器资源处理更多的秒杀请求。
2、流量控制:
- 优点:能根据上下游的处理能力自动调节流量,达到“削峰平谷”的作用。
- 缺点:增加了系统调用链环节,导致总体的响应时延边长;上下游系统都要将同步调用改为异步消息,增加了系统的复杂度。
在海量的请求下,单位时间内过多的请求会压垮我们的服务器,造成服务器宕机;那么我们应如何避免过多的请求压垮我们的系统,做到削峰平谷呢?
一个健壮的设计程序有自我保护能力,可以在海量的请求下,还能在自身能力范围内尽可能多地处理请求,拒绝处理不了的请求并且保证自身运行正常。但现实中很多程序并没有那么“健壮”,而直接拒绝请求返回错误对于用户来说也是不怎么好的体验。因此,我们需要设计一套足够健壮的架构来将后端的服务保护起来。
实例1:设计思路 -> 使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。
还以秒杀系统为例,加入消息队列后,整个秒杀流程变为:1、网关在收到请求后,将请求放入请求消息队列;2、后端服务从请求消息队列中获取APP请求,完成后续秒杀处理过程,然后返回结果。
秒杀开始后,当短时间内大量的秒杀请求到达网关时,不会直接冲击到后端的秒杀服务,而是先堆积在消息队列中,后端服务按照自己的最大处理能力,从消息队列中消费请求进行处理。对于超时的请求可以直接丢弃,APP将超时无响应的请求处理为秒杀失败即可。运维人员可以随时增加秒杀服务的实例数量进行水平扩容,而不对系统的其他部分做任何更改。
实例2:简单的流量控制方法 --> 消息队列实现一个令牌桶,前提是我们能够预估出服务器的处理能力。
令牌桶控制流量的原理:单位时间内只发放固定数量的令牌到令牌桶中,规定服务在处理请求之前必须先从令牌桶中拿出一个令牌,如果令牌桶中没有令牌,则拒绝请求。这样就能保证单位时间内,能处理的请求不超过发放令牌的数量,起到了流量控制的作用。
正在上传…重新上传取消正在上传…重新上传取消转存失败重新上传取消
令牌桶可以简单地用一个有固定容量的消息队列加一个“令牌发生器”来实现:令牌发生器按照预估的处理能力,匀速生产令牌并放入令牌队列(如果队列满了则丢弃令牌),网关在收到请求时去令牌队列消费一个令牌,获取到令牌则继续调用后端秒杀服务,如果获取不到令牌则直接返回秒杀失败。
3、服务解耦:
消息队列可以实现系统应用之间的解耦。
实例:订单是电商系统中比较核心的数据,当创建一个新订单时:1、支付系统需要发起支付流程;2、风控系统需要审核订单的合法性;3、客服系统需要给用户发短信告知通知;4、经营分析系统需要更新统计数据;5、等等
这些订单下游的系统都需要实时获得订单数据。随着业务的不断发展,这些订单下游系统不断的增加,不断的变化,并且每个系统可能只需要订单数据的一个子集,负责订单服务的开发团队不得不花费很大的精力,应对不断增加变化的下游系统,不停地修改调试订单系统与这些下游系统的接口。任何一个下游系统接口变更,都需要订单模块重新进行一次上线,对于一个电商的核心服务来说,这几乎是不可接受的。
所有的电商都选择用消息队列来解决类似的系统耦合过于紧密的问题。引入消息队列后,订单服务在订单变化时发送一条消息到消息队列的一个主题Order中,所有下游系统都订阅主题Order,这样每个下游系统都可以获得一份实时完整的订单数据。无论增加、减少下游系统或是下游系统需求如何变化,订单服务都无需做任何更改,实现了订单服务与下游服务的解耦。
4、其它场景:
- 作为发布/订阅系统实现一个微服务级系统间的观察者模式;
- 连接流计算任务和数据;
- 用于将消息广播给大量接收者