一、同步与异步
作为项目的基础,首先要理解同步与异步的区别。
同步:用户发起请求,服务端执行任务,指导执行完任务之后才给用户回包报告任务完成。
异步:用户调用接口向服务端发起请求,此时收到一个任务凭证,一般是taskid,接着任务在服务端异步处理,用户与此同时调用接口轮询任务是否完成。(此处还有一个机制叫回调,即设置回调函数,等待任务完成后通知用户,但是此处有两个问题,首先是接口调用方必须提供调用者的地址,其次是需要考虑回调失败的情况,所以一般使用轮询这个机制,但回调可以保证更加及时,有一些业务团队两种都使用,将轮询作为兜底,回调确保及时性)
异步的使用场景:耗时操作,一个请求需要很多时间才完成,这种底层处理一般对上层暴露两个接口,一个发起任务的接口,另一个查询任务接口,我们所说的框架能够很好地串联多个异步任务。而且本项目的核心是这个框架,对于细节的处理,即如何实现例如任务处理,鉴黄,转码等操作均交给封装好的第三方去做。
同时,希望阶段与阶段间同步,即需要有依赖,像之前说过的,上一步的输出是下一步的输入。
总结来说分为以下三点:1.整体的异步。
2.阶段间的同步
3.阶段内的异步
二、消息队列
本项目强行定义多个阶段就是为了与消息队列作区分,如果只有单个阶段,或是阶段间没有强一致性,也就是说不存在依赖关系的阶段就可以用消息队列而不是异步处理框架。但是要注意的是消息队列本身可以用于异步处理。
①消息队列的由来
消息队列作为最古老的中间件之一,主要用于收发消息但又不仅仅限于收发消息。
举个形象的例子,一家巧克力工厂,需要生产、研磨、成型三个车间,为了提高生产效率,我们不希望阶段与阶段之间同步,即并不需要完成某个阶段后才进行下一个阶段(不用生产完豆子拿去研磨,研磨完拿去成型这样工厂同时只做一件事),因此添加了传送带来解决这个问题,即每个车间做完之后放上传送带即可,并不需要等待上一阶段的完成,这实际解决了上下游工序之间的“通信”问题。但传送带带来了新的问题,即传送带堵塞问题,生产完的豆子可能来不及第一时间被研磨,而研磨车间传递出去时,成型车间也不一定能够第一时间成型所有研磨好的巧克力豆,为了解决这个问题,可以在每个传送的下游配备一个暂存仓库,这样上下游的车间都不用考虑下游是否有足够的效率处理自己传送过去的巧克力,只需要在某个车间有空时从暂存仓库中取出半成品即可,这个仓库实际上起到了通信过程中的“缓存”作用,传送带解决了运输问题,仓库可以暂存一些半成品,解决了上下游生产速度不一致的问题,这是一个巧克力版本的简单消息队列(MQ)。
②哪些问题适合消息队列解决
Ⅰ.异步问题:一个很经典的问题,秒杀系统的设计,其核心问题是如何利用有限的服务器资源处理短时间内尽可能多的请求,一个秒杀系统可能包括的步骤包括:风险控制、库存锁定、生成订单、通知用户、更新统计数据等,如果没有任何优化,这将是一个同步执行的过程,即APP发送请求给网关,依次调用上述五个流程,然后将结果返回给APP,这将是一个非常麻烦的过程,但事实上,决定秒杀成功的只有风险控制和库存锁定两个阶段,只要这两个阶段完成,就可以返回给用户秒杀成功,对于后续的步骤,不一定要在秒杀请求中处理完成,消息队列就在此时展示用处,在前两个阶段依次执行完之后,确定本次的秒杀结果就可以返回给用户秒杀结果,然后把请求的数据放到消息队列中,由消息队列异步执行后续操作,这样的话,5个步骤被简化为了2个,且更多的资源被用来处理秒杀服务,秒杀结束后在处理后续业务,充分利用了资源。大致流程如下图所示:
这样的好处是:①更快返回结果,用户等待时间变短
②实现了步骤之间的并发,提升了系统的总体性能。
2.流量控制
还是上述的秒杀系统,在实现了异步处理使系统快速处理秒杀任务的功能之后,还有一个问题,如何避免过多的请求压垮秒杀系统,也就是所谓的“健壮性”,也就是说在自己的能力范围内处理尽可能多的请求,拒绝处理不了的请求并维持自身正常运转。但现实中很多程序并不具有健壮性,且直接给用户报错也会导致不好的用户体验。这里又用到消息队列在网关和秒杀系统之间做一个隔离,达到流量控制和保护后端服务的目的。加入消息队列后,整个过程变为网关在收到请求后,将请求放入请求消息队列,然后后端服务根据自己的处理能力从消息队列中获取APP请求,完成秒杀过程,然后返回结果,具体流程如下:
此时即使有大量的秒杀请求,也不会直接冲击后端服务,而是会暂存在消息队列当中,后端服务根据自己的处理能力,消费消息队列中的请求。对于超时的请求可以丢弃,APP直接返回秒杀失败即可,并且,运维人员还可以随时增加秒杀服务的实例数量以进行扩容,并且不用对系统其他部分做任何修改。这种设计的优点是可以根据下游的处理能力自动调节流量,形成“削峰填谷”的效果。即高负载时限制流量,低负载时充分利用系统资源,避免浪费。
但是显而易见地,这种设计存在两个缺点:1.增加了系统链路,导致系统总体响应时间变长。
2.上下游都要将同步调用改为异步消息,增加了复杂性。
为了简化消息队列操作,克服上述缺点,有一种使用消息队列实现令牌桶的方式。
令牌桶控制流量的原理是:单位时间内只发放固定数量的令牌到令牌桶中,规定服务在处理请求之前必须先从令牌桶中拿出一个令牌,如果令牌桶中没有令牌,则拒绝请求。这样就保证单位时间内,能处理的请求不超过发放令牌的数量,起到了流量控制的作用
实现的方式也很简单,不需要破坏原有的调用链,只要网关在处理 APP 请求时增加一个获取令牌的逻辑。
令牌桶可以简单地用一个有固定容量的消息队列加一个“令牌发生器”来实现:令牌发生器按照预估的处理能力,匀速生产令牌并放入令牌队列(如果队列满了则丢弃令牌),网关在收到请求时去令牌队列消费一个令牌,获取到令牌则继续调用后端秒杀服务,如果获取不到令牌则直接返回秒杀失败。
3.服务解耦
在电商当中,订单是一个比较核心的数据,当一个新的订单创建时,诸如风控、支付、客服、经营分析等系统都会发起新的任务请求,这些系统称为订单的下游系统,随着业务的不断扩展,下游系统随之增多,并且已有的系统也可能不断变化,同时每个系统需要的,可能只是订单数据的一个子集。但这个时候,负责订单开发的团队需要花费很大的精力不断增加新的接口或者调整已有接口,任何一个下游系统接口的改变,都需要订单模块重新上线,这对于一个电商系统的核心服务来说,几乎是不可能的。
因此,所有的电商都选择用消息队列来解决类似的系统耦合过高的问题,引入消息队列后,订单的任何变化都会发送至消息队列中的一个主题Order中,所有订阅了这个Order的下游系统都会收到变化消息,实现了订单数据的实时传递与同步。
注:自我理解相当于订单数据暂时存储在消息队列中,任由下游系统取用,不同主题的队列大概就是不同类型的数据,比如订单主题,库存主题,支付主题等等.
引入消息队列的局限性:1.增加系统链路长度,从而增加系统的复杂.
2.引入消息队列带来的延迟问题.
3.数据不一致问题,因为更新有可能不及时.
③消息队列的常见版本
选择标准:开源,消息可靠不易丢失,Cluster(支持集群,在某个节点宕机时,确保消息队列仍能正常工作且不会丢失消息)以及足够好的性能
④消息队列产品
1. RabbitMQ
优势:轻量化、迅捷、易于部署与使用。宣传为“开箱即用”的消息队列。号称世界上使用最广泛的消息队列。
特色:Exchange机制,在生产者和队列之间有一个Exchange,可以使用户实现自由的路由配置,根据这个路由配置,生产者将不同的消息分发到不同的队列当中。
不足:1.对消息堆积的处理不好,RM认为队列堵塞是一种不正常的,应尽量去避免,因此当队列中消息堆积时,RM的处理性能会大大降低。
2.虽然每秒钟几万到十几万条消息的处理性能足够出色,但仍有部分场景可能会导致性能跟不上需求。RM的性能实际中常见消息队列中性能最差的。
3.本身使用小众编程语言Erlang,后续扩展和开发是个问题。
②RocketMQ
优点:阿里巴巴开源项目,后捐赠给Apache,双十一使用的就是该架构。性能好,稳定,可靠,每秒处理几十万消息。中文社区,java开发,易于扩展和开发。
特色:毫秒级响应,若项目对时延有要求,优先考虑。
不足:国际上不够通用,与周边生态的集成和兼容稍逊一筹。
③Kafka
优点:在诞生初期,由于面向海量日志场景,因此Kafka设计的比较粗糙,未考虑集群,消息可能会丢失,功能不齐。但后来均做了完善。无论是在可靠性、性能、稳定性都能满足多个场景需求。同时Kafka使用了scala和java语言编程,大量使用了异步和批量的思想,这使得Kafka能做到超高性能,在三者中应该是最优秀的,但与RocketMQ并没有数量级上的差距,同样是几十万条消息每秒。(原博主说测试到最高2000w条消息)
特色:兼容性好。是与周边生态系统兼容最好的MQ。尤其在大数据和流计算领域,几乎所有的相关开源软件都会优先支持Kafka。
不足:由于使用了大量异步与批量设计,使得Kafka反而对于同步消息的处理不够及时,因为当客户端发出一条消息时候,Kafka不会立即处理,而是会等一批一起发送,因此当业务场景中每秒的消息量没有那么大时,Kafka性能反而不高,时延会很大。
④一些二线产品
二线产品都有一些明显的短板,也肯定不会用,了解即可。
ActiveMQ:最老牌的开源MQ,但目前已不再更新与支持。无论是功能还是性能方面,ActiveMQ 都与现代的消息队列存在明显的差距,可能意义就是支持古老的系统版本。
ZeroMQ:并不严格是一个消息队列,而是一个基于消息队列的多线程网络库。如果业务要求是将消息队列集成到进程当中,考虑ZeroMQ。
Plusar:运算与存储分离的设计。新兴的开源消息队列产品,最早是由 Yahoo 开发,目前处于成长期,流行度和成熟度相对没有那么高。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://ohhbene.com/basic-project.html