一、消息队列
1、消息队列概述
消息队列(Message Queue,简称为MQ)是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管从 MQ 中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。
消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题。实现高性能、高可用、可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。
目前在生产环境,使用较多的消息队列有ActiveMQ、RabbitMQ、Kafka、RocketMQ等。
2、消息队列应用场景
消息队列在实际应用中常用的使用场景分为
- 异步处理
- 应用解耦
- 流量削锋
- 消息通讯
2.1、异步处理
场景说明:用户注册后,需要发送注册邮件和发送注册信息,传统的做法有两种:
- 串行方式
- 并行方式
串行方式
将注册信息写入数据库成功后,发送注册邮件,然后发送注册短信,而所有任务执行完成后,返回信息给客户端
并行方式
将注册信息写入数据库成功后,同时进行发送注册邮件和发送注册短信的操作。而所有任务执行完成后,返回信息给客户端。同串行方式相比,并行方式可以提高执行效率,减少执行时间
上面的比较可以发现,假设三个操作均需要50ms的执行时间,排除网络因素,则最终执行完成,串行方式需要150ms,而并行方式需要100ms。
由上可以看出,传统串行和并行的方式会受到系统性能的局限,那么如何解决这个问题?
由此可以引入消息队列,将不是必须的业务逻辑,异步进行处理,由此改造出来的流程为
根据上述的流程,用户的响应时间基本相当于将用户数据写入数据库的时间,发送注册邮件、发送注册短信的消息在写入消息队列后,即可返回执行结果,写入消息队列的时间很快,几乎可以忽略。
2.2、应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。
传统的做法为:订单系统调用库存系统的接口。如下图所示:
这种传统方式的缺点是:
- 假设库存系统访问失败,则订单减少库存失败,导致订单创建失败
- 订单系统同库存系统过度耦合
解决缺点,需要引入消息队列,引入消息队列后的架构如下图所示:
- 订单系统:用户下单后,订单系统进行数据持久化处理,然后将消息写入消息队列,返回订单创建成功
- 库存系统:使用拉/推的方式,获取下单信息,库存系统根据订单信息,进行库存操作。
假如在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其后续操作了。由此实现了订单系统与库存系统的应用解耦。
2.3、流量削峰
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
- 可以控制参与活动的人数;
- 可以缓解短时间内高流量对应用的巨大压力;
流量削锋处理方式系统图如下:
- 服务器在接收到用户请求后,首先写入消息队列。这时如果消息队列中消息数量超过最大数量,则直接拒绝用户请求或返回跳转到错误页面;
- 秒杀业务根据秒杀规则读取消息队列中的请求信息,进行后续处理。
2.4、日志处理
日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。架构简化如下:
- 日志采集客户端:负责日志数据采集,定时写入Kafka队列;
- Kafka消息队列:负责日志数据的接收,存储和转发;
- 日志处理应用:订阅并消费kafka队列中的日志数据;
这种架构在实际开发中的应用,可以参照案例:新浪技术分享:我们如何扛下32亿条实时日志的分析处理
- Kafka:接收用户日志的消息队列。
- Logstash:做日志解析,统一成JSON输出给Elasticsearch。
- Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能。
- Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELK stack的重要原因。
2.5、消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列、聊天室等。
点对点通讯
在点对点通讯架构设计中,客户端A和客户端B共用一个消息队列,即可实现消息通讯功能。
聊天室通讯
客户端A、客户端B、直至客户端N订阅同一消息队列,进行消息的发布与接收,即可实现聊天通讯方案架构设计。
3、消息队列实例
电商系统
消息队列采用高可用、可持久化的消息中间件。比如Active MQ,Rabbit MQ,Rocket MQ。
- 应用将主干逻辑处理完成后,写入消息队列。消息发送是否成功可以开启消息的确认模式。(消息队列返回消息接收成功状态后,应用再返回,这样保障消息的完整性)
- 扩展流程(发短信、配送处理)订阅队列消息。采用推或拉的方式获取消息并处理。
- 消息将应用解耦的同时,带来了数据一致性问题,可以采用最终一致性方式解决。比如主数据写入数据库,扩展应用根据消息队列,并结合数据库方式实现基于消息队列的后续处理。