「消息队列」看过来!

为了得到更良好的阅读体验,建议您前往我的独立域名博客观看:传送门
)java

1、什么是消息队列?


当我试图用一则通俗的比喻来讲明这个概念的时候,我想到一个有意思的比喻:若是把队列抽象成一个集合体,那么消息队列也就是一堆消息的集合。按照这个思路我想到了「杂志」。这不就是一堆消息的集合吗,关心这些消息的人都能经过「购买」来得到这些消息,而我能够经过不一样种类的「杂志」或许到不一样的消息。而且若是我做为出版方,我能够提供全部出版过的「杂志」,也能够选择让读者只能购买近期的。git

2、为何须要消息队列?


好处一:解耦

假设咱们作了一个会议室预约系统,咱们的一个设备坏了。咱们须要通知预约这个会议室的全部人,因而咱们须要发邮件,伪代码以下:github

@Service
public class EquipmentServiceImpl implements EquipmentService {
    @Autowired private EmailService emailService;
    @Autowired private EquipmentRepository equipmentRepository;

    public void setEquipmentBroken(Long id) {
        Equipment equipment = equipmentRepository.findById(id);
        equipment.setStatus(Equipment.StatusEnum.BROKEN);

        emailService.sendEmail();
    }
}

问题来了,若是咱们后来发现设备坏了而且须要更改可用库存的数量,这时候咱们是否是要在这里加入 InventoryService 库存服务的代码呢?后来若是经理说设备坏了应该通知他才对啊,因此咱们要不要加入 emailService.sendEmailTo(Manager) 这样的代码呢?redis

随着咱们业务模块接入愈来愈多,咱们的代码与其余模块愈来愈耦合,修改代码的难度也指数级的增长,因此咱们引入「消息队列」,把「设备坏了」这样的消息发送到队列中,其余关心这条消息的业务就会获得这样的「通知」,而后就会去作对应的事,这样各个模块之间就解耦了。伪代码看上去以下:数据库

public void setEquipmentBroken(Long id) {
    Equipment equipment = equipmentRepository.findById(id);
    equipment.broken();

    eventBus.publish(new EquipmentBrokenEvent(equipment.id));
}

好处二:异步处理

接着上面的例子,假设咱们已经把「发送邮件」、「修改库存」以及「通知经理」的代码都写入了咱们的 Service 代码中,它们分别耗时:30ms、50ms、80ms,而且咱们得知,本来最主要的功能实际上是「发送邮件」,但咱们完成主要的功能以后却等待了更多的额外时间,这显示是不合理的。服务器

因此咱们为了提升用户体验&提升吞吐量,咱们其实能够引入「消息队列」来进行异步的操做。微信

好处三:削峰/限流

假设咱们的服务器最多能支持每秒 1000 个请求,而咱们公司在节日要搞促销,为了不服务器挂掉咱们额外申请了两台服务器作了负载均衡,因而咱们如今的机器最理想的状况可以支持每秒 3000 个请求,但奈何活动太火爆了,每秒来的请求有大概 4000 个,这些多出来的请求就可能致使服务器给直接挂掉了。架构

因此咱们就引入了一个「消息队列」,让消息不直接到达服务器,而是先让「消息队列」保存这些数据,而后让下面的服务器每一次都取各自能处理的请求数再去处理,这样当请求数超过服务器最大负载时,就不至于把服务器搞挂了。负载均衡

3、消息队列适用的场景


基于上面的描述,咱们大概能想到「消息队列」的局限性,例如当「生产者」须要「从消费者得到反馈」时,就会出现必定的问题。例如我以前尝试着使用「事件驱动」的方式编码时,我想要把 Service 的一些主逻辑给转移到关注该事件的监听器上时,发现有点问题,我本来的意图是想让一部分代码解耦,但做为主逻辑的一部分我须要保证它们准确的执行,当我使用「消息」的方式传递出去时,我没法获得消费者的反馈,因此最终我仍是把主逻辑给迁回来了,算是一次失败的尝试吧。框架

场景一:异步处理

经过上述的问题你也看到了,「消息队列」适用于异步处理,而且是那些不指望从消费者获得反馈的处理。就好像一开始说到的设备坏了的问题,我只须要通知设备坏了,至于以后须要作什么事,关心的人天然会去作相应的处理。

场景二:日志收集

上面提到的异步处理,跟日志系统彷佛搭配起来也很好。特别是当你须要把日志发往单独的数据平台的时候,「消息队列」尤其有用,咱们再也不须要在业务代码里面侵入咱们的各类打点or日志,只须要简单的发布一条消息,再去关注作处理就行了。

场景四:应用解耦

基于上面的例子你应该也能感觉一二了。

场景三:流量削峰

这也是「消息队列」常见的场景,经过引入「消息队列」,咱们一来能够控制请求的人数,二来也能够缓解短期内高流量的压力。

场景四:消息通信

