同步与异步
同步
调用的问题:
- 业务调用链过长,用户等待时间长
- 部分组件故障会瘫痪整个业务
- 业务高峰期没有缓冲(木桶原理一样,短板成为性能的瓶颈)
异步
异步直接调用的问题:业务高峰期时产生大量的异步线程,造成线程池不够用或者内存爆满
场景
异步处理
可以更快地返回结果;
减少等待,自然实现了步骤之间的并发,提升系统总体的性能。
流量控制
1. 网关在收到请求后,将请求放入请求消息队列;
2. 后端服务从请求消息队列中获取 APP 请求,完成后续秒杀处理过程,然后返回结果。
秒杀开始后,当短时间内大量的秒杀请求到达网关时,不会直接冲击到后端的秒杀服务,而是先堆积在消息队列中,后端服务按照自己的最大处理能力,从消息队列中消费请求进行处理。对于超时的请求可以直接丢弃,APP 将超时无响应的请求处理为秒杀失败即可。运维人员还可以随时增加秒杀服务的实例数量进行水平扩容,而不用对系统的其他部分做任何更改。 这种设计的优点是:能根据下游的处理能力自动调节流量,达到“削峰填谷”的作用。
但这样做同样是有代价的:增加了系统调用链环节,导致总体的响应时延变长。
上下游系统都要将同步调用改为异步消息,增加了系统的复杂度。
如果预估出秒杀服务的处理能力,就可以用消息队列实现一个令牌桶,更简单地进行流量控制
令牌桶控制流量的原理是:单位时间内只发放固定数量的令牌到令牌桶中,规定服务在处理请求之前必须先从令牌桶中拿出一个令牌,如果令牌桶中没有令牌,则拒绝请求。这样就保证单位时间内,能处理的请求不超过发放令牌的数量,起到了流量控制的作用。
实现的方式也很简单,不需要破坏原有的调用链,只要网关在处理 APP 请求时增加一个获取令牌的逻辑。 令牌桶可以简单地用一个有固定容量的消息队列加一个“令牌发生器”来实现:令牌发生器按照预估的处理能力,匀速生产令牌并放入令牌队列(如果队列满了则丢弃令牌),网关在收到请求时去令牌队列消费一个令牌,获取到令牌则继续调用后端秒杀服务,如果获取不到令牌则直接返回秒杀失败。
服务解耦
- 支付系统需要发起支付流程;
- 风控系统需要审核订单的合法性;
- 客服系统需要给用户发短信告知用户;
- 经营分析系统需要更新统计数据;
- ……
这些订单下游的系统都需要实时获得订单数据。随着业务不断发展,这些订单下游系统不断的增加,不断变化,并且每个系统可能只需要订单数据的一个子集,负责订单服务的开发团队不得不花费很大的精力,应对不断增加变化的下游系统,不停地修改调试订单系统与这些下游系统的接口。任何一个下游系统接口变更,都需要订单模块重新进行一次上线,对于一个电商的核心服务来说,这几乎是不可接受的。
所有的电商都选择用消息队列来解决类似的系统耦合过于紧密的问题。引入消息队列后,订单服务在订单变化时发送一条消息到消息队列的一个主题 Order 中,所有下游系统都订阅主题 Order,这样每个下游系统都可以获得一份实时完整的订单数据。无论增加、减少下游系统或是下游系统需求如何变化,订单服务都无需做任何更改,实现了订单服务与下游服务的解耦
消息广播
消息收集
最终一致性
连接流计算任务和数据
做异构数据库之间的数据同步
问题
引入消息队列带来的延迟问题;
增加了系统的复杂度;
可能产生数据不一致的问题。