来了来了,消息队列系列总算来咯。对于搜索引擎相关的知识大家消化的怎么样呀?其实对于搜索引擎来说,我们学习的内容还是挺全面的,也算是比较深入了。而对于消息队列来说,我不准备写得太深入,因为对于这个东西,实战并不算多,主要的原因咱们在今天这篇文章结束的时候再详细的来说吧。
先来说概念,到底啥是消息队列?那么多种消息队列工具,或者叫消息队列中间件,我们应该选择哪个呢?我将以哪个作为主讲呢?咱们一一来看。
说消息队列之前,不得不先说一下队列。跟过我之前数据结构系列的同学们,对队列应该不陌生吧。排队上公交的例子还记得吧?队列的特点最简单的理解就是通过数组,数据从数组的一端进入,比如从数组尾部添加数据(或尾指针),然后从另一端(头部或头指针)出。与之对应的还有一种叫做栈的东西,正好是和它反过来的,栈是从相同的一头进出数据。将队列想像成一根绳子,将它平铺后就有左右两端,我们可以在左边续上新的绳子这叫入队,然后从右边剪掉一部分,这叫出队。同样的,也可以右进左出,反正只要不是在一边出的,就可以看做是队列。
链表和数组都可以实现队列,而且 PHP 中的数组函数也可以非常方便地实现队列这种数据结构。队列在树和图的遍历中,还可以实现广度遍历的效果。这些内容如果大家不记得了,还是要再复习一下哦。
消息队列,英文名是 Message Queue ,简称 MQ 。很明显,它是将“消息”放到队列中。是的,不管别的什么高大上的定义,只要你了解队列的含义,然后把消息当成是要加入队列的数据,或者说,把队列里面的数据称为消息,这就是消息队列。
最早的消息队列,其实是应用在操作系统中作为进程间通信的一种方式存在的。这一块的内容我们之前在 Swoole 系列进程间通讯相关的内容中也讲过。而通常大家所说的消息队列,则是一种中间件,是一种独立的存储型队列系统,不仅可以跨进程跨应用通信,还可以跨服务器远程通信。简单点理解,我们可以写多个系统,然后连接同一个数据库,不同的系统通过读取数据库里的数据就可以实现这些系统之间的通信。而消息队列中间件系统,也是这样的可以独立以及分布式部署的像数据库一样的东西。它以队列这种数据结构为基本载体,让数据以有序的、有流向的方式保存起来。所有的应用、服务、程序都可以读写这个中间队列库中的数据,而这些数据就被称为消息。
通常,消息队列最典型的应用就是由一个应用程序作为生产者,而另一个应用程序作为消费者。当然,也可以同一个程序即是生产者也是消费者。生产者向队列中添加数据,消费者从队列中读取数据,这个添加和读取的顺序都是遵循队列的基本特征的左进右出或右进左出就可以了。一般是先进队的数据先被取出来,对应的一个计算机名词就是 FIFO (First In First Out,栈是 LIFO,Last in First out)。当然,也有优先队列可以改变这种顺序,这个也是非常常见的一个概念。
消息队列本质上就是一个大的缓冲区,只受磁盘和内存容量的限制,可以让不同的生产者向队列中发送消息,也可以让不同的消费者从队列中获取数据。因为这个特点,它可以帮我们做很多平常写程序很难做到的事情,我们最后一个小节会专门讲到消息队列的用途。
好了,其实消息队列的概念大家或多或少都应该了解,咱们也不多废话了。接下来就看看现在市面上各种消息队列工具吧。
之前我们在讲搜索引擎时提到过不少搜索引擎工具。比如说 ES、Sphinx、Solr,还有我们主讲的 XS 以及纯 PHP 实现的 TNTSearch 。是不是感觉都快有选择恐惧症了。说实话,在搜索引擎领域真的不用选择恐惧,大项目直接 ES ,中小型项目 XS ,小型项目 TNTSearch ,没毛病。而对于消息队列,那才真的是让你选择焦虑。
首先,现在最火的大名鼎鼎的 Kafka ,你要是没听过它的大名,就相当于在搜索引擎领域不知道 ES ,在数据库领域不知道 MySQL 一样。但是,相对来说,它的领先地位远达不到 ES 的一骑绝尘和 MySQL 的大比重。不过,它的增长势头也一直没有停歇。同时,它还是配合大数据的最常用的消息队列,天生分布式,并且需要使用 Zookeeper 来做分布式部署。速度极快,单机最高每秒百万级数据吞吐,时效性毫秒级。
然后,就是 RabbitMQ ,另一个大佬,使用 Erlang 开发的消息队列系统。在 Kafka 没有大火前,兔子队列应该是消息队列系统的大哥大。完整的确认及持久化机制,让他的安全性非常高。各种开发语言组件异常丰富,自带的管理界面也非常好用。单机吞吐量万级,时效性微妙级。
两个大哥大,但是它们并没有垄断,还有 RocketMQ 和 ActiveMQ ,一个是阿里开源的类似 Kafka 的,不过仅支持 Java 。另一个是老牌消息队列系统,但也是 Apache 下的顶级项目。
别忘了,Redis 也是有消息队列功能的,所以在这一领域,Redis 是绝对有资格来分一杯羹的。
上面五个是非常常见的消息队列系统,也是非常出名的,但是还有一些比较小众的消息队列系统。说小众其实更确切的说是我在干 PHP 这些年中,接触过的一些 PHP 项目中使用过的消息队列系统。
第一个也是比较古老的,但非常简单的 SQS ,全名是 简单队列系统 ,有用过的小伙伴举手!现在应该叫 Amazon SQS 了吧,是 Amazon 提供的一个云服务?还是这个开源组件就是 Amazon 来维护了?我也不清楚,当时我们的是自己搭起的服务。这个东西真的就是一个完全的队列数据结构的网络存储实现,貌似没有别的什么特别的功能。太久之前用过了,我都记不清细节了。
另外一个叫 Beanstalkd ,用过 Laravel 框架的同学一定见过这个单词吧。Laravel 的队列组件中,直接可用的三个驱动,一个是 Redis ,一个是 Amazon SQS,另一个就是 Beanstalkd 。这个消息队列我没有实战用过,但我知道它是一个非常轻量级的,功能很完整的消息队列系统。如果说 Redis 中的队列功能只是一个附属功能,不是一个完整的消息队列系统级实现的话,那么 Beanstalkd 则是一个非常标准的消息队列实现。据说它就像是一个轻量级的 RabbitMQ 。反正我是没用过也没研究过啦,有用过的小伙伴可以评论区留言分享一些学习资料哦。
上面随便一说,就是一堆。
Kafka、RabbitMQ、RocketMQ、ActiveMQ、Redis、SQS、Beanstalkd 七个。说实话,还有更多的没列出来呢。前面五种是比较通用的,也比较常见的。后面两个则是在 PHP 项目中可能会见到的。
那么我们后面要讲解的,要学习的是哪个呢?
其实呀,在这个系统中,我只是想简单地介绍一下消息队列中的一些基本概念,并不打算像之前的系列文章那样深入的就某一种软件框架进行深入学习。为什么呢?
一是我最大接触过的项目,是一个游戏的统计分析系统,每天最高3000W+的日志量,1000W日活,最高并发单机2W+连接,三台应用服务器接收请求入队,4台消费者处理队列数据。生产者和消费者都是使用 Swoole ,要不应用服务器抗不住。三台服务器同时还提供广告、数据统计分析和后台的服务。这种情况下,也只是使用 Redis 的队列就搞定了,而且还是只用到最简单的 List 功能下的队列效果。配置就是一台 4G 容量的单机阿里云 Redis ,除了日志数据之外,也提供上述其它应用的缓存服务。也就是说,仅仅是这样配置的一个 Redis 就能抗住我所经历过的最大量的项目,所以我是实在不敢想象要用到 Kafka 这样的分布式消息队列的系统得有多大的数据量和并发数。
二是对于大部分的 PHPer 来说,可能连我上面的这种项目经历过的人都少,所以对于消息队列在高并发处理下的需求并不高。大部分的需求只是处理一些异步任务,比如说电商的下单之后的邮件、短信、消息通知之类的功能。对于这类功能来说,Redis 其实并不合适,前面也说过,它是有队列功能,但它并不完整。这样的功能,其实用 RabbitMQ 是非常合适的。
好了,结果也出来了吧?咱们后续学习的内容,以消息队列的概念和几种应用形式为主。使用的工具就是 RabbitMQ 和 Redis 。关于这两个系统具体的安装,以及详细的 API 咱们都不会详细地说,毕竟不是以软件工具的学习为主。
和之前的搜索引擎系列不同,当时我们是通过详细的学习 XS 的各种功能来引出搜索引擎的各种概念,然后通过概念的了解大家再看别的搜索引擎就会感觉非常轻松了。但在消息队列中,本身概念就不多,软件的功能也都是围绕着这些概念的。而且最主要的功能和概念,就是最简单的最普通的那种像数据结构和算法里的队列效果。因此,我们在这个系列中,就以消息队列的各种概念和简单的 RabbitMQ 及 Redis 的示例来进行学习。如果对这些工具的具体 API 有疑问,可以直接去相应的官网查找相关的资料,即使是 RabbitMQ 的官方文档,其实内容也真的不算多。
后续演示的内容,只需要单机的 RabbitMQ 和 Redis 就可以了。我这里是使用 Docker 安装的 RabbitMQ ,然后 Mac 系统的 brew 工具安装的 Redis ,大家也可以先提前准备好哦。需要安装 PHP 的 Redis 扩展以及 Composer 安装 php-amqplib/php-amqplib ,这是 RabbitMQ 的 PHP 扩展包。
学习的内容以我日常接触过的实际应用和消息队列的核心概念为主,因此,不会是某个单独软件工具的具体教程。就是再强调一遍上面说过的,我们是学习功能和概念的,不局限于某个具体的软件。这些功能和概念市面上所有的消息队列工具都有提供的。如果你要更加深入地学习某个队列应用的话,可以去查找相关的文档,比如说 RabbitMQ 的入门手册就有各个语言版本的 https://www.rabbitmq.com/getstarted.html 。这个手册中的这几个例子,浅显易懂,非常经典,是第一推荐学习资料。如果你完全没接触过 RabbitMQ 也没关系,因为每篇文章都会有 RabbitMQ 和 Redis 的实现。对于 Redis 来说,功能比较简单,查阅 Redis 的官方文档即可。而且之前咱们也已经一起学过 Redis 系列了,相信一直跟着我学习的同学都是没问题的。同时我们还会通过 Laravel 框架中的队列功能,来看看在 Redis 中,框架是如何实现本身 Redis 所不具备的各种队列功能的。这也是我们的重点学习内容,整个系列也就六篇文章,围绕的还是 PHPer 们在应用队列时的一些问题和相关概念。内容不多,但相信一起学习完之后,大家对消息队列会有一个更加全面的认识。
有不会安装的小伙伴可以评论区或者公众号留言,也可以加我微信哦!
最后咱们再说一下消息队列能干啥。这个其实也就是简单说下,毕竟相关资料太多了。而且在上面的例子中,我就已经说了两种应用场景了。
流量削峰:高并发场景下的业务处理。就是我前面说的做统计系统的功能。客户端上报的日志,上传上来后直接入库,中间可能会有各种逻辑判断,请求并发量高了之后不仅是应用服务抗不住,数据库可能也抗不住。于是,先进队,然后再由消费者将数据分拆并进行初步整理后入库,以便于后续的分析使用。大数据系统大部分也是在干这事,Kafka 的分布式高并发能力,基本都是头部中大型互联网企业才能用得到的。还有一种情况,秒杀场景下,也会使用消息队列来应对瞬间的超大流量。
应用解耦:就是我前面说过的,下单之后,要向商家发邮件、短信、通知消息,而且也有可能也要同步向客户发送。如果是同步操作,可能会等半天,而且万一邮件发送失败了要不要报错呢?用户界面直接显示报错还是算下单成功呢?使用消息队列之后,咱们下单就正常操作完订单表就好了,下订单的代码不用再写发送信息啥的,把订单信息放到消息队列,让对应的邮件服务、短信服务、通知服务从队列中拿到数据再各自去处理,不影响主业务的流畅完成。
异步通信:综合上述两个功能,其实就是让我们的系统主流程可以快速完成,其它的流程让别的程序异步执行。所有系统也可以根据队列中的内容来进行通信,这也是消息队列在操作系统中最原始的功能。
说人话总结一下,消息队列应对的场景,最主要的问题就是解决大流量、大数据量下处理变慢或者直接崩溃的问题,让数据能够有个缓冲,或者分散处理。而对于我们 PHPer 来说,这一块其实很多同学的接触有限。而且就像上面我说过的,我接触过的最大流量,也只是通过一个很低配置的 Redis 中的不完全队列功能就解决了。所以说,对于消息队列,我的心得确实也只能是点到为止了。
好了,总结一下吧,今天咱们就是简单聊了聊啥是消息队列,有哪些消息队列以及后续我们学习的主要方向。内容非常简单,同时这个系列也不是很复杂很冗长的,大家可以轻松对待哦。