初学Kafka

简介

Kafka是最初由Linkedin公司开发,是使用Scala语言编写的一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,后捐献给Apache基金会。

Apache Kafka 是由Scala与Java开发的一个分布式的发布-订阅消息系统,因其将消息持久化到磁盘中,并对消息创建了备份保证数据的安全。

目前kafka定位为一个分布式流式处理平台,它以高吞吐、可持久化、可水平扩展、支持流处理等多种特性而被广泛应用于海量数据传递、离线和实时的消息处理业务系统中。

特性

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

使用场景

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

技术优势

  • 开源、免费
  • 可伸缩性:Kafka集群在运行期间就可以扩展或者收缩
  • 可靠性:分区容错方式 Kafka通过复制日志到多台服务器以进行容错,集群可以在不中断服务的情况下从故障中恢复。
  • 高吞吐量:Kafka可以高速消息处理,高并发百万级别,支持实时流数据处理。

基本概念

kafka为什么那么快 kafka难不难_kafka

  • producer:负责往kafka中生产数据,具体生产到哪一个partition中去,是由partition自己决定的
  • consumer:负责消费消息,每个consumer具有自己的消费者组,组与组之间可以消费同一个topic下的数据,但是同一个组内的不同consumer不能消费同一个topic下的数据。
  • broker:组成kafka集群的节点,broker之间没有主从关系,broker之间由zookeeper来协调。broker负责消费的读写,存储,每个broker可以管理多个partition
  • topic:一类消息的总称,topic由partition组成,有多少个,创建的时候可以指定。
  • partition:实际存储数据的地方,每个partition有副本,有多少,创建的时候可以指定。partition是直接接触磁盘的,append追加消息,每个partition都有一个broker来管理,这个broker叫做这个partition的leader,其他的副本的brocker叫做follower,一个partition同时可以对一个组内的一个消费者提供消费。
  • offset:每条消息都有当前Partition下唯一的64字节的offset,它指明这条消息的起始位置。
  • zookeeper:协同数据,存储元数据,broker,partition,topic,consumer的offset等,充当注册中心。
  • replica:副本是对partition的备份,不会被消费者消费,同一partition中有且只有一个负责生产消费。
  • AR(Asigned Replicas):分区中所有的副本统称为AR
  • ISR(In-Sync Replicas):所有与leader保持同步的副本统称为ISR
  • OSR(Out-of-Sync-Replicas):与leader副本同步滞后过多的副本。
  • HW(High Watermark):高水位,标识了一个特定的offset,消费者只能取到这个offset之前的消息。

-LEO(Log End Offset):日志末端位移,记录该副本底层日志中下一条消息的位移值,如果LEO=10,那么表示该副本保存了10条消息,位移值范围是[0,9] 。

快速配置

安装部署Zookeeper

1、将下载好的zookeeper.tar.gz解压到常用安装目录下面即可

2、将conf目录下的zoo_sample.cfg文件,复制一份,重命名为zoo.cfg

3、修改zoo.cfg配置文件,将dataDir=/tmp/zookeeper修改成zookeeper安装目录所在的data文件夹(需要在安装目录下面新建一个空的data文件夹和log文件夹),再添加一条添加数据日志的配置。

  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
  • initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒
  • syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10 秒
  • dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

4、启动zookeeper,判定是否安装成功,双击运行bin目录下的zkServer.cmd文件即可

5、检查服务是否启动,可以通过 netstat -ano|findStr 2181 命令查看是否有你配置的 clientPort 端口号(默认2181)在监听服务,也可以通过双击执行zkCli.cmd来判定是否启动成功。

安装部署Kafka

1、进入Kafka配置目录,\kafka_2.11-1.0.0\config ,编辑文件“server.properties” 添加自己的日记目录:log.dirs=… 同时打开注释 listeners=PLAINTEXT://:9092。如果Zookeeper在某些其他的机器或集群上运行,可以将“zookeeper.connect:2181”修改为自定义IP与端口。在这里使用了同一个机器,所以没其他做修改。文件中的Kafka端口和broker.id也是可以配置的。默认设置不变。

2、在zookeeper的基础上,运行Kafka服务
进入Kafka安装目录,\kafka_2.11-1.0.0切换到命令行窗口,运行kafka。
.\bin\windows\kafka-server-start.bat .\config\server.properties

