Kafka学习笔记整理

本文详细介绍了Apache Kafka的核心概念,包括其作为消息系统、存储系统和流处理平台的角色,以及重要的概念如主题、分区、多副本等。文章探讨了Kafka的生产者和消费者原理,特别是消费者组、消息投递模式和位移提交。此外,还讲解了副本的高水位和低水位以及日志存储的细节,如日志清理和压缩策略。通过对Kafka内部机制的深入理解,读者能够更好地掌握Kafka在实际应用中的工作原理。
摘要由CSDN通过智能技术生成

主要内容摘要

  • 生产者
  • 消费者
  • 再均衡操作
  • 副本和日志存储
  • 延迟操作
  • 控制器
  • 学习目标:

掌握下面这些概念

1、给一份学习使用的docker-compose搭建环境,供学习使用。
2、了解Kafka的一些核心概念
3、熟悉客户端组件及常用的使用方式及原理
4、协调者处理消费者再均衡
5、副本与日志存储
5、控制器

Kafka docker-compose

version: '2'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"
    volumes:
      - "./zookeeper/data:/data"
      - "./zookeeper/datalog:/datalog"

  kafka:
    image: wurstmeister/kafka
    ports:
      - "9092"             # kafka 把9092端口随机映射到主机的端口
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 10.2.46.144           #本机ip
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_CREATE_TOPICS: test:1:1
      KAFKA_DELETE_TOPIC_ENABLE: "true"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./kafka/logs:/kafka
  kafka-manager:
    image: sheepkiller/kafka-manager
    links:
      - zookeeper
    environment:
      ZK_HOSTS: zookeeper:2181
      APPLICATION_SECRET: letmein
      KM_ARGS: -Djava.net.preferIPv4Stack=true
    ports:
      - "9000:9000"

kafka的角色

消息系统:

作为消息中间件都具备系统解耦、冗余存储、流量削峰、缓冲、异步通信、扩展性、可恢复性等功能。同时具有消息顺序性和回溯消费的功能。

存储系统

可以把消息持久化到磁盘,并且降低消息丢失的风险,需要设置数据保留策略为“永久”,或启用主题的日志压缩功能。

流式处理平台

有一个完整的流式处理的类库

重要的概念

主题

Kafka中的消息是以主题为单位归类的,逻辑上生产者往主题推送消息,消费者从主题拉取消息。在物理的存储上,消息是存在具体的分区的。

分区

一个主题可以分为多个分区,一个分区只能属于一个主题。同一个主题的不同分区存储的消息是不同的,分区在存储层可以看做是一个可追加的日志文件,消息在被加入到分区的时候会分配一个特定的偏移量(offset)。
offset是消息在分区的唯一标识,Kafka通过它来保证消息在分区内的顺序性,不过offset并不跨越分区,也就是说,Kafka并不保证主题有序,只能保证分区有序。

  1. 那如何保证分区内的消息是有序的呢?

设置多个分区

如果主题只有一个分区,也就只有一个文件,那这台机器的I/O将会成为这个主题的性能瓶颈,Kafka的分区可以分布在不同的服务器上,设置多个分区可以进行水平的扩展,从而解决这个问题。分区的数量可以在创建主题的时候指定,也可以在后期动态的修改。

  1. 如何动态的修改某个主题的分区数量呢?

分区多副本

分区存储消息,那如果分区所在的服务器崩了,那消息不就都不能使用了吗?因此Kafka引入了多副本的概念,我们可以为某个分区设置多个副本来提升容灾能力。副本之间是“一主多从”的关系,leader副本负责处理读写请求,follower副本只负责与leader同步。当leader副本出现故障时,从follower副本中重新选举一个处理作为leader副本,从而实现了故障转移。

AR相关概念

消息会先发送到leader副本,之后follower副本会从leader副本拉取消息进行同步,同步会有快慢问题。分区所有的副本统称为AR(Assigned Replicas),所有与leader副本保持一定程度同步的副本(包括leader副本)称为ISR(In-Sync Replica)。这里的“一定程度”就是滞后的范围,可以通过参数配置。与leader副本同步滞后过多的副本称为OSR(Out-of-Sync Replicas),故AR = ISR + OSR。
leader副本维护和跟踪ISR集合中所有follower副本的滞后状态,当滞后太多会被剔除,当“追上”后再加入到ISR中。

