@为什么需要消息队列?
- 解耦
- 异步
- 削峰
@消息队列的通信模式?
- 点对点(一个消息一个消费者)
- 发布订阅(消息被发送给订阅的消费者)
@术语
- Producer:消息的生产者
- Broker:kafka实例,每个kafka都有一个或多个实例
- Topic:消息的主题,每个broker有多个topic
- Partition:Topic的分区,每个topic有多个partition,分区的作用是负载,提高Kafka的吞吐量,同一个topic在不同的分区的数据是不重复的,表现形式就是一个一个的文件夹
- Replication:每一个分区都有多个副本,每个副本的作用就是在当主分区(Leader)故障的时候或选择一个副本(Follwer)成为新的Leader。在Kafka中默认最大数量是10个,且副本的数量不能超过Broker的数量。Follower和Leader在不同的机器,同一个机器对同一个分区也只有一个副本。
- Message:消息
- Consumer Group:可以将多个消费者组成一个组,同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者可以消费同一个topic的不同分区的数据。
- Zookeeper:kafka集群依赖zookeeper来保存集群的元信息,来保存系统的可用性。
@发送消息
Producer将消息发给Leader,然后Follower主动找Leader同步的,用push模式将数据发布到Broker,消息是顺序写入磁盘的。
@为什么分区?
- 方便扩展
- 提高并发
@怎么找到对应分区?
- 指定partition
- 如果没指定,有key的话根据key值hash出一个partition
- 如果没指定也没有key,则轮询选出一个partition
@如何保证消息不丢失?
ACK应答机制。
Producer向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可以设置为0,1,all:
- 0:Producer不等集群的返回就可以发送下一条,不确保消息发送成功,安全性低但效率高
- 1:只要Leader应答就可以发送下一条
- all:Leader和所有Follower同步后才可以发送下一条
@不存在的Topic写能成功吗?
能,kafka会自动创建topic,分区和副本的数量根据默认配置都是1。
@保存数据
写磁盘,会单独开辟一块磁盘空间,顺序写入数据(比随机高)。
@Partition
Partition在服务器上表现形式就是一个个的文件夹,每个文件夹下有多个segment文件,每个segment文件包括index文件,log文件,timeindex文件三个文件。log是存储(很多个)message的,index和timeindex是用于检索的。
segment文件命名规则:partion全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值。数值最大为64位long大小,19位数字字符长度,没有数字用0填充。
@Message
- offset:一个8字节的有序id号,可以唯一确定每条消息在Partition的位置
- 消息大小:4个字节
- 消息体:存放的消息数据被压缩过,占用的空间根据具体的消息而不一样
@存储策略,旧数据什么时候删除呢?
- 基于时间,默认配置是168个小时(7天)
- 基于大小,默认配置是1073741824
删除数据不会影响性能的,kafka读取特定消息的时间复杂度是O(1)。
@ 消费数据
kafka采用点对点模式,消费者主动去kafka集群拉取消息,同Producer,拉取消息找Leader。
多个消费者可以组成一个消费者组(consumer group),有同一个组id。 同一个消费者组的可以消费同一个topic下不同partition的数据。但是不会组内多个消费者消费同一Partition的数据。 就是说一个partition只能被某消费者组的一个消费者消费。消费者组的consumer的数量最好与partition保持一致。
@查找消息
segment+offset。
- 先用二分找到segment文件(因为segment的命令方式是递增的=前一个序号+前一个的偏移)。
- 打开segment的.index为难,该文件的起始偏移量为offset+1。同样用二分找到第一个小于等于指定相对offset索引的最大的那个。
- 然后打开数据文件,顺序扫描。