1. 做一个消息队列要考虑的问题
参考:消息队列Message Queue_MusicDancing的博客-优快云博客
1.1 消息队列不可能是单机的
使用MQ必然是分布式或集群的。而Kafka天然是分布式的,往一个topic丢数据,实际上就是往多个broker的partition存储数据。
1.2 数据持久化到那里?
数据写到消息队列,可能会存在数据丢失问题,MQ中的数据要持久化到哪里?Kafka会将partition以消息日志的方式(落磁盘)存储起来,通过 顺序访问IO和缓存(等到一定的量或时间)才真正把数据写到磁盘上,来提高速度。
1.3 怎么保证消息有序?
Kafka会将数据写到partition,单个partition的写入是有顺序的。如果要保证全局有序,那只能写入一个partition中。如果要消费也有序,消费者也只能有一个,(也可以有多个,但一个consumer group的消费者只能有一个, 因为consumer启动的时候可以设置从start开始读取)。
1.4 为什么会重复消费数据?
凡是分布式就无法避免网络抖动/机器宕机等问题的发生,很有可能消费者A读取了数据,还没来得及消费,就挂掉了。Zookeeper发现A挂了,让消费者B去消费原本消费者A的分区,等消费者A重连的时候,发现已经重复消费同一条数据了。(各种各样的情况,消费者超时等等都有可能...)。
如果业务上不允许重复消费的问题,最好消费者那端做业务上的校验(如果已经消费过了,就不消费了)。
2. Kafka入门
Kafka类似消息队列,把消息放到队列里边的叫生产者,从队列里边消费的叫消费者。一个消息中间件,往往会有多个队列,此时生产者和消费者就得知道:
1. 把数据丢给哪个队列;
2. 从哪个队列消费。
2.1 Topic&Partition&Broker
因此需要给队列取名字,叫做topic(相当于数据库里边表的概念)。

可以有多个生产者往同一个队列(topic)丢数据,多个消费者从同一个队列(topic)拿数据。为了提高一个队列(topic)的吞吐量,Kafka会把topic进行分区(Partition)。

Kafka集群就是多台Kafka服务器(Broker),一个topic会分为多个partition,实际上partition会分布在不同的broker中,即Kafka是天然分布式的。

2.2 生产者写数据
2.2.1 partition备份
万一其中一台broker出现网络抖动或者挂了怎么办?Kafka是这样做的:
数据存在不同的partition上,kafka把这些partition做备份。每个partition都会备份,这些备份散落在不同的broker上。
生产者往topic丢数据,消费者消费topic的数据,都是与主分区交互。备份分区仅仅用作于备份,不做读写。如果某个Broker挂了,那就会选举出其他Broker的partition来作为主分区,这就实现了高可用。之后被修复过来的前主分区将作为备份分区了。
2.2.2 partition持久化
partition是如何将数据持久化呢?不持久化如果Broker中途挂了,肯定会丢数据。
Kafka将partition的数据写在磁盘(的消息日志),不过Kafka只允许追加写入(顺序访问),避免缓慢的随机 I/O 操作。且不是partition一有数据就立马将数据写到磁盘上,它会先缓存一部分,等到足够多数据量或等待一定的时间再批量写入(flush)。
2.3 消费者消费数据
2.3.1 单个消费者
消费者从partition中取数据。消费者也可以有多个,多个消费者可以组成一个消费者组。

2.3.2 消费者组
上图是一个消费者消费三个分区的情况,下图是一个消费者组(三个消费者),为了提高吞吐量,可以让每个消费者去消费一个分区。
- 如果group中的某个消费者挂了,那么其中一个消费者可能就要消费两个partition了,该消费者需要知道挂掉的消费者消费到哪了;
- 如果只有三个partition,而消费者组有4个消费者,那么一个消费者会空闲;
- 如果多加入一个消费者组,无论是新增的消费者组还是原本的消费者组,都能消费topic的全部数据。(消费者组之间从逻辑上是独立的)

3. 数据读写机制
3.1 写数据
生产者往topic里丢数据是存在partition上的,而partition持久化到磁盘是IO顺序访问的,且先写缓存,隔一段时间或者数据量足够大的时候才批量写入磁盘的。
3.2 读数据
消费者读数据很有讲究:正常的读磁盘数据是需要将内核态数据拷贝到用户态的,而Kafka 通过调用sendfile()直接从内核空间(DMA的)到内核空间(Socket的),少做了一步拷贝的操作。

3.3 offset
Kafka用offset来表示消费者的消费进度,每个消费者会都有自己的offset。每次消费的时候,都会提交这个offset,且选择是自动提交还是手动提交。
在旧版本的Kafka中,
offset由Zookeeper来管理,后来Kafka开发者认为Zookeeper不合适大量的删改操作,于是把offset在broker中以内部topic(__consumer_offsets)的方式来保存起来。

Zookeeper虽然在新版的Kafka中没有用作于保存客户端的offset,但是Zookeeper是Kafka一个重要的依赖。
- 探测broker和consumer的添加或移除;
- 负责维护所有partition的领导者/从属者关系(主分区和备份分区),如果主分区挂了,需要选举出备份分区作为主分区;
- 维护topic、partition等元配置信息;
- ....
1199

被折叠的 条评论
为什么被折叠?



