1. 写在前面
开始学习Kafka。
学习理解一件事物,第一件事情是去理解在这个事物里面的相关概念,廓清了基础概念,你才能知道别人在谈论这件事物的哪一部分,这是很基础的学习方法。
2.概念列举
生产者、消费者和broker
Kafka是基于发布订阅的大吞吐量的消息系统。
一般消息系统可分为点对点的系统和发布订阅系统。
生产者是Kafka消息的产生者,可以是页面的点击行为,可以是某一笔交易的转账,可以是一个日志消息等等,任务你想异步的行为,都可以包装成一个消息,而产生这些消息的服务,都会调用Kafka的client来发送信息都Kafka的服务器。
BrokerKafka的boker也就是kafka的独立服务器,它接受来自生产者的消息,为消息的每个分区设置偏移量,并保存到磁盘中;为消费者提供服务,对消费者的读取行为做响应,并改变偏移量;除此之外还按照配置清除过期的消息等等。
消费者也就是发布订阅系统中的订阅者,消费者根据配置可以是单播或者组播模式,单播模式可以看成所有消费者在同一个群组;组播模式中,对于每个topic,同一个群组中又且仅有一个消费者会消费到该主题的消息,这极大的提升集群对消息的处理速度。
下面是kafka中消息在各角色中的流转关系。(我们假设kafka服务器数量和消息分区数量相等,即每台broker上保存着topic的一个集群,这样图会比较清楚)
Kafka消费者生产者和服务器的关系
由上图,绿色和红色分别代表着不同的topic。
流转过程是这样的:每个消费者都可能产生消息,并保存到kafka集群中的broker上的某个分区中,每个boker都会分担部分消息的存储工作,并维持着该分区的偏移量;对于每个消费者群组,群组中的总会有一台consumer在消费每个topic的消息,随着群组中消费者数量的扩容,群组对于消息的吞吐量也是不断增加的。
消息和批次
消息是Kafka中的最小数据单元,类比与“数据库”中的一条记录;消息由字节数组组成,Kafka没有具体的格式和定义,但是客户端提供的消息定义中有一组可选的数据单元:
public final class ProducerRecord<K, V> {
private final String topic; //消息主题
private final Integer partition; //消息分区
private final K key; //消息的键
private final V value; // 消息值
}
再以上的字段中,只有消息主题是必须的,标识这个消息的分类。
在分区中会具体讲一下消息的键的作用。
批次同我们常说的分批处理思想中的批次概念是一致的;从根本上来讲都是为了减少消耗,提升效率。
如果每一个产生一条消息,我们就写到网络中,会带来大量的开销,所以将消息分批次来传递;当然分批会带来延迟,这样就需要在延迟和吞吐量之间做一个权衡,Kafka提供参数来给开发者优化这种平衡。
单个批次消息越多,延迟越大,同时消息会被压缩,来提升数据的传输和存储能力,当然压缩更消耗CPU。
批次里面的消息都是属于同一个主题中的同一个分区,这样可以保证一次发送一批消息时的网络开销最小。
主题和分区
主题是消息的分类标识,类似与文件系统中的文件夹;
分区是一个主题的队列,同一个主题会包含若干分区,每一个分区都是一个提交记录,消息会被追加到分区中,在一个分区中保证顺序,已先入先出的顺序被消费。
Kafka为每个分区中维护着一个偏移量,偏移量记录着当前分区的消费记录,偏移量保存在分布式协同服务器ZooKeeper上。
分区在Kafka中有着重要的意义,Kafka通过分区来实现数据冗余和主题的横向扩展;多个分区可以分布在不同的kafka服务端机器上,这使主题也可以横跨多个服务器存在,保证了分布式的能力;
在消息中讲到了消息的键,在消息没有配置键的时候,生产者会把消息均衡的写入到各个分区。当我们需要把特定的消息写入到固定的分区时,可以通过消息的键和分区器来实现,分区器会将键生成成散列值,并映射到各个分区上。
为了大量的消息能负载分散,要求主题的分区数要大于当前Kafka的broker服务器数量,这样才能保证所有每个broker能分担到消息的压力。在实际生产中,我们可以增加分区来给主题扩容,但是不能减少分区。
选定分区数量是一个需要经验的事情,需要考虑多个因素:
1.主题需要多大的吞吐
2.单个分区的最大吞吐量多少
3.每个broker上拥有的分区数量,这需要考量磁盘和网络带宽
4.单个分区上拥有的分区也不能太多,毕竟分区越多内存也越大,重新选举的时间也越长
需要注意的是,如果使用了消息的键来控制消息写入分区,那么增加主题时就需要慎重了,因为这会带来rehash的问题。
下一篇会带来Kafka的消费者和生产者详细介绍,以及一些常用的配置。
网友评论