kafka搭建和基础知识

10 篇文章 0 订阅

earliest
当各partition有消费者组已提交的offset时,从提交的offset开始消费;无提交的offset时,从起始开始消费 
latest
当各partition下有消费者组已提交的offset时,从提交的offset开始消费;无提交的offset时,消费最新的该partition下的数据

 

broker producer consumer
topic 多个partition(区) 存储层面是append log 文件,消息都会被直接追加到log 文件的尾部,每条消息在文件中的位置称为offset(偏移量)!!!  为了存在多个broker上,扩容
在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1!!!!!
partitions 需要备份的个数(replicas),每个partition 将会被备份到多台机器上,以提高可用性
索引机制来存储offset!!! index指向多个段segment  多叉树!!!  几乎不允许对消息进行“随机读写”。

消息被消费,消息仍然不会被立即删除。日志文件将会根据broker 中的配置要求,保留一定的时间之后删除;比如log 文件保留2 天,那么两天后,文件会被清除,无论其中的消息是否被消费
kafka集群几乎不需要维护任何consumer和producer 状态信息,这些信息由zookeeper.offset 将会保存在zookeeper 中!!!!

传统的消息传递有两种方式: 队列方式(queuing)、发布-订阅(publish-subscribe)方式.
队列方式:一组消费者从机器上读消息,每个消息只传递给这组消费者中的一个。
分布-订阅方式:消息被广播到所有的消费者。Kafka提供了一个消费组(consumer group)的说法来概括这两种方式
kafka 中,一个partition 中的消息只会被group 中的一个consumer 消费!!!!每个group 中consumer 消息消费互相独立,不过一个consumer 可以消费多个partitions 中的消息!!
消费者的数量不能超过分区数 如果你想要消息是全局有序的,你可以设置主题只有一个分区,同时这意味着只能有一个消费者

Producer根据指定的partition方法(round-robin轮询、key-hash等)用户可以自己指定,消息发布到指定topic的partition里面,Consumer从kafka集群pull数据,并控制获取消息的offset
消费者的迭代器不会停止。如果当前没有消息,迭代器将阻塞直至有新的消息发布到该话题!!!  应该是有详细就会唤醒线程

当发布的消息数量达到设定值或者经过一定的时间后!!!,段文件真正写入磁盘中。写入完成后,消息公开给消费者。!!!!
broker会将消息暂时buffer起来,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,这样减少了磁盘IO调用的次数. log.retention.hours
broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新。

吞吐量:数据磁盘持久化:消息不在内存中cache,直接写入到磁盘,充分利用磁盘的顺序读写性能,数据批量发送
负载均衡:roducer根据用户指定算法,将消息发送到指定的partition,每个partition有自己的replica,每个replica分布在不同的Broker节点上。一般不会在一个机器上,就是为了高可用
拉取系统:会持久化数据,broker没有内存压力,根据消费能力自主控制消息拉取速度!!!,根据自身情况自主选择消费模式,例如批量,重复消费,从尾端开始消费等
可扩展性:当需要增加broker结点时,新增的broker会向zookeeper注册

应用场景:消息队列 行为跟踪(产生消息消费者实时处理,或实时监控) 流处理

ACK一致性级别 如何保证发出的消息不丢失!!!!  producer properties props.put("acks", "1")!!!
生产者ack=0(不需要ACK,至多一次), ack=all(leader和所有follows都写入成功,默认), ack=1(leader成功即可)。
消费者层面,kafka支持至多一次和至少一次两种模式  props.put("enable.auto.commit", "false");  consumer.commitSync(); 

offset下标自动提交其实在很多场景都不适用,因为自动提交是在kafka拉取到数据之后就直接提交 将提交方式改成false之后
需要手动提交只需加上这段代码

优化 发送方面,使用批量发送代替实时发送。 vm方面,默认kafka用的是cms gc,可以考虑g1垃圾回收期

消费慢:
kafka消息增量一般都堆积比较严重,消息数变化曲
消费者消费能力不行导致!!  多线程消费  批量消费
max.poll.interval.ms=300!!! 默认 业务时间不能超过这个  max.poll.records = 50  拉去条数减少    默认值为500!!!  之前业务太长,需要分析,直接拉取入库,后续后台分析

