在高并发的应用场景中,由于来不及同步处理请求,接收到的请求往往会发生阻塞。例如,大量的插入、更新请求同时到达数据库,这会导致行或表被锁住,最后会因为请求堆积过多而触发“连接数过多的异常” 的错误。因此,在高并发的应用场景中需要一个缓冲机制,而消息队列则可以很好地充当这样一个角色。消息队列通过异步处理请求来缓解系统的压力。
什么是消息队列
“消息队列” (Message Queue, MQ)从字面来理解,是一个队列,拥有先进先出(FIFO)的特性。它主要用于不同进程或线程之间的通信,用来处理一系列的输入请求。消息队列采用异步通信机制。即:消息的发送者和接收者无须同时与消息队列进行数据交互,消息会一直保存在队列中,直至被接收者读取。每一条消息记录都包含详细的数据说明,包括数据产生的时间、数据类型、特定的输入参数。
消息队列的应用场景
应用解耦:多个应用可通过消息队列对相同的消息进行处理,应用之间相互独立,互不影响;
异步处理:相比于串行和并行处理,异步处理可以减少处理的时间;数据限流:流量高峰期,可通过消息队列来控制流量,避免流量过大而引起应用系统崩溃;
消息通信:实现点对点消息队列或聊天室等。
1.应用解耦,由于消息与平台和语言无关,并且在语法上也不再是函数之间的调用,因此,消息队列允许应用接口独立地进行扩展,只用应用接口遵守同样的接口约束。
举例,用户使用客户端上传一张个人图片。(1)上传系统将图片信息(如唯一ID、图片类型、图片尺寸等)批量写入消息队列,写入成功后会将结果直接返回给客户端。(2)人脸识别系统定时从消息队列中读取数据,完成对新增图片的识别。
图片上传系统无须关心人脸识别系统是否对上传的图片进行了处理,它只需要关心是否成功将图片信息写入消息队列。由于用户无须立即知晓人脸识别的结果,因此人脸识别系统可选择不同的调度策略来处理
2.异步处理,用户在注册账号时,服务程序需要给用户发送邮件注册信息和短信注册信息。比较传统的做法是-通过串行和并行的方式来实现。
(1)串行方式:先将用户注册信息写入数据库,然后发送短信注册信息,再发送邮件注册信息。以上三个任务全部完成后,才会将结果返回给用户。假设这三个阶段的耗时均为20ms,不考虑网络等其他消耗,则整个过程需耗时60ms。
(2)并行方式:先将用户注册信息写入数据库,然后在发送短信注册信息的同时还发送邮件注册信息。以上任务全部完成后才会将结果返回给用户。
针对上述应用场景,采传统方式时,系统的性能(如并发量、吞吐量、响应时间等)会产生瓶颈。此时需要引入消息队列异步处理非必要业务环节
用户将注册信息写入数据库约耗时20ms (和串行和并行的处理时间相同) 。短信和邮件注册信息写入消息队列后会直接将结果返回给用户。由于写入消息队列的速度非常快,基本可以忽略。另外, “通过异步读取消息队列中的短信注册信息”过程和“邮件注册信息”过程相当于同时进行的,那么整个过程约耗时20ms.
从上面的分析可以看出,在调整架构后,系统的整体处理时间是串行方式的1/3,是并行方式的1/2。
3.数据限流:数据限流也是消息队列的常用场景之一,一般在促销和“秒杀”活动中使用得较为广泛。例如,在电商的“双11"活动中,由于瞬间的数据访问量过大,服务器接收到的数据请求·过大,则导致服务器上的应用服务无法处理请求而崩溃。为了解决这类问题,一般需要先将用户请求写入消息队列(相当于用消息队列做一次缓冲),然后服务器上的应用服务再从消息队列中读取数据。
数据限流具有以下优点:·用户请求写数据到消息队列时,不与应用业务服务直接接触,中间存在一次缓冲。这极大地减少了应用服务处理用户请求的压力。可以设置队列的长度,用户请求遵循FIFO(先进先出)原则。后来的用户请求处于队列之外时,是无法秒杀到商品的,这些请求会直接被舍弃,返给用户"商品已售完”的结果。
4.消息通信:消息队列具有高效的通信机制,所以其在点对点通信和聊天室通信中被广泛应用。