LEO & HW

HW(High Watermark):标识一个特定的消息偏移量offset,消费者只能消费到这个offset之前的消息。

在这里插入图片描述
​ 图 1-1 分区中各种偏移量的说明
图1-1代表一个日志文件,文件中有9条消息,第一条消息的offset为0,最后一条消息的offset为8;该日志文件的HW为6.

LEO(Log End Offset):标识当前日志文件中下一条待写入消息的offset,如上图中的消息9的位置。
ISR集合中的每个副本都会维护自身的LEO,而集合中最小的LEO即为分区的HW。

  1. 分区的HW是什么?

由此可见,Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。使用这种ISR的方式有效的权衡了数据可靠性和性能之间的关系。

生产者

生产者相对比较简单
目标:保证消息已经发到服务端并且不丢失(acks)

一般配置例子

spring:
kafka:
bootstrap-servers: xx:9092,xx:9092,xx:9092
producer:
acks: all
retries: 3
batch-size: 50
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer

 producer.send(record, new Callback() {
   @Override
    public void onCompletion(RecordMetadata metadata, Exception exception) {
        if (exception == null) {
            //deal?
            System.out.println(metadata.partition() + ":" + metadata.offset());
       }else{
            exception.printStackTrace();
        }
    }
});

分区器

指定消息发送到各个分区。
如果指定了key,会对可以进行HASH算法,来得到分区号;如果不指定key,会以轮询的方式发送到各个可用的分区。

生产者内部原理

在这里插入图片描述
在这里插入图片描述

消费者

消费者组

Kafka中存在一个消费者组的概念,每个消费者都属于一个消费者组。当消息发布到主题之后,只会被订阅它的消费者组中的其中一个消费者消费。每个分区只能被一个消费者组中的一个消费者所消费。

这里就有一个分配策略的概念:
对一个消费组而言, 一个分区被一个消费者所消费,如果订阅主题有6个分区,一个消费者消费6个分区,两个消费者各消费3个分区,三个消费者个消费两个分区;这样消费者具有横向伸性,可以通过增加或减少消费者数量来提升或降低整体的消费能力。(默认使用的是RangeAssignor分配策略)

1、其他的分配策略?

消息的两种投递模式

  • 点对点模式:如果所有消费者都隶属于一个消费者组,那么所有的消息都会被均衡地投递给每一消费者,每条消息都只会被一个消费者消费。
  • 发布/订阅模式: 如果每个消费者都属于不同的消费者组,那么所有的消息都会被投递给所有的消费者,每条消息会被所有的消费者消费。

消费者客户端

具体步骤:

1. 配置消费者客户端;

bootstrap.servers: 格式:host:port,默认为"",不必配置全; group.id: 默认值为"",不配置会报错;client.id: 会生成"consumer-"与数字的拼接。

2. 订阅主题;

订阅主题,如果前后订阅了不同的主题,那么以最后一次的为准;
还有一个带正则参数的方法;
第二个参数是再均衡监听器;
还可以直接订阅某些主题的特定分区,通过assign()方法来实现。
可以通过partitionsFor来查询指定主题的元数据信息

List<PartitionInfo> partitionsFor(String topic)

例子:通过assign方法来获取各个分区的position、committed offset、lastConsumedOffset


    Properties props = initConfig();
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
    
    List<PartitionInfo> partitionInfos = consumer.partitionsFor(topic);
    
    partitionInfos.stream().forEach(partitionInfo -> {
   
        int partition = partitionInfo.partition();
        TopicPartition tp = new TopicPartition(topic, partition);
    
        consumer.assign(Arrays.asList(tp));
        long lastConsumedOffset = -1;
        while (true) {
   
            ConsumerRecords<String, String> records = consumer.poll(1000);
            if (records.isEmpty()) {
   
                break;
            }
            List<ConsumerRecord<String, String>> partitionRecords
                    = records.records(tp);
            lastConsumedOffset = partitionRecords
                 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值