消息队列(⼀):消息队列应⽤场景⼀、什么是队列
队列(Queue)是⼀种常见的数据结构,其最⼤的特点就是先进先出(First In First Out),作为最基础的数据结构,队列应⽤很⼴泛。⽐如⽕车站排队买票等等。可以⽤下图表⽰队列:
其中a1、a2、an表⽰队列中的数据。数据从队尾⼊队列,然后从队头出队列。
⼆、什么是消息队列
消息队列(Message Queue)是⼀种使⽤队列(Queue)作为底层存储数据结构,可以⽤于解决不同进程与应⽤程序之间通讯的分布式消息容器,也可以称为消息中间件。
⽬前⽐较常⽤的消息队列有ActiveMQ、RabbitMQ、Kafka、RocketMQ、Redis等。
消息队列和队列有什么区别呢?
唯⼀的区别在于⼊队列的时候称为⽣产者,出队列的时候称为消费者。
三、消息队列应⽤场景
消息队列应⽤场景⾮常⼴泛,下⾯我们列举⽐较常见的⼏个场景
1、分布式场景rabbitmq rocketmq kafka区别
1.1、异步处理
⼀般我们写的程序都是按照顺序执⾏的(即同步的⽅式)。⽐如电商系统中订单的例⼦,其执⾏顺序如下:
1. ⽤户提交订单。
2. 订单完成以后增加积分。
3. 发⽣积分变动的短信通知。
可以⽤下⾯的流程图表⽰:
如果按照上⾯的顺序执⾏,假如每个服务都需要花费⼀秒,那么客户端就要花费3秒的时间。对于⽤户来说,3秒的时间显然是不能忍受的,那么我们该如何解决呢?我们可以使⽤异步的⽅式来解决这个问题,看下⾯⼀张流程图:
按照这种⽅式,积分服务和短信服务使⽤线程异步的⽅式进⾏操作,那么客户端只需要花费1秒的时间就可以完成了。但是,这种异步的⽅式会带来另外的问题:并发量降低。因为积分服务和短信服务都需要在订单服务⾥⾯开启线程,开启的线程多了,会导致客户端访问订单服务的并发量降低,可能导致客户端提交订单的实际时间会超过1秒钟。那么如何解决异步带来的问题呢?那就是使⽤消息队列,看下⾯的流程图:
在上⾯的流程中,我们增加了⼀个消息队列的⾓⾊,⾸先由客户端提交订单,然后把订单写⼊到消息队列,积分服务和短信服务同时去消费消息队列⾥⾯的消息,这种⽅式不需要订单服务在额外的开启异步线程,客户端可以实现真正的耗时1秒。
1.2、应⽤解耦
我们还是以电商系统为例进⾏讲解,先看下⾯的流程图:
上图的业务逻辑:客户端发起⼀个创建订单的请求,创建订单的时候,我们要先获取库存,然后在去扣减库存,这样订单系统和库存系统就形成了⾮常紧密的依赖关系。假如这时候库存系统发⽣了宕机,由于订单系统依赖于库存系统,这时候订单系统将不能使⽤。那么如何解决呢?
看下⾯使⽤消息队列的流程图:
在上⾯的流程中,我们加⼊了消息队列。⾸先客户端发起创建订单的请求,订单的消息写⼊到消息队列⾥⾯,然后库存系统去消息队列⾥⾯订阅消息,最后异步的去更新库存系统。如果库存系统发⽣了宕机,
由于订单系统不直接依赖于库存系统,所以订单系统可以正常的响应客户端的请求。这样就实现了应⽤解耦。
1.3、流量削峰
对于⾼并发的系统来说,在访问⾼峰时,突发的流量就像洪⽔般涌向应⽤系统,尤其是⼀些⾼并发写操作,随时会导致数据库服务器瘫痪,⽆法继续提供服务。
⽽引⼊消息队列则可以减少突发流量对应⽤系统的冲击。消费队列就像“⽔库”⼀样,拦截上游的洪⽔,削减进⼊下游河道的洪峰流量,从⽽达到减免洪⽔灾害的⽬的。
在这⽅⾯最常见的例⼦就是秒杀系统,⼀般秒杀活动瞬间流量很⾼,如果流量全部涌向秒杀系统,会压垮秒杀系统,通过引⼊消息队列,可以有效缓冲突发流量,达到“削峰”的作⽤。
我们使⽤秒杀的场景来描述流量削峰,先看下⾯⼀张流程图:
在上⾯的流程中,我们把秒杀服务称为上游服务,订单服务、库存服务、余额服务统称为下游服务。客户端发起秒杀的请求,秒杀服务收到客户端发送的请求以后,创建订单,修改库存,扣减余额,这是秒杀的基本业务场景。
假如下游服务只能同时处理1000个并发请求,上游服务可以处理10000个并发请求,⽽客户端发起了10000个请求,超出了下游服务可以处理的并发量,所以会导致下游服务发⽣宕机。这时就可以加⼊消息队列来解决宕机的问题。看下⾯加⼊消息队列的流程图:
我们在上⾯的流程图中加⼊了消息队列,描述服务接收到客户端发送的10000个请求以后,把所有的请求都写⼊到消息队列中,然后下游服务去订阅消息队列⾥⾯的秒杀请求,然后在去执⾏⾃⼰的业务逻辑操作。
我们举个简单的例⼦,上游服务还是能处理10000个并发请求,下游服务还是只能处理1000个并发请求,那么这时候我们在消息队列⾥⾯会允许存1000个并发请求。上游的秒杀服务接收到10000个并发请求,⽽消息队列⾥⾯只能存1000个请求,多余的请求就不会存⼊到消息队列⾥⾯,直接返回给客户端提⽰“系统繁忙,请稍后!”。这就是所谓的流量削峰场景。这是由下游服务可以处理的并发量决定的。由于下游服务只能处理1000个并发请求,所以消息队列⾥⾯只能存1000个秒杀,多余的秒杀请求全部返回客户端提⽰。这样就保证了下游服务的正常响应,不会导致下游服务发⽣宕机,提⾼了系统的可⽤性。
2、⽇志场景
2.1、优化⽇志传输
为了程序的健壮性,我们⼀般会在程序中添加各种记录⽇志的功能,⽐如错误⽇志、操作⽇志等等,看下⾯⼀张流程图:
上⾯的流程图是同步记录⽇志的流程。使⽤同步记录⽇志的流程,会使得整个流程花费的时间增多,⽽且也会容易造成业务系统宕机(如果数据库损坏了,向数据库记录⽇志的操作将会产⽣错误)。我们可以使⽤消息队列的⽅式优化⽇志的传输。看下⾯的流程图:
加⼊了消息队列以后,可以缩短系统花费的时间,⽽且也可以达到应⽤系统解耦的功能。
3、及时通讯场景
3.1、聊天室
消息队列最主要功能是收发消息,其内部有⾼效的通讯机制,因此⾮常适合⽤于消息通讯。
我们可以基于消息队列开发点对点的聊天系统,也可以开发⼴播系统,⽤于将消息⼴播给⼤量接收者。
其他: