最近一直在学Kafka相关的知识,推荐一本书:《深入理解Kafka核心设计与实践原理》——朱忠华 著。这本书确实写的很不错,写的非常透彻、细致,研读下来能收获不少。所以从今天开始,我打算用一个月的时间解读一下这本书。整理成类似笔记的文章,算是一种学习总结吧。如果你也刚好在学Kafka或者想了解这方面的知识,又或者已经在工作中使用到了,欢迎大家下面留言讨论!
言归正传,下面我们直接开始第一篇《初识Kafka》。
初识Kafka
>>>> 基本概念
Kafka是一个多分区、多副本且基于Zookeeper协调的分布式消息系统。目前已定位为一个分布式流式处理平台。一个典型的Kafka体系结构包括若干Producer、若干broker、若干Consumer,以及一个Zookeeper集群。如图下图:
其中,Zookeeper是Kafka用来负责集群元数据管理、控制器的选举等操作的。Producer将消息发送到broker,broker负责将收到的消息存储到磁盘中,然后Consumer负责从broker订阅并消费消息(Consumer是使用拉(Pull模式)从服务端拉取消息)。
>>>> 术语与概念
Producer:生产者,负责创建消息,然后将消息发送到Kafka中。
Consumer:消费者,消费者连接到Kafka上并采用Pull模式订阅消息,进而进行相应的业务处理。
broker:一个独立的Kafka服务节点或Kafka服务实例。
Topic与Partition
主题是一个逻辑上的概念,它可以细分为多个分区,一个分区只属于单个主题。分区可以分布在不同的broker上,即一个主题可以横跨多个broker。每条消息被发送到broker之前,会根据分区规则选择存储到哪个具体到分区。如果分区规则设定的合理,所有的消息可以均匀地分配到不同的分区中(即不同的broker上)。这样,就不会因为单台机器I/O造成这个主题的性能瓶颈。通过增加分区的数量可以实现水平扩展,以此来提供比单个broker更强大的性能。
同一主题下的不同分区包含的消息是不同的。分区在存储层面可以看作是一个可追加的日志(Log)文件,消息在被追加到分区日志文件到时候都会分配一个特定的偏移量(offset)。offset是消息在分区中的唯一标识,Kafka通过它来保证消息在分区内的有序性,但offset并不夸分区,所以Kafka保证的是分区有序而非主题有序。
Kafka为分区引入了多副本(Replica)机制,通过增加副本数量可以提升容灾能力。副本之间是“一主多从”的关系,其中leader副本负责处理读写请求,follower副本只负责与leader副本的消息同步,同一分区的不同副本中保存的是相同的消息(在同一时刻,副本之间并非完全相同)。副本处于不同的broker中,当leader副本出现故障时,从follower副本中选举新的leader副本对外提供服务。通过多副本机制实现了故障的自动转移。
IR、ISR、OSR
分区中的所有副本统称为AR(Assigned Replicas)。所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR(In-Sync Replicas)。消息会先发送到leader副本,之后follower副本才能从leader副本中拉取消息进行同步,同步期间内follower副本相对于leader副本而言会有一定程度的滞后。与leader副本同步滞后过多的副本(不包括leader副本)组成OSR(Out-of-Sync Replicas),由此可见,AR=ISR+OSR。ISR与OSR都是AR的一个子集。
一定程度的滞后是指可忍受的滞后范围,这个范围可以通过参数进行设置。正常情况下,所有的follower副本都应该与leader副本保持一定程度的同步,即AR=ISR,OSR为空集。
leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态,当follower副本落后太多或失效时,leader副本会把它从ISR集合中剔除。如果OSR集合中有follower副本“追上”的leader副本,那么leader副本会把它从OSR集合转移至ISR集合。默认情况下,当leader副本发生故障时,只有在ISR集合中的副本才有资格被选举为新的leader(不过这个原则可以通过修改相应的参数配置来改变)。
HW与LEO
HW(High Watermark),俗称高水位。它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个offset之前的消息。
LEO(Log End Offset),它标识当前日志文件中下一条待写入消息的offset。
分区IRS集合中的每个副本都会维护自身的LEO,而IRS集合中最小的LEO即为分区的HW,对消费者而言只能消费HW之前的消息。
同步复制要求所有能工作的follower副本都复制完,这条消息才会被确认为已经提交成功,这种复制方式极大地影响了性能。异步复制下,数据只要被leader副本写入就被认为已经提交成功,这种情况下,如果follower副本都还没有复制完而落后于leader副本,突然leader副本宕机,则会造成数据丢失。Kafka的复制机制既不是完全同步,也不是单纯的异步复制,使用这种ISR的方式则有效地权衡了数据可靠性与性能之间的关系。
>>>>服务端参数配置
1.zookeeper.connect
该参数指明broker要链接的zookeeper集群的服务地址(包含端口号),没有默认值,且此参数为必填项。类似可以配置为localhost:2181,如果Zookeeper集群中有多个节点,则可以用逗号将每个节点隔开,类似于localhost1:2181,localhost2:2181,localhost3:2181这种格式。
2.broker.id
该参数用来指定Kafka集群中broker的唯一标识,默认值为-1。如果没有设置,那么Kafka会自动生成一个。
3.log.dir和log.dirs
Kafka将所有的消息都保存在磁盘上,而这两个参数用来配置Kafka日志文件存放的根目录。一般情况下,log.dir用来配置单个目录,而log.dirs用来配置多个根目录(以逗号分隔),但是Kafka并没有对此做强制性限制,即log.dir和log.dirs都可以用来配置单个或多个根目录。log.dirs的优先级比log.dir高,但如果没有配置log.dirs,则会以log.dir配置为准。默认情况下只配置了log.dir参数,其默认值为/tmp/kafka-logs。
4.message.max.bytes
该参数用来指定broker所能接收消息的最大值,默认值为1000012(B),约等于976.6KB。如果Producer发送的消息大于这个参数所设置的值,那么(Producer)就会报出RecordTooLargeException的异常。如果需要修改这个参数,还需要考虑max.request.size(客户端)、max.message.bytes(Topic端参数)等参数的影响。为了避免修改此参数而引起级联的影响,建议在修改此参数之前考虑分拆消息的可行性。
如果文章对你有帮助的话
请关注并转发一下
长按二维码,扫扫关注哦