如果处理时间太久,超过了kafka的认定时间,kafka就会认为这个消费者挂了,从而踢掉重新分配一个消费者。处理方式可以是:1,一次不拉过多的数据。2,kafka认定消费者挂了的时间设置久点。!!!!!!!!!!!!!!!

 

#broker的全局唯一编号,不能重复
broker.id=01
#broker需要使用zookeeper保存meta数据
zookeeper.connect=master:2181,slave1:2181,slave2:2181
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#partion buffer中,消息的条数达到阈值,将触发flush到磁盘
log.flush.interval.messages=10000
#消息buffer的时间,达到阈值,将触发flush到磁盘
log.flush.interval.ms=3000
#删除topic需要server.properties中设置delete.topic.enable=true否则只是标记删除
delete.topic.enable=true


replication不能多broker
./kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic test
./kafka-topics.sh --list --zookeeper localhost:2181

Kafka集群保证数据的不丢失
生产者生产数据保证数据不丢失
消费者消费数据保证数据的不丢失

同步发送模式  
producer.type=sync 
request.required.acks=1
异步发送模式  https://www.cnblogs.com/wangzhuxing/p/10099894.html !!!!!
producer.type=async 
request.required.acks=1 
queue.buffering.max.ms=5000 
queue.buffering.max.messages=10000 
queue.enqueue.timeout.ms = -1 
batch.num.messages=200


版本要一致客户端和kafka  消费者必须有groupId

找不到Host  配置hosts映射!!!

@KafkaListener(topics = {"test"},groupId = "test")
@Async
public void getTopic(ConsumerRecord<?, ?> record) 

@KafkaListener(topics = "teemo", id = "consumer", containerFactory = "batchFactory")
public void listen(List<ConsumerRecord<?, ?>> list) 

 

kafka学习
是一个分布式、支持分区的(partition)、多副本的(replica),多订阅者。基于zookeeper协调的分布式消息系统  文件存储机制设计很关键
高吞吐量、低延迟  kafka每秒可以处理几十万条消息   
可扩展性:kafka集群支持热扩展  
持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
高并发:支持数千个客户端同时读写

数据缓存和削峰值和异步通信和缓冲

使用场景:
日志收集 一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等
消息系统:解耦和生产者和消费者、缓存消息等。
流式处理:比如spark streaming和storm

Broker Leader的选举:Kakfa Broker集群受Zookeeper管理,只会有一个注册成功。失败了,watcher会选举其他的broker
bug:Zookeeper通信的timeout时间是6s,controller如果有6s中没有和Zookeeper做心跳,就会判断死掉了,重新选举  由于网络等原因慢  
概念意思
broker:服务器节点,存储topic的数据。如果某topic有N个partition,集群有N个broker,那么每个broker存储该topic的一个partition,一个broker可以存topic 零个,一个,多个partition
Topic: 每条发布到Kafka集群的消息都有一个类别,物理上不同Topic的消息分开存储到多个broker,逻辑上一个Topic一起。  类似于数据库的表名
Partition:topic中的数据分割为一个或多个partition,在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1!!!不同partition间的数据丢失了数据的顺序,用segment文件存储
            由于每台机器的磁盘大小是有限的,所以即使有再多的机器,可处理的消息还是被磁盘所限制,无法超越当前磁盘大小.因此有了partition的概念.
segment:分成了多个segment(段),然后通过一个index,索引,来标识第几段  segment文件保留的最长时间,默认保留7天(168小时)log.retention.hours   每个segment的大小,默认为1G
offset:偏移量,读到数据,根据二分发查找segment中的index索引来快速定位到位置
Producer:生产者发送的消息,存储到一个partition中    
Consumer:可以消费多个topic中的数据
Consumer Group:每个Consumer属于一个特定的Consumer Group
Leader:每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的partition
Follower:Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。如果Leader失效,则从Follower中选举出一个新的Leader
ISR:in sync replicas(复制)从复制品中删除。

