kafka架构详解及常见问题

kafka是什么

kafka是一种高吞吐量的分布式消息系统

kafka有什么作用

  • 作为常规的消息队列使用
  • 作为网站的活性跟踪工具
  • 作为日志收集中心

kafka的架构

kafka架构详解及常见问题_第1张图片

名词解释
  • broker:消息系统中的一个处理节点,一个kafka节点就是一个broker,多个broker可以组成kafka集群。
  • topic:主题,kafka根据topic对消息进行归类,发布到kafka集群的每一天消息都需要指定一个topic。
  • producer:消息生产者,向broker发送消息的客户端。
  • consumer:消息消费者,从broker消费消息的客户端。
  • consumer group:消费组,每个consumer都属于一个特定的consumer group,一条消息可以发送到多个不同的consumer group中,但是一个consumer group里面只能有一个consumer能够消费该消息。
  • partition:分区,物理上的概念,一个topic可以有多个partition,消息均匀的分配在不同的partition上,每个partition内部的消息是有序的。
topic和partition的关系
  • kafka会为每个topic维护多个分区(partition)日志文件,每个patition在kafka存储层面是append log。
  • producer发送的消息会追加到log文件的尾部,并且分区中会按照时间顺序给每条消息分配一个递增的顺序编号,这个编号就是offset,也叫偏移量,是一个Long型的数字。
  • 我们可以根据offset在分区里确定一条唯一的消息。消息在分区内有序,但topic下面的消息是无法保证有序的。
  • 有多个partition分区时,producer生产者会根据以下两种情况决定把消息发往那个分区:
    1. 如果没有key值,则进行轮询发送。
    2. 如果有key值,会对key值进行hash,然后对分区数量进行取余,保证同一个key值会被路由到同一个分区里。如果想保证队列的强一致性,则可以把所以的消息都设置为同一个key。

partition文件详解

  1. topic中partition的存储分布

在kafka存储文件中,同一个topic下有多个不同的partition,每个partition为一个目录,partition命名规则为topic名称+有序序号,序号从0开始

  1. partition中文件的存储方式
  • 每个partition文件相当于一个大型的文件评价分配到多个大小相等的segment段数据文件中,但是每个segment段中的消息数量不一定相等,这种特性方便老的segment数据文件的快速删除。
  • 每个partition只需要支持顺序读写就行了,segment文件的生命周期有配置决定。
  • 这样做的好处就是能够快速删除无用文件,有效提高磁盘的利用率。
  1. partition中segment数据文件的存储结构
  • segment文件由索引文件和数据文件两部分组成,两个文件一一对应,文件后缀分别是.index和.log
  • 索引文件中存储着大量的元数据,数据文件存储着大量的消息。索引文件中的元数据指向对应数据文件中消息的物理偏移地址。
  1. 在partition中如何通过offset查找到对应的message

比如读取offset=368776的message,需要通过以下两个步骤查找:

  • 第一步查找segment文件
        根据二分查找,根据offset在segment文件列表中查找,快速定位到具体的segment文件。
  • 第二步根据segment文件查找message
        根据找到的segment文件,定位到对应的index文件里的元数据,根据指针找到对应的数据文件,然后开始顺序查找,直到找到368776为止。

kafka的消费模型

  1. 推送模式(Push)

基于推送模型的消费系统,由消息代理记录消费状态。消息代理将消息推送到消费者后,标记消息为已经被消费状态。这种模式无法很好的在消费端很好的控制消费的语义。
比如消费代理把消息推送给消费者后,消费者服务故障导致消息没有正常被处理,但是此消息的消费状态已经被消费代理标记为已消费,那么词条消息就等于丢失了。

  1. 拉取模式(Pull)

消息消费的速率及进度由消费者掌控,可以按照任意的offset偏移量进行消费,可以消费已经消费过的消息。但是如果消费端发送阻塞,就会出现问题。

kafka的网络模型

  • kafka client:单线程的selector

producer和consumer是使用的此模式,并发连接数小,逻辑简单。

  • kafka server:多线程的selector

kafka的服务端用的是多线程的模型。