消息通信是指,消息队列通常都内置了高效的通讯机制,所以也能够用在纯的消息通信。好比实现点对点消息队列,或者聊天室等。

4、常见消息队列中间件


若是本身设计一个?

咱们在讨论市面上常见的「消息队列」中间件以前,咱们先来考虑本身造一个怎么样?若是是你本身来设计,你会怎么作?乍一想,彷佛每一个语言都会有本身实现的「队列」,往队列里塞数据,再从队列里面挨个取就好了?

可是一细想好像事情并不简单。做为一个「消息队列」,你首先要保证数据不能给人家弄丢了吧?存内存?万一断电了怎么办?写磁盘?消息量超过系统写磁盘速率上限了怎么办?备份又该怎么作呢?

好,假设我一整捣鼓,保证了个人数据不会丢失了,下一个问题,生产者怎么往「消息队列」里面塞数据?个人意思是,生产者可能不止一个,把全量的消息放在一个队列彷佛不太合适,我须要给这些消息分个类吧?新来了一个分类的消息我怎么动态的扩容呢?消费者又如何消费这些数据呢?多个消费者之间又如何进行协调呢?

好吧..总之问题挺多的..并不像表面那么简单。

RabbitMQ

RabbitMQ 是使用 Erlang 编写的一个开源的消息队列,自己支持不少的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它很是重量级,更适合于企业级的开发。同时实现了 Broker 构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负 载均衡或者数据持久化都有很好的支持。

Redis

Redis 也能用来作「消息队列」。Redis 是一个基于 Key-Value 对的 NoSQL 数据库,开发维护很活跃。虽然它是一个 Key-Value 数据库存储系统,但它自己支持 MQ 功能, 因此彻底能够当作一个轻量级的队列服务来使用。对于 RabbitMQ 和 Redis 的入队和出队操做,各执行 100 万次,每 10 万次记录一次执行时间。测试 数据分为 128 Bytes、512 Bytes、1 K和 10 K四个不一样大小的数据。实验代表:入队时,当数据比较小时 Redis 的性能要高于 RabbitMQ,而若是数据大小超过了 10 K,Redis 则慢的没法忍受;出队时,不管数据大小,Redis 都表现出很是好的性能,而 RabbitMQ 的出队性能则远低于Redis。

Kafka/Jafka

Kafka 是 Apache 下的一个子项目,是一个高性能跨语言分布式 Publish/Subscribe 消息队列系统,而 Jafka 是在 Kafka 之上孵化而来的,即 Kafka 的一个升级版。

具备如下特性:

  • 快速持久化,能够在O(1)的系统开销下进行消息持久化;
  • 高吞吐,在一台普通的服务器上既能够达到 10 W/s的吞吐速率;
  • 彻底的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现复杂均衡;
  • 支持 Hadoop 数据并行加载,对于像Hadoop的同样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。

Kafka 经过 Hadoop 的并行加载机制来统一了在线和离线的消息处理。Apache Kafka 相对于 ActiveMQ 是一个很是轻量级的消息系统,除了性能很是好以外,仍是一个工做良好的分布式系统。

ZeroMQ

ZeroMQ 号称最快的消息队列系统,尤为针对大吞吐量的需求场景。ZeroMQ 可以实现 RabbitMQ 不擅长的高级 / 复杂的队列,可是开发人员须要本身组合多种技术框架,技术上的复杂度是对这 MQ 可以应用成功的挑战。ZeroMQ 具备一个独特的非中间件的模式,你不须要安装和运行一个消息服务器或中间件,由于你的应用程序将扮演这个服务器角色。你只须要简单的引用 ZeroMQ 程序库,可使用 NuGet 安装,而后你就能够愉快的在应用程序之间发送消息了。可是 ZeroMQ 仅提供非持久性的队列,也就是说若是宕机,数据将会丢失。其中,Twitter 的 Storm 0.9.0 之前的版本中默认使用 ZeroMQ 做为数据流的传输(Storm 从 0.9 版本开始同时支持 ZeroMQ 和 Netty 做为传输模块)。

ActiveMQ

ActiveMQ 是 Apache 下的一个子项目。 相似于 ZeroMQ,它可以以代理人和点对点的技术实现队列。同时相似于 RabbitMQ,它少许代码就能够高效地实现高级应用场景。

参考资料


  1. Kafka 设计解析(一):Kafka 背景及架构介绍
  2. 浅谈消息队列及常见的消息中间件
  3. 消息队列介绍及经常使用MQ对比
  4. 什么是消息队列?
  5. 消息队列的使用场景是怎样的? - 知乎

按照惯例黏一个尾巴:

欢迎转载,转载请注明出处!
独立域名博客:wmyskxz.com
简书ID:@我没有三颗心脏
github:wmyskxz 欢迎关注公众微信号:wmyskxz 分享本身的学习 & 学习资料 & 生活 想要交流的朋友也能够加qq群:3382693

相关文章
相关标签/搜索