zoukankan      html  css  js  c++  java
  • kafka入门

    一、是什么

      Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志、消息系统。擅长实时的处理大量数据以满足各种需求场景:基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等。

      kafka的设计目的:

    • 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间的访问性能;
    • 高吞吐率,即使在非常廉价的商用机器上也能做到单机支持每秒100K条消息的传输;
    • 支持Kafka Server间的消息分区,及分布式消费,同时保证每个partition内的消息顺序传输;
    • 同时支持离线数据处理和实时数据处理。

      kafka的特性:

    • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
    • 可扩展性:kafka集群支持热扩展
    • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
    • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)。此特性应该是依赖zk来实现。
    • 高并发:支持数千个客户端同时读写

      kafka相关概念名词:

    • Broker:消息中间件处理结点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
    • Topic:一类消息,Kafka集群能够同时负责多个topic的分发。
    • Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。
    • Segment:partition物理上由多个segment组成。
    • offset:每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中。partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息。
    • Producer:负责发布消息到Kafka broker。
    • Consumer:消息消费者,向Kafka broker读取消息的客户端。
    • Consumer Group:每个Consumer属于一个特定的Consumer Group。Consumer Group是显式分布式,多个Consumer构成组结构,每条消息只能被某个Group中的某一个Consumer消费。

    二、有什么用

      kafka主要用于以下场景:

    • 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
    • 消息系统:解耦和生产者和消费者、缓存消息等。目前我们公司主要用kafka做消息队列中间件。
    • 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
    • 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。此场景思路跟上一条类似。
    • 流式处理:比如spark streaming和storm
    • 事件源
    • 数据存储

    三、怎么用

      3.1、设计原理

      消息模型可以分为两种:队列和发布-订阅式。队列的处理方式是一组消费者从服务器读取消息,一条消息只有其中的一个消费者来处理。在发布-订阅模型中,消息被广播给所有的消费者,接收到消息的消费者都可以处理此消息。Kafka为这两种模型提供了单一的消费者抽象模型: 消费者组(consumer group)。消费者用一个消费者组名标记自己。

           一个发布在Topic上消息被分发给此消费者组中的一个消费者。假如所有的消费者都在一个组中,那么这就变成了queue模型。假如所有的消费者都在不同的组中,那么就完全变成了发布-订阅模型。更通用的, 我们可以创建一些消费者组作为逻辑上的订阅者。每个组包含数目不等的消费者,一个组内多个消费者可以用来扩展性能和容错。       

           并且,kafka能够保证生产者发送到一个特定的Topic的分区上,消息将会按照它们发送的顺序依次加入,也就是说,如果一个消息M1和M2使用相同的producer发送,M1先发送,那么M1将比M2的offset低,并且优先的出现在日志中。消费者收到的消息也是此顺序。如果一个Topic配置了复制因子(replication facto)为N,那么可以允许N-1服务器宕机而不丢失任何已经提交(committed)的消息。此特性说明kafka有比传统的消息系统更强的顺序保证。但是,相同的消费者组中不能有比分区更多的消费者,否则多出的消费者一直处于空等待,不会收到消息。

      落实到实际,一个kafka集群中包含若干producer,若干broker,若干consumer,以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,选举leader,以及在consumer group发生变化时进行rebalance。producer使用push模式将消息发布到broker,consumer使用pull模式从broker订阅并消费消息。

      3.2、消息投递的可靠性 

      kafka提供了三种投递模式:

      at most once:最多一次,这个和JMS中”非持久化”消息类似,发送一次,无论成败,将不会重发。消费者fetch消息,然后保存offset,然后处理消息;当client保存offset之后,但是在消息处理过程中出现了异常,导致部分消息未能继续处理。那么此后”未处理”的消息将不能被fetch到,这就是”at most once”。

      at least once:消息至少发送一次,如果消息未能接受成功,可能会重发,直到接收成功。消费者fetch消息,然后处理消息,然后保存offset。如果消息处理成功之后,但是在保存offset阶段zookeeper异常导致保存操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是”at least once”,原因offset没有及时的提交给zookeeper,zookeeper恢复正常还是之前offset状态。

      exactly once:消息只会发送一次。kafka中并没有严格的去实现(基于2阶段提交),我们认为这种策略在kafka中是没有必要的。

      kafka提供的是“At least once”模型,因为消息的读取进度由offset提供,offset可以由消费者自己维护也可以维护在zookeeper里,但是当消息消费后consumer挂掉,offset没有即时写回,就有可能发生重复读的情况,这种情况同样可以通过调整commit offset周期、阈值缓解,甚至消费者自己把消费和commit offset做成一个事务解决,但是如果你的应用不在乎重复消费,那就干脆不要解决,以换取最大的性能。

      有许多系统声称它们实现了exactly-once,但是它们其实忽略了生产者或消费者在生产和消费过程中有可能失败的情况。比如虽然一个Producer成功发送一个消息,但是消息在发送途中丢失,或者成功发送到broker,也被consumer成功取走,但是这个consumer在处理取过来的消息时失败了。
     
      3.3、消息持久化
      kafka使用文件存储消息(append only log),这就直接决定kafka在性能上严重依赖文件系统的本身特性.且无论任何OS下,对文件系统本身的优化是非常艰难的.文件缓存/直接内存映射等是常用的手段.因为kafka是对日志文件进行append操作,因此磁盘检索的开支是较小的;同时为了减少磁盘写入的次数,broker会将消息暂时buffer起来,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,这样减少了磁盘IO调用的次数.对于kafka而言,较高性能的磁盘,将会带来更加直接的性能提升。
     
      一个topic可以认为一个一类消息,每个topic将被分成多个partition,每个partition在存储层面是append log文件。
     
      在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。
     
      每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。但每个段segment file消息数量不一定相等,这种特性方便old segment file快速被删除。

      segment file组成:由2大部分组成,分别为index file和data file,此2个文件一一对应,成对出现,后缀”.index”和“.log”分别表示为segment索引文件、数据文件。

       3.4、副本策略

      kafka中,replication策略是基于partition,而不是topic;kafka将每个partition数据复制到多个server上,任何一个partition有一个leader和多个follower(可以没有);备份的个数可以通过broker配置文件来设定。leader处理所有的read-write请求,follower需要和leader保持同步.Follower就像一个"consumer",消费消息并保存在本地日志中;leader负责跟踪所有的follower状态,如果follower"落后"太多或者失效,leader将会把它从replicas同步列表中删除.当所有的follower都将一条消息保存成功,此消息才被认为是"committed",那么此时consumer才能消费它,这种同步策略,就要求follower和leader之间必须具有良好的网络环境.即使只有一个replicas实例存活,仍然可以保证消息的正常发送和接收,只要zookeeper集群存活即可。

      选择follower时需要兼顾一个问题,就是新leader server上所已经承载的partition leader的个数,如果一个server上有过多的partition leader,意味着此server将承受着更多的IO压力.在选举新leader,需要考虑到"负载均衡",partition leader较少的broker将会更有可能成为新的leader。
      
      为了更好的做负载均衡,Kafka尽量将所有的Partition均匀分配到整个集群上。
     
      Producer在发布消息到某个Partition时,先通过ZooKeeper找到该Partition的Leader,然后无论该Topic的Replication Factor为多少,Producer只将该消息发送到该Partition的Leader。Leader会将该消息写入其本地Log。每个Follower都从Leader pull数据。这种方式上,Follower存储的数据顺序与Leader保持一致。Follower在收到该消息并写入其Log后,向Leader发送ACK。一旦Leader收到了ISR中的所有Replica的ACK,该消息就被认为已经commit了,Leader将增加HW并且向Producer发送ACK。

      为了提高性能,每个Follower在接收到数据后就立马向Leader发送ACK,而非等到数据写入Log中。因此,对于已经commit的消息,Kafka只能保证它被存于多个Replica的内存中,而不能保证它们被持久化到磁盘中,也就不能完全保证异常发生后该条消息一定能被Consumer消费。  

      Leader选举本质上是一个分布式锁,有两种方式实现基于ZooKeeper的分布式锁:节点名称唯一性:多个客户端创建一个节点,只有成功创建节点的客户端才能获得锁;临时顺序节点:所有客户端在某个目录下创建自己的临时顺序节点,只有序号最小的才获得锁。

      Majority Vote的选举策略和ZooKeeper中的Zab选举是类似的,实际上ZooKeeper内部本身就实现了少数服从多数的选举策略。kafka中对于Partition的leader副本的选举采用了第一种方法:为Partition分配副本,指定一个ZNode临时节点,第一个成功创建节点的副本就是Leader节点,其他副本会在这个ZNode节点上注册Watcher监听器,一旦Leader宕机,对应的临时节点就会被自动删除,这时注册在该节点上的所有Follower都会收到监听器事件,它们都会尝试创建该节点,只有创建成功的那个follower才会成为Leader(ZooKeeper保证对于一个节点只有一个客户端能创建成功),其他follower继续重新注册监听事件。

      3.5、数据读写

      生产者(producer)是负责向Kafka提交数据的,Kafka会把收到的消息都写入到硬盘中,它绝对不会丢失数据。为了优化写入速度Kafak采用了两个技术,顺序写入和MMFile。

      顺序读写:因为硬盘是机械结构,每次读写都会寻址,写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最“讨厌”随机I/O,最喜欢顺序I/O。为了提高读写硬盘的速度,Kafka就是使用顺序I/O。每条消息都被append到该Partition中,属于顺序写磁盘,因此效率非常高。但即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分页存储来利用内存提高I/O效率。

      通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存)。使用这种方式可以获取很大的I/O提升,省去了用户空间到内核空间复制的开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)

      消费端读取数据时,利用Zero Copy技术直接从内核空间(DMA的)到内核空间(Socket的),然后发送网卡。实际上,Kafka把所有的消息都存放在一个一个的文件中,当消费者需要数据的时候Kafka直接把“文件”发送给消费者。当不需要把整个文件发出去的时候,Kafka通过调用Zero Copy的sendfile这个函数

    四、深入研究方向。

      4.1、kafka怎么用在流式处理和事件源场景中

      流式处理这个场景可能比较多,也很好理解。保存收集流数据,以提供之后对接的Storm或其他流式计算框架进行处理。很多用户会将那些从原始topic来的数据进行阶段性处理,汇总,扩充或者以其他的方式转换到新的topic下再继续后面的处理。例如一个文章推荐的处理流程,可能是先从RSS数据源中抓取文章的内容,然后将其丢入一个叫做“文章”的topic中;后续操作可能是需要对这个内容进行清理,比如回复正常数据或者删除重复数据,最后再将内容匹配的结果返还给用户。这就在一个独立的topic之外,产生了一系列的实时数据处理的流程。Strom和Samza是非常著名的实现这种类型数据转换的框架。

      事件源是一种应用程序设计的方式,该方式的状态转移被记录为按时间顺序排序的记录序列。Kafka可以存储大量的日志数据,这使得它成为一个对这种方式的应用来说绝佳的后台。比如动态汇总(News feed)。

      4.2、目前用到了零拷贝的框架(kafka,netty)

      4.3、重复消费问题的出现场景及解决办法

    五、面试点

      5.1、同时消息中间件,kafka相较ActiveMQ、RabbitMQ有何优劣势

  • 相关阅读:
    Markdown引用图片,且不使用网上链接的解决方法
    测试
    sudo用户权限添加问题
    windows安装ipython
    ansible基本操作
    mysql用户权限操作
    解决windows7系统的快捷方式无法添加到任务栏
    linux下查看磁盘分区的文件系统格式
    mail客户端POP和IMAP协议
    linux设置history历史记录
  • 原文地址:https://www.cnblogs.com/qhj348770376/p/9180911.html
Copyright © 2011-2022 走看看