消息队列是啥
消息队列英文叫Message Queue。是一种先进先出的数据结构。
//1:创建一个保存字符的队列
Queue<String> stringQueue = new LinkedList<String>();
//2:往消息队列中放入消息
stringQueue.offer("hello");
//3:从消息队列中取出消息并打印
System.out.println(stringQueue.poll());
复制代码
上面的代码演示了一个简单的队列。作用就是保存消息,取出消息。消息队列的本质就是一个消息的容器。消息的生产者产生消息放入队列,消息的消费者取出消息进行消费。
所以,kafka就是个二道贩子,把消息接进来,然后送出去。
消息队列的应用场景
-
应用解耦
应用和应用之间如果使用接口进行交互,这属于一种强耦合的调用关系,假如接口调用失败,则整个过程都失败。这里加入消息队列作为一个中转,调用者把调用接口的行为变为向消息队列发送消息,生产者发送成功后,他的使命就完成了。他不关心消息是否被及时消费。而消息的消费者在合适的时间取出消息进行消费即可。
-
异步处理
异步处理就是多应用对消息队列的同一消息进行处理,并发处理消息,比起串行处理,效率大大提高。
-
限流削峰
比如秒杀这种业务场景,用消息队列做一个容器,这个容器是能放十条消息(限制队列长度即可实现),后台只需要慢慢消费这十条消息即可,避免了大量请求直接涌向后台接口,把后台接口搞崩掉。
-
消息驱动的系统
系统分为消息队列,消息生产者,消息消费者,生产者负责生产消息,消费者(多个)负责对消息进行处理。就是一种系统设计理念。通过消息队列做到解耦合,也做到了缓冲,削峰的作用。
消息队列的两种方式
点对点模式
点对点模式包括三个角色
- 消息队列
- 发送者(生产者)
- 接收者(消费者)
消息发送者发送消息,消息消费者消费消息,当消息被消费之后,队列中就不在保存消息。所以消息消费者不可能消费到已经被消费的消息。
发布/订阅模式
发布/订阅模式
发布/订阅模式包括三个角色:
- 角色主题(Topic)
- 发布者(Publisher)
- 订阅者(Subscriber)
发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
发布/订阅模式的特点:
- 每个消息可以有多个订阅者。也就是一个消息可以被不同的订阅者消费。
- 发布者和订阅者有时间上的依赖。针对某个Topic的订阅者,订阅者必须订阅之后才能消费该主题发布的消息。
- 订阅者必须提前订阅该角色主题,并保持在线运行。
kafka基本情况
分布式,分区,多副本,多订阅这的日志系统(分布式MQ系统)。
发送消息者为Producer,消息接收者为Consumer。Kafka集群由多个kafka实例组成,每个实例(Server)叫做broker。无论是kafka集群,还是producer和consumer都依赖于Zookeeper来保证系统可用性,zk中保存了一些元(mate)信息。
kafka的特点:
- 可靠性:分布式,分区,复制,容错
- 可扩展性:kafka消息传递系统轻松缩放,无需停机
- 耐用性:kafka使用分布式提交日志,这个以为这他会尽可能的快速将数据持久化到磁盘上,因此它是持久的。
- 性能:kafka对于发布订阅和消息订阅都具有高吞吐量。
kafka架构
Kafka Cluster: 由多个实例组成cluster。每个实例(服务器)称为broker(掮客)
Kafka broker: kafka集群的每个实例。每个实例都有一个唯一的编号,起标识作用。
Kafka consumer: 消息的消费者,负责消费消息。
Kafka Topic: 主题,用来区分出不同的消息种类。存储消息的时候按种类区分,放入不同的topic下。比如向曾经的广播,每个台有一个频率,然后你要听某个台的话你需要把频率调到对应的频率上,这个频率就是topic。其实就是一个区分的作用。topic是一个逻辑划分单位。
shard: topic的分片。一般来说,不同的分片会放在不同的节点上(broker)。分片的数量理论上是没有上限的。对于一个topic,可以划分为多个小的容器,每个容器其实就是一个分片(分区),然后每个分区可以均匀的落在各个节点上。主要作用是在存储数据的时候,可以让数据在不同的分片上来存储,相当于将数据存储在不同的服务器中,从而达到提高topic存储容量的目的。
replicas: 副本,对每个分片构建多个副本,保证数据不会丢失。副本的上限就是节点的数量。比如kafka集群里有3个实例,那么最多只能设置3个副本。多个副本之间是存在主从关系的。主副本负责数据读写,从副本负责数据拷贝。不过在新版本2.0中有所变化。从副本在一定程度上可以进行读写。副本越多,数据越安全,同时对磁盘占用的空间越多。
kafka原理 分片和副本机制
一个消费者可以监听多个topic。
偏移量。
分片: 对一个topic(主题,理解为一个大容器即可),划分为多个小容器,每个小容器其实就是一个分片(分区),然后这些分片会均匀的落在各个broker上。在存储数据的时候,数据会存储在不同的分片上,也就是数据会落在不同的机器上,从而扩展了topic的存储容量。
副本: 对每个分片的数据复制多个副本,从而保证数据不容易丢失。需要注意的是,同分片的多个副本不能放在一个节点上,因为当这个节点挂掉,那么这些副本就都丢了。副本的目的就是为了防止丢失,所以需要保证副本的分散存储。所以副本的数量受限于节点的数量,副本的最大值只能和节点的最大值相等。
kafka数据不丢失原理(ack)
生产者端如何保证数据不丢失
生产者端是靠ack校验机制保证数据不丢失的。
ack的三个值(0,1,-1)
0:生产者只负责发送消息,不关心消息是否被kafka成功接收。
1:生产者需要保证数据成功发送到指定topic的分片的主副本上,然后kafka会给出ack响应。
-1(all):生产者需要确保消息成功发送到kafka指定topic的分片的所有副本中,并且都给出ack响应,才可以认为消息发送成功了。
broker端如何保证消息不丢失
broker端主要是通过数据的副本机制和ack为-1来保证数据不丢失。
消费端如何保证数据不丢失
1:消费者去连接kafka集群,kafka根据消费者的groupId找到其上次消费的位置(偏移量),如果该消费者是第一次消费,默认从监听的时间开始监听消息。(这里可以配置不同消费机制,也可以从头消费)
2:消费者开始获取数据,之后进行业务处理,然后提交偏移量给kafka。
这里会不会存在消息丢失呢?
答案是不会的!但是这里可能会存在消息重复消费的问题,因为如果当消息消费完成,然后没来得及提交偏移量,消费者挂了,那么下次消费的时候,kafka根据这个消费者groupId找上次消费的位置,而因为消费者上次没有提交偏移量,所以这里就会造成消息重复消费。
kafka的每个消费者组的偏移量信息都记录在哪里呢?
版本不同,记录的位置不同。
在0.8.x版本及之前,偏移量信息被记录在Zookeeper中
在0.8.x之后,偏移量被记录在kafka中,在kafka中专门有一个主题来进行统一的记录(_consumer_offsets 此topic有50个分区,每个分区一个副本)
kafka的存储机制
kafka中数据存储机制:以一个topic分片的副本为例:
index是索引文件,log是日志文件,数据记录在log中。index文件主要用于存储消息的偏移量在log文件的物理偏移量的信息。
kafka是一个消息中间件,当数据被消费了,此时这个数据就可以被认为是无用了,需要在某个时间点删除。
数据存储在副本中,副本被某个broker节点进行管理,最终的数据是存储在磁盘中,那么数据是存储在一个文件中还是分文件存储?
是分文件来存储的。每个文件存储1GB的数据。
在一个文件段中主要由两个文件构成。一个是index,一个是log。index是log的索引文件。
文件名是此文件存储消息的起始偏移量。
为什么kafka要进行分文件来存储数据呢?
1)保证每个文件不至于过大,这样读取效率会更高。
2)kafka仅仅是一个临时存储数据的中介,默认情况下kafka会删除过期数据(时间为7天)。如果放在一个文件中,删除时需要遍历文件内容,效率低,操作麻烦。分文件的话只需要用文件的最后修改时间判断即可。
Kafka的数据查询机制
上图是一个副本的数据,如何快速的找到777777这条数据呢?
1)确定数据所在的segment段
2)在这个段(737337)中先去查询index,从中找到777777消息在log文件中具体的物理偏移量
3)遍历log文件,顺序查找到具体位置,获取数据即可
kafka的生产者分区策略
假设,有一个topic,此topic有三个分片,三个副本。这是消息生产者生产的数据应该发往那个分片,或者所有的分片都会接收到消息吗?
消息只会发送给某一个分片的主副本,然后主副本将信息数据同步给其他两个从副本。
kafka中有四种生产者发送消息的分区策略:
1)hash取模
2)粘性分区(轮询)
3)指定分区方案
4)自定义分区方案
具体懒得写了。。。
kafka消费者的负载均衡策略
如果消息生产的速度远远大于消息消费的速度就会造成消息的积压,那么如何解决呢?
增加消费者数量(需要保证他们在同一组内才能达到提高消费速度的目的啊),这里需要注意的是,kafka的消费者负载均衡规定,在一个消费者组内,消费者的数量最多只能和监听topic的分片数量相等,如果消费者数据量大于了topic的分片数据量,那么总会有消费者处于闲置状态。且一个分片的数据,只能被一个消费者所消费,不能被组内其他消费者所消费。
如何使用kafka模拟点对点和发布订阅呢?
定义多个消费者,让消费者属于不同的group,订阅同一个topic即可,模拟发布订阅
让所有监听topic的消费者,都属于同一个消费者组即可模拟点对点
Kafka数据积压
(可以通过kafka-eagle查看)
Kafka配额限速机制
生产者和消费者以极高的速度生产/消费消息,从而占用broker的全部或者大量资源,造成网络IO饱和。会影响其他topic的正常运行。
配额(Quotas)就是为了解决这个问题。