MQ是什么?消息队列,直接上定义可能不太好理解,咱们直接举几个生活的例子来说明这个消息队列都有啥妙用吧,先总的来说吧有以下几个用处:1.应用解耦,2.消息消峰,3.异步处理等,接着咱们来一个一个看看。
解耦:比如,网购的东西,快递员送货给收货人,以前都要给收货人打电话问什么时候有时间,联系具体时间送货,后来我们现在都有快递柜或者便利店收快递,快递员只需要把快递放到代收点,代收点通知收件人来拿货即可,MQ就如同这个代收点,实现了快递员和收件人的解耦,我们的系统里很多有上下游的系统比如,下了订单,库存系统减少库存,资金系统增加,下了订单之后,只需发送一个订单消息,其他子系统自己取根据消息操作对应系统,实现下单系统和其他系统的解耦。
异步:再比如以前快递员送货的时候都需要按约定时间去等收件人,这个时候就涉及到同步的问题,如果收件人临时有点事,快递员可能要一直等,有了便利店(MQ),快递员把快递放进去以后,不用等收件人,收件人啥时候有空啥时候来领。在我们系统吞吐量是固定的,如果A系统做完调用B然后等B在做完再返回,这个时间肯定大于 A系统做完发个消息给B的时间,这样可以B系统不实时要求的情况下,在吞吐量固定的情况下提高整体的处理效率。
消峰:没有代收点之前,买了一堆快递,都是不同的快递公司,一起到了,电话都打来让去东南西北门领取,直接裂开哈哈,有了代收点(MQ)之后,不同快递公司放到了不同的门,我们只需要慢慢的一个一个门的领取就行,不用着急。在我们系统里就太形象了,一下子过来几百万订单,下游系统不用着急,消息都在消息队列里,一条一条消费就行了,起到了消息消峰的作用。
消息队列也分了两种,一种是点对点,一种是发布订阅,点对点的是一个生产者对应一个消费者,消费者在主动轮训获取消息,好处是消费消息的频率消费者可以自己控制,缺点是需要额外的线程去监听消息队列里有没有消息。发布订阅模式是,类似广播,生产者发送了消息,消息队列会推送数据,消费者是被动的接收或者主动拉取。
接着咱们看看具体的MQ落地的产品Kafka吧,他的底层原理一个图就可以搞定,稍微有点复杂,咱们一点一点来看:
绿色框是消息生产者,红线代表发布的消息,橘黄色框的是kafka的集群,黑色线代表消息的主机给从机的备份,蓝色的虚线代表消息的消费,蓝色框是消息的消费者,Kafka是基于紫色zookeeper的实现的。这样再看是不是清楚了许多,下面是几个名词的含义:
Producer:就是消息的生产者Broker:每一个都是一个kafka的实例,可以粗略的认为一个Broker是一个服务器(也可以不是,大部分是)。Topic:类似一个消息通道一样,规定同一个topic的消息都在一个通道里顺序存放,一个topic可以包含多个Partition,消息也可以存放在不同的分区Partition里。Partition:topic的分区,就是为了负载用的,同一个topic的数据在不同Partition里是不重复被打散的。存在的形式就是文件夹。Replication:副本,每个分区会有多个副本,主分区leader挂了之后follower会选一个当新的leader,副本都在在不同的机器上,默认的最多可以有10个副本。
Consumer:消息的消费者Consumer Group:多个消费者组成的消费组,同一个topic里多个分区,每个消费组里只能有一个消费者,消费同一个分区数据,其他同消费组的消费者无法消费相同topic的相同分区的数据。
接着我们看下,生产者发送消息数据的流程,如图:
生产者发送数据,先去集群获取要存放的leader,然后用ack的三种策略之一来确定是否发送成功,可设置的值为0、1、all。0代表发完消息不等集群返回,最快效率最高,1代表只要leader应答就代表发送成功,all代表leader接收了,follower也全部备份完毕后才返回给生产者,效率最低最安全。
leader收到消息之后,follower是自己主动去拿leader的消息的,备份好会给leader发送确认消息。上面我们知道,topic收到的数据是存在分区里的,具体存到哪个分区呢,也有三种:1.如果写入消息的时候指定了partition就写入指定的,2.没有指定partition但是设置了数据的key会根据key的hash值对partition的个数取余来获取存到哪个partition里,3如果key都没指定,会轮询选出一个partition存放消息。然后存分区的时候是按顺序存的,offset代表可以唯一确定每条消息在parition内的位置。
kafka是存在硬盘上的,意不意外,是不是有的小伙伴疑问了,这种写磁盘的方式难道不是很慢吗,高并发咋使用这种方式,其实kafka是初始化提前开辟了一块空间来顺序写入,比随机写入效率高多了。既然是存在磁盘里,那肯定有个问题,磁盘大小又不是无限大,删除策略是什么?有两种方式,1是基于时间,默认7天后删除,2是基于空间的删除方式,当文件大小大于默认的大小1073741824时删除。
消费数据的时候是什么样子呢,消费者消费数据,也是从leader开始消费,同一个消费组者的消费者可以消费同一topic下不同分区的数据,但是不会组内多个消费者消费同一分区的数据,如下图所示:
图示是消费者组内的消费者小于partition数量的情况,所以会出现某个消费者消费多个partition数据的情况,消费的速度也就不及只处理一个partition的消费者的处理速度!如果是消费者组的消费者多于partition的数量,那会不会出现多个消费者消费同一个partition的数据呢?上面已经提到过不会出现这种情况!多出来的消费者不消费任何partition的数据。所以在实际的应用中,建议消费者组的consumer的数量与partition的数量一致!
最后在补充一点,我们每次消费数据都是会记录消费到第几个offset数据了,在早期的版本中,消费者将消费到的offset维护zookeeper中,consumer每间隔一段时间上报一次,这里容易导致重复消费,且性能不好!在新的版本中消费者消费到的offset已经直接维护在kafk集群自带的topic【__consumer_offsets】中了。
最后,大家想获取更多知识的,可以继续关注公众号,不定时推送。分享了这么牛逼的知识,还不请小编喝个水吗,哈哈哈,欢迎土豪直接赏赞,谢谢,您的支持就是小编最大的动力。