kafka搭建  安装到/opt/kafka  https://blog.csdn.net/qq_37598011/article/details/88980317
基本操作和可视化: https://www.jianshu.com/p/2d83a67e2c79?nomobile=yes
首先安装java https://blog.csdn.net/qq_37598011/article/details/88980317
kafaka里面已经带了zookeeper
Zookeeper集群的工作是超过半数才能对外提供服务,3台中超过两台超过半数,允许1台挂掉 
安装zookeeper wget http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz /config/zookeeper.properties
#broker.id=0  每台服务器的broker.id都不能相同
安装Kafka wget http://mirror.bit.edu.cn/apache/kafka/2.0.0/kafka_2.11-2.0.0.tgz  /config/server.properties
启动 ./bin/*.sh config/*.properties    后台 nohup ./kafka-server-start.sh ../config/server.properties 1>/dev/null 2>/dev/null &
集群监控体量太大和数据监控kafka tool

#broker的全局唯一编号,不能重复
broker.id=01
#broker需要使用zookeeper保存meta数据
zookeeper.connect=master:2181,slave1:2181,slave2:2181
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#partion buffer中,消息的条数达到阈值,将触发flush到磁盘
log.flush.interval.messages=10000
#消息buffer的时间,达到阈值,将触发flush到磁盘
log.flush.interval.ms=3000
#删除topic需要server.properties中设置delete.topic.enable=true否则只是标记删除
delete.topic.enable=true

listeners=PLAINTEXT://{内网ip}:9092  标识很重要

版本匹配!!!1.0 和 0.9坑!!!
<dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
        <version>2.0.0.RELEASE</version>//与springboot版本不合适
</dependency>

 

配置 https://blog.csdn.net/fenglibing/article/details/82117166

https://www.cnblogs.com/yx88/p/11013338.html

spring:
  kafka:
    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
      bootstrap-servers: xxx:9092,xxx:9092
    consumer:
      bootstrap-servers: xxx:9092,xxx:9092
      group-id: test
      auto-offset-reset: earliest
      enable-auto-commit: true
      auto-commit-interval: 100
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

 

spring.kafka.producer.retries=0
spring.kafka.producer.batch-size= 16384
spring.kafka.producer.buffer-memory= 33554432
spring.kafka.producer.key-serializer= org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer= org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.bootstrap-servers= xx:9092
spring.kafka.producer.acks=1

spring.kafka.consumer.bootstrap-servers= xx:9092
spring.kafka.consumer.group-id= test1
spring.kafka.consumer.auto-offset-reset= earliestf
spring.kafka.consumer.enable-auto-commit= true
spring.kafka.consumer.auto-commit-interval= 100
spring.kafka.consumer.key-deserializer= org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer= org.apache.kafka.common.serialization.StringDeserializer

      
      
      
 @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    public void send(String message) {
        System.out.println("sendssssssssssssssssssssssssssss");
        kafkaTemplate.send("test", message);
    }

    @PostConstruct
    public void sendM(){
        send("heqiang1");
    }
    
    
@KafkaListener(topics = {"test"})
    @Async
    public void getTopic(ConsumerRecord<?, ?> record) {

        Optional<?> kafkaMessage = Optional.ofNullable(record.value());
        if (kafkaMessage.isPresent()) {
            Object message = kafkaMessage.get();
            System.out.println("----------------- record =" + record);
            System.out.println("------------------ message =" + message);
            System.out.printf("topic = %s, offset = %d, value = %s \n", record.topic(), record.offset(), record.value());
        }
    }

 

 private static Properties getProps(){
        Properties props =  new Properties();
        props.put("bootstrap.servers", "47.52.199.51:9092");
        props.put("acks", "all"); // 发送所有ISR
        props.put("retries", 2); // 重试次数
        props.put("batch.size", 16384); // 批量发送大小
        props.put("buffer.memory", 33554432); // 缓存大小,根据本机内存大小配置
        props.put("linger.ms", 1000); // 发送频率,满足任务一个条件发送
        props.put("client.id", "producer-syn-1"); // 发送端id,便于统计
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        return props;
    }
    
     KafkaProducer<String, String> producer = new KafkaProducer<>(getProps());
     
     
     
private static Properties getProps(){
        Properties props =  new Properties();
        props.put("bootstrap.servers", "47.52.199.52:9092");
        props.put("group.id", "test_3");
        props.put("session.timeout.ms", 30000);       // 如果其超时,将会可能触发rebalance并认为已经死去,重新选举Leader
        props.put("enable.auto.commit", "true");      // 开启自动提交
        props.put("auto.commit.interval.ms", "1000"); // 自动提交时间
        props.put("max.poll.records","1000"); // 每次批量拉取条数
        props.put("auto.offset.reset","earliest"); // 从最早的offset开始拉取,latest:从最近的offset开始消费
        props.put("client.id", "producer-syn-1"); // 发送端id,便于统计
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        return props;
    }
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps()));
     ConsumerRecords<String,String> records = consumer.poll(1000);!!!拉取条数
     
     // 当前批次offset 提交拉去到哪里了
     consumer.commitSync();

 

#如果该值大于零时,表示启用重试失败的发送次数
spring.kafka.producer.retries=2
spring.kafka.producer.batch-size= 16384
spring.kafka.producer.buffer-memory= 33554432
spring.kafka.producer.key-serializer= org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer= org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.bootstrap-servers= master:9092,slave1:9092,slave2:9092,slave3:9092
#procedure要求leader在考虑完成请求之前收到的确认数,用于控制发送记录在服务端的持久化,其值可以为如下:
#acks = 0 如果设置为零,则生产者将不会等待来自服务器的任何确认,该记录将立即添加到套接字缓冲区并视为已发送。在这种情况下,无法保证服务器已收到记录,并且重试配置将不会生效(因为客户端通常不会知道任何故障),为每条记录返回的偏移量始终设置为-1。
#acks = 1 这意味着leader会将记录写入其本地日志,但无需等待所有副本服务器的完全确认即可做出回应,在这种情况下,如果leader在确认记录后立即失败,但在将数据复制到所有的副本服务器之前,则记录将会丢失。
#acks = all 这意味着leader将等待完整的同步副本集以确认记录,这保证了只要至少一个同步副本服务器仍然存活,记录就不会丢失,这是最强有力的保证,这相当于acks = -1的设置。
#可以设置的值为:all, -1, 0, 1
spring.kafka.producer.acks=1

spring.kafka.consumer.bootstrap-servers= master:9092,slave1:9092,slave2:9092,slave3:9092
#spring.kafka.consumer.group-id= simpleGroup
#testearliest当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
#latest当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
#nonetopic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
#spring.kafka.consumer.auto-offset-reset= earliest
#如果'enable.auto.commit'为true,则消费者偏移自动提交给Kafka的频率(以毫秒为单位),默认值为5000。
spring.kafka.consumer.enable-auto-commit= true
spring.kafka.consumer.auto-commit-interval= 100
spring.kafka.consumer.max.poll.records=1000
#consumer在这段时间内没有发送心跳信息,则它会被认为挂掉了
#spring.kafka.consumer.properties.session.timeout.ms=10000
#超过指定时间间隔没有向服务端发送poll()请求,会认为该consumer锁死,就会将该consumer退出group,并进行再分配
#spring.kafka.consumer.properties.max.poll.interval.ms=300000
spring.kafka.consumer.key-deserializer= org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer= org.apache.kafka.common.serialization.StringDeserializer

 

 @PostConstruct
    public void init() throws InterruptedException {
        int i = 0;
        while (true){
            send("heqiang" + i);
            i++;
            Thread.sleep(10000);
        }
    }

    //异步
    public void send(String message){
        System.out.println(message);
        System.out.println(LocalDateTime.now().toString());
        try{
            kafkaTemplate.send("test", message);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @KafkaListener(topics = {"test"},groupId = "test")
    @Async
    public void getTopic(ConsumerRecord<?, ?> record) {
        Optional<?> kafkaMessage = Optional.ofNullable(record.value());
        if (kafkaMessage.isPresent()) {
            Object message = kafkaMessage.get();
            System.out.println("----------------- record =" + record);
            System.out.println("------------------ message =" + message);
            System.out.printf("topic = %s, offset = %d, value = %s \n", record.topic(), record.offset(), record.value());
        }
    }


//    @KafkaListener(topics = {"test"},groupId = "test1")
    @KafkaListener(id = "id0", topicPartitions = { @TopicPartition(topic = "test", partitions = { "0" }) })
    @Async
    public void getTopic1(List<ConsumerRecord<?, ?>> records) {
        for (ConsumerRecord<?, ?> record : records) {
            Optional<?> kafkaMessage = Optional.ofNullable(record.value());
            if (kafkaMessage.isPresent()) {
                Object message = kafkaMessage.get();
                System.out.println("----------------- record =" + record);
                System.out.println("------------------ message =" + message);
                System.out.printf("topic = %s, offset = %d, value = %s \n", record.topic(), record.offset(), record.value());
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值