消息队列

Wednesday, March 7, 2018

概述

消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构,是大型分布式系统不可缺少的环节.

应用场景

异步处理

用户注册时,一般需要进行注册信息写入数据库,发送注册邮件和发送注册成功短信三个操作,处理方式有三种:

  • 串行方式

将注册信息写入数据库后,发送注册邮件,发送注册成功短信,三个操作全部完成后再返回客户端,如下图:

  • 并行方式

将注册信息写入数据库后,发送邮件的同时发送注册成功短信,三个操作完成后再返回客户端,如下图:

  • 引入消息队列

将不是必须的业务操作放入消息队列进行异步处理

假设三个业务执行时间都是50毫秒,不考虑其他操作业务开销,则串行方式执行时间是150ms,并行方式执行时间是100ms,引入消息队列后执行时间仅需50ms,据此计算出串行方式1秒可处理请求数不到7次(1000/150),并行是10次(1000/100),而消息队列方式可执行20从(1000/20).

应用解耦

用户下单后,订单系统需要通知库存系统,这里有两种做法:

  • 传统方式

订单系统直接调用库存系统接口,成功后返回客户端

  • 引入消息队列

订单系统:用户下单后,订单系统完成持久化操作后将消息写入消息队列,立即返回客户端

库存系统:订阅下单消息,采用拉/推方式获取下单信息进行库存操作

可以比对得出,传统方式有两个弊端:

  1. 库存系统一旦出现异常,则减库存操作会失败,进而导致订单失败
  2. 订单系统与库存系统耦合

引入消息队列后,订单系统写入消息队列后即不再关心后续操作,实现订单系统与库存系统的解耦,并且库存系统异常也不会影响订单系统.此方式也提高了扩展性,如果需要添加一个消息后续处理系统,仅仅只需要这个系统订阅消息队列即可.

流量削峰

流量削峰经常用于秒杀活动当中,此类活动一般瞬时流量特别大,严重会导致服务挂掉,这里有两种处理方式:

  • 增加服务器

这种方式简单快速高效,但缺点是活动每次就一会,其余时间服务器一直是闲置的,因而不可取

  • 引入消息队列

服务器接收到用户的请求后,首先写入消息队列,如果消息队列长度超过最大数量,则抛弃用户请求或跳转到错误页面,而秒杀系统则根据消息队列中的数据做后续处理.

这种方式有两个优点

  1. 可以控制参与活动的人数
  2. 可以缓解短时间内高流量压垮服务器

日志处理

日志处理是指引入消息队列(比如Kafka),解决大量日志传输的问题,具体如下:

  • 日志采集客户端负责采集日志,并将消息写入消息队列系统
  • 消息队列负责日志数据的接收,存储和转发
  • 日志处理系统负责订阅并消费消息队列中的日志

消息通讯

消息队列一般都内置高效通信系统,因而可以应用在消息通讯,比如点对点通讯,聊天室等.

  • 点对点通讯

客户端A和客户端B使用同一队列,进行消息通讯

  • 聊天室

客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收,实现类似聊天室效果

应用实例

电商系统

消息队列采用高可用,可持久化的消息中间件,比如Active MQ,Rabbit MQ,Rocket MQ等.

  • 应用完成主业务后,将信息写入消息队列,开启消息的确认模式来确定消息是否发送成功
  • 扩展流程订阅消息,采用推或拉方式获取并处理消息
  • 消息队列解耦应用的同时带来了数据一致性的问题,可采用最终一致性方式解决

日志收集系统

  • Zookeeper提出负载均衡和地址查找服务
  • 日志收集客户端用于采集日志并将消息推送到Kafka队列
  • Kafka集群负责接收,路由,存储,转发消息处理
  • Storm集群及OtherApp采用拉的方式消费消息队列的数据
MessageQueue MessageQueue

PHP-Resque实现轻量级消息队列PHP+Redis实现轻量级消息队列