3、测试

A、创建主题

  1. 现在创建主题,命名为“test”,replication factor=1(因为只有1个Kafka服务器在运行)。如果集群中所运行的Kafka服务器不止1个,可以相应增加replication-factor,从而提高数据可用性和系统容错性。
  2. 在C:\Users\wcy\Downloads\kafka_2.11-1.0.0\bin\windows打开新的命令行。
  3. 输入下面的命令,回车:kafka-topics.bat --create --zookeeper localhost:2181–replication-factor 1 --partitions 1 --topic test

B. 创建Producer及Consumer来测试服务器。

1.在C:\Users\wcy\Downloads\kafka_2.11-1.0.0\bin\windows打开新的命令行。

2.输入以下命令,启动producer,可以输入消息:kafka-console-consumer.bat --topic test --bootstrap-server localhost:9092

3.在同样的位置C:\Users\wcy\Downloads\kafka_2.11-1.0.0\bin\windows再次打开新的命令行。

4.现在输入下列命令启动consumer,可以获取消息:kafka-console-consumer.bat --topic test --bootstrap-server localhost:9092

5.两个命令行窗口,producer可以输入任何消息,consumer可以获取消息。

spring-boot集成kafka

1、引入依赖

<dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>

2、添加配置

spring:
  kafka:
    bootstrap-servers: 127.0.0.1:2181
    producer:
      # 发生错误后,消息重发的次数。
      retries: 0
      #当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算。
      batch-size: 16384
      # 设置生产者内存缓冲区的大小。
      buffer-memory: 33554432
      # 键的序列化方式
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 值的序列化方式
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      # acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。
      # acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
      # acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
      acks: 1
    consumer:
      # 自动提交的时间间隔 在spring boot 2.X 版本中这里采用的是值的类型为Duration 需要符合特定的格式,如1S,1M,2H,5D
      auto-commit-interval: 1S
      # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
      # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
      # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录
      auto-offset-reset: earliest
      # 是否自动提交偏移量,默认值是true,为了避免出现重复数据和数据丢失,可以把它设置为false,然后手动提交偏移量
      enable-auto-commit: false
      # 键的反序列化方式
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # 值的反序列化方式
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    listener:
      # 在侦听器容器中运行的线程数。
      concurrency: 5
      #listner负责ack,每调用一次,就立即commit
      ack-mode: manual_immediate
      missing-topics-fatal: false

生产者

消息发送流程

kafka为什么那么快 kafka难不难_服务器_02


ProducerRecord生产者执行器设置topic参数,负责send发送消息,可以选择同步或者异步方式,因为需要通过网络传输,需要指定序列化器与分区器,通常使用默认设置,还可以使用拦截器拦截非法消息。

消费者

kafka为什么那么快 kafka难不难_kafka为什么那么快_03


kafka消费者是消费组的一部分,多个消费者组成一个消费组,消费组有自己的groupId,同一消费组的不同消费者会收到不同分区的消息,即一个partitions只会被同一groupId下一个consumer消费(为了保证消息的顺序)。

kafka一个重要特性就是只要一次写入,就可以支持多个应用读取全量的消息,即一个topic可以供多个groupId消费。

消费者必须配置和生产者对应的反序列化器。

位移提交

kafka中topic下的每个消息消费无需,但每个分区中消息为有序的,为保证有序性消费,所以需要在分区中标志消费到了哪个offset位置,但kafka的broker只管发消息,并不管消费者是否真正成功的消费了这条消息,而只是提供了一个API,让消费者自己通过提交(commit)操作来更新消费到哪个位置的消息,这在实际生产中就会导致消息丢失或者消息重复消费的问题。

消息丢失:如果消费者默认采用自动提交的方式,即消费者收到这个消息时就确认,但此时如果消费者宕机,无疑这条消息就被丢失了。

重复消费:消费者端如果采用处理完消息后手动提交的方式,在刚处理完消息还没来得及提交时,如果消费者挂了就会导致这条消息会被重复处理。

消费者提交方式

自动提交:kafka.auto.commit=true,默认也为true,消费者调用poll时,每5秒自动提交一次,应用不需要显式调用提交API。
同步提交:在消费者处理完消息后,手动提交offset。
异步提交:在消费者处理完消息后,采用异步回调的方式提交offset,避免同步提交时导致的系统阻塞。

