在本文中,我将从为什么需要消息队列开始讲起,举两个小例子,跟你聊聊目前消息队列的一些使用场景。
比如消息队列在复杂系统中的解耦,又比如消息队列在高并发下的场景如果让流量变得更平缓。
随后我会跟你介绍一下Kafka中的一些重要的名词,比如主题、Broker、分区等。
注意,Kafka不仅仅是消息中间件,他还是优秀的分布式流处理平台,不过在本文中重点还是研究Kafka在消息队列中的应用,以及原理。
在我们学习Kafka之前,先想一想什么地方需要用到消息中间件。
然后,我将举两个小例子,简单的说一说消息中间件的使用场景。
比如我们在一个系统中,需要调用其他的很多个系统,我们当然可以在这个系统中挨个调用其他的系统。但是问题就来了,如果我们需要调用的其他系统有变动,比如增加了新的系统,或者有一些系统不再提供服务了,那么应该怎么办呢?修改系统调用的代码,然后再次上线?
这样显得特别的麻烦,而且也使得这个系统与其他的系统完完全全的耦合在了一起。
所以我们可以把我们的”服务调用“,封装成一个消息,发送到消息中间件上。
对于其他的系统,只需要去这个消息中间件上面拉取自己需要的消息,然后进行处理。
此外,对于用户来说,也不需要等待这么长的时间,只要这个系统将消息丢进了消息中间件就可以返回了,这就保证了更快的响应速度。
这就是我们所说的解耦,一个系统只管把数据发送到中间件中,另外的系统只管从中间件中拿到数据,然后处理。
一开口就知道老高并发了。
这个名词我们其实并不陌生,但凡你搜过”高并发“、”秒杀”这一类的关键词,就一定会查到这样的结果。
那么削峰填谷的关键就在于让流量变得更加的平缓。
咱们就拿“秒杀”举例。
那么对于这个商城来讲,这个“秒杀”活动的上游服务就是下单。而这个上游服务需要调用很多的下游服务,比如库存服务生成库存,订单服务生成订单,支付服务,而支付服务又可能需要调用第三方的支付接口等等。简单来讲,就是上游服务的处理速度远远大于下游服务的处理速度。
那么这个时候如果我们不对上游服务做任何的限制,所有的请求直接打到下游服务,那么整个系统都可能挂掉。
所以,我们可以用消息中间件来做“削峰填谷”这件事情。
上游服务只需要将“某某用户在某某时间购买了某某商品”等这些必要的信息,丢进消息中间件中,然后下游服务按照自己的速度,从消息中间件中拉取信息,然后消费。这样,整个系统的处理就能有条不紊了。
在这里,我只是举了一些小例子,省略了很多细节,真正的业务并没有这么简单,还有很多东西是需要考虑的,比如我们把消息放进了消息中间件中,什么时候才能被消费呢,会不会一直饥饿,这个时候需不需要再次发送信息呢?
再比如,如果我再次发送了信息,有没有可能重复消费呢?
又或者,我们发送的信息有没有可能丢了?
诸如此类的问题其实还有很多,我们带着这些问题往下看。
说完了消息队列的用途,我准备跟你介绍一下在Kafka中的几个常见的名词。
但是有一点是需要注意的,虽然在本篇,甚至本系列的文章中,我可能都在讲消息队列这个概念,但是Kafka不仅仅只是个消息引擎系统,他还是一个很优秀的分布式流处理平台。
只不过作者能力学识都有限,所以目前只能先研究消息队列这个方面的内容。
这个很容易理解,生产者就是发送消息的对象。
生产者负责把需要处理的消息或者记录,发送到消息队列中,剩下的事情就与他无关了。
消费者是处理消息的对象。
消费者负责从消息队列中拉取待处理的消息,然后进行处理。
在上面的内容中,我只说到了“把消息丢到消息队列”以及“从消息队列中拉取消息”这么两种说法,那么现在我们要解决的问题是:
怎么确定我该把消息发送到哪/我该从哪里拿消息?
如果有不同种类的消费者,会不会把消息搞混?
其实如果只有一种消息,那么是不会有这个问题的。但是如果有不同种类的消息呢,比如我有下单的消息,也有日志的消息,那么会不会存在订单服务拿到了日志消息这种情况呢?难道我应该配置多个Kafka吗?
所以在Kafka中有了主题这种说法。
在解释原理之前,你可以这么理解,一个主题,对应一个队列。我们在发送消息的时候,选择合适的主题,将消息发送到这个主题中。
生产者将消息发送到设定好的主题中,消费者负责从特定的主题拉取消息,然后进行处理。
如此一来,我们的消息队列就可以处理更多种类的消息了。
上面我们提到了生产者与消费者,他们被称为Kafka的客户端。
既然有客户端,那么就一定有服务端,就是我们这一小节提到的Broker。
Broker相当于Kafka的服务端,你可以理解为是队列存在的地方,生产者把消息发送到Broker中,消费者从Broker中获取消息。
在上面我们提到了,在Broker中有好几个主题,生产者向Broker中的某一个主题发送信息,消费者从Broker中的某一个主题拉取信息。
那么我们很容易的可以发现,这个消息队列是存在性能瓶颈的。
在这里,Broker所在的机器的IO速度,可能会使得这个消息队列存在性能上的瓶颈。
假设我们的Broker上面有特别多的主题,那么这个时候如果由于IO速度不够,可能会导致生产者无法及时的将消息发送到Broker中,消费者无法及时的从Broker中拉取消息。
所以就有了分区这个概念,相当于我们可以把一个主题分成很多份。但是,当生产者往某一个主题中发送消息的时候,并不会把这个消息发送给这个主题的所有分区,而是会发送到这个主题的某一个分区下。
也就是说,这里的分区,是扩展的概念,而不是副本的概念。所以,这里的分区,也被称为数据分区、数据分片。
此外,这些分区可以部署在不同的机器上,性能也就提升了好几倍。
“高可用”这个概念,在互联网中也特别的重要。
而通常来讲,可用性通常都是通过冗余来实现的。
上面我们提到了分区这个概念,利用分区,把一个主题分成多个部分进行扩展。
但是如果某一个分区挂了,是不是就这个主题的很多信息就丢失了呢?
因此有了Replica这个概念。简单的来说,就是把每一个分区,都备份几份,也就是说,Replica是副本的概念。 通常来讲,我们理解的副本,都是有一个leader,若干个follower,且一般leader负责写,follower负责读。不过在Kafka中跟MySQL这些不太一样,在Kafka中follower就仅仅只是作冗余使用,所有的读写还是发生在了leader身上。
首先,谢谢你能看到这里。
在《Kafka入门》系列的文章中,我的打算是跟MySQL系列的文章一样,尽可能的把复杂的概念讲得更加简单易懂一些。另外,也会稍微的深入一点点原理,尽可能的在会用的情况下,知道他是怎么实现的,以及为什么要这么设计。
在这期间我如果有哪些理解的不够到位,或者解释的不对,欢迎留言指正!
再次感谢你能看到这里!
PS:如果有其他的问题,也可以在公众号找到我,欢迎来找我玩~