kafka的高可用性

  1. kafka的多broker集群模式具有天然的高可用性
        每个broker是一个节点,每个topic的消息可以发送到多个partition分区上,而每个分区又可以存在于不同的broker节点上
  2. 副本机制
  • kafka每个主题的分区都会有0个或者多个副本,副本(follower)保持和主副本(leader)的数据同步,如果leader挂掉,follower会替代成为新的leader
  • kafka中并不是所有的follower都能够拿来替代leader,kafka在leader节点中维护了一个ISR(In Sync Replicas)集合。ISR里的follower节点必须和ZK保持连接,并且数据不能落后leader太多。另外AR(Assigned Replicas)集合用来表示所有的副本,OSR(Out Sync Replicas)集合用来标识落后被剔除的副本。
    AR = ISR + OSR
  1. HW:高水位,consumer能够看到此partition的位置
        HW可以保证leader所在的broker失效,该消息仍然可以从新选举的leader中获取,不会造成消息丢失
  2. request.required.acks参数,生产者发送数据时,可以通过该参数来设置数据的可靠级别
  • 1(默认):producer生产者在ISR中的leader已成功收到数据并得到确认后发送下一条数据。可能会存在follower还未来得及同步leader的数据,然后leader挂掉了,那切换到follower称为新的leader后,数据丢失。
    0:producer生产者无需等待来自broker的确认就可以继续发送下一批消息,数据传输效率高,但是数据可靠性低。如果生产者发送数据库,broker并未受到消息就挂掉了,则消息就丢失了。
    -1:producer生产者需要等待ISR中所有的follower都确认收到数据后,才算发送一次消息完成,消息的可靠性最高。但也有一种情下数据会丢失,如果ISR里只有leader节点时(其他follower节点与ZK失去了连接),数据可能会遇到acks=1时的情况。

kafka为什么快

  1. 写数据
  • 顺序写入
        磁盘的读写速度取决于你怎么去使用它,一般分为顺序读写和随机读写。在顺序读写的情况下,某些场景的读写速度可以和内存操作持平。
        因为磁盘是机械结构,每次数据的读写都需要寻址和写入两个步骤,而寻址的动作就是一个“机械动作”,最耗时。所以硬盘最喜欢顺序IO,而最讨厌随机IO。kafka正是采用的顺序IO的形式写入数据。
        因为内存的资源比较珍贵,如果把这些操作都放在内存上,会是一笔非常大的内存开销,会造成频繁而且漫长的GC,很影响性能。
        partition分区会把数据插入到文件末尾,所以我们没办法删除数据。正是因为如此,每个消费者可以根据offset读取到历史的数据。不过kafka也不是永远不会删除数据,他提供了两种策略来删除数据。一是基于时间,比如值保留最近七天的数据;二是基于partition文件的大小,文件保留配置大小的部分。
  1. MMF(Memory Mapped Files)内存映射文件
        利用操作系统的Page来实现文件到物理内存的直接映射,完成映射之后你对物理内存的映射会被同步到磁盘上(操作系统在适当的时候)。
        这种方式节省了很多磁盘的IO,省去了用户空间到内核空间的开销。
        同时这样方式有一个缺点就是数据不可靠,因为数据没有真正写到磁盘上,操作系统会在程序主动调用fush的时候才把数据真正写到磁盘。对此,kafka提供了一个参数,producer.type来控制数据是不是主动flush。如果kafka写入mmp后立即flush到磁盘再返回producer就叫同步(sync),如果不立即flush就叫异步(async)。
  1. 读数据
  • 基于sendFile实现Zero Copy
        传统模式下,当需要对一个文件进行传输是,具体流程的细节如下:
    (1)调用read函数,文件数据被copy到内核缓冲区
    (2)read函数返回,文件数据从内核缓冲区copy到用户缓冲区
    (3)write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区
    (4)数据从socket缓冲区copy到相关协议引擎。
    以上细节是传统read/write方式进行网络文件传输的方式,我们可以看到,在这个过程当中,文件数据实际上是经过了四次copy操作:
        硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎
    而sendfile系统调用则提供了一种减少以上多次copy,提升文件传输性能的方法。
    在内核版本2.1中,引入了sendfile系统调用,以简化网络上和两个本地文件之间的数据传输。sendfile的引入不仅减少了数据复制,还减少了上下文切换。
  1. 批量压缩

在很多情况下,系统的瓶颈不是CPU或磁盘,而是网络IO,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。
进行数据压缩会消耗少量的CPU资源,不过对于kafka而言,网络IO更应该需要考虑。

  • 如果每个消息都压缩,但是压缩率相对很低,所以Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩
  • Kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保持压缩格式,直到被消费者解压缩
  • Kafka支持多种压缩协议,包括Gzip和Snappy压缩协议

kafka怎么保证消息不丢失

待补充

kafka怎么保证消息不被重复消费

  1. kafka的消费者有两套API,分别是high level和low level。
  • high level:消费过的数据不发再次消费,必须把每次消费的位置提交到ZK或者KAFKA集群内部。
  • low level:一个消息可以多次读取,必须在程序中跟踪offset的值。

参考文章

https://www.jianshu.com/p/9dfead2ada17
https://www.jianshu.com/p/4bf007885116

你可能感兴趣的:(学习笔记,kafka,分布式)