再平衡

再平衡指的是在kafka consumer所订阅的topic发生变化时发生的一种分区重分配机制,她为消费组的高可用与可伸缩性提供了保障,使得消费组能方便的实现添加或删除消费者,在发生再平衡时消费者无法从kafka读取消息。一般有三种情况会触发再平衡:

  • consumer group中的新增或删除某个consumer,导致其所消费的分区需要分配到组内其他的consumer上;
  • consumer订阅的topic发生变化,比如订阅的topic采用的是正则表达式的形式,如test-*此时如果有一个新建了一个topic test-user,那么这个topic的所有分区也是会自动分配给当前的consumer的,此时就会发生再平衡;
  • consumer所订阅的topic发生了新增分区的行为,那么新增的分区就会分配给当前的consumer,此时就会触发再平衡。

存储

partition最为存储对象的直接映射,相当于一个巨型文件,一个partition又被平均分配到多个大小相等的数据段(segment)中,每个segment中包含的消息数目不一定相等。
每个segment文件由两部分组成,分别是.index索引文件和.log数据文件,分区全局第一个segment从0开始,之后segment为上一个segment的offset值。
kafka为了实现快速查找,采用分区(partition)+分段(logsegment)+稀疏索引的方式定位,稀疏索引部分采用二分查找算法。
Kafka在设计时采用文件追踪的方式写入消息,并且不允许修改以前的消息,除此以外Kafka大量使用页缓存以及零拷贝技术,所以即便是使用磁盘存储,Kafka也能实现高吞吐。
kafka的设计哲学:分区并行、ISR机制、顺序写、页缓存、高效序列化、零拷贝。每项技术都能展开讲很多。。。具体百度kafka为什么这么快?

稳定性

kafka的副本机制使提交到kafka的消息不会丢失,并且能保证高吞吐、高性能,但遇到网络故障时又怎么办呢?Kafka的消息传输保障机制非常直观,实现采用at-least-once机制,即如果生产者发送给Kafka消息后,因为网络故障的原因导致没有接受到ack,生产者会retry多次,确保消息已正确传输到服务器,但可能会导致消息重复发送的问题。

幂等性

幂等性,即对接口的多次调用所产生的结果与调用一次是一致的。生产者在重试的时候有可能产生重复写入消息,使用幂等性就可以避免由于这种情况而产生的错误,幂等性只保证Kafka在与一个消费者的一次回话中的一个分区内的幂等,即如果消费者意外重启或者跨多个分区是无法实现幂等的。

事物

幂等性不能跨多个分区操作,而事物正好可以弥补这一缺憾,事物可以保证对多个分区写入操作的原子性,所以要开启事物,必须先开启幂等性。

控制器

Kafka集群中会有多个broker,其中一个会被选为控制器(Kafka Controller),他负责管理整个集群中所有分区和副本的状态,当某个leader挂掉时,由控制器负责从follower中选取出新的leader副本;当分区ISR集合变化时、或者执行sh脚本时等多种情况都是由控制器进行分配。
Kafka控制器的选举算法依赖Zookeeper,选举成功后会在zookeeper中创建临时节点。

kafka高级应用

命令行工具

消费组管理:
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list #查询所有group
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group group.demo #查询名为group.demo的消费组详情
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group group.demo --state #查询名为group.demo的消费组状态
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group group.demo --members #查询名为group.demo的消费组成员信息
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --delete group.demo #删除名为group.demo的消费组

消费位移管理:
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group group.demo --all-topics --reset-offsets --to-earliest --execute #重置group.demo下所有主题的offset

数据管道connect

Kafka是一个使用越拉越广的消息系统,尤其在大数据开发、实时数据处理与分析中,解决与其他系统集成与应用解藕的问题。

相关概念

连接器:实现connect API,决定运行多少个任务,按照任务来进行数据复制,从worker进程获取任务配置并将其传递
task:负责将数据移入或者移出Kafka
work进程:相当于connector与task的容器,勇于负责管理连接器的配置,启动连接器和链接任务,提供Rest API。
转换器:Kafka connect与其他系统之间的数据格式转换。