flume+kafka篇

本文深入探讨了Kafka的理解,包括其分布式、日志系统特性,以及与Spark Streaming、Hive的整合。同时,介绍了Flume如何确保数据可靠性,Kafka的数据管理和消费机制,以及如何保证消息有序和避免数据丢失。Kafka的高吞吐量实现、分区策略和消费者分配策略也被详细阐述。最后,提到了Kafka与传统消息传递的区别及其在解决数据积压和写入性能优化方面的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题1、谈谈对kafka的理解

  • kafka是最初由linkedin公司开发的,使用scala语言编写,kafka是一个分布式,分区的,多副本的,多订阅者的日志系统(分布式MQ系统),可以用于搜索日志,监控日志,访问日志等。

  • apache kafka是一个分布式发布-订阅消息系统和一个强大的队列,可以处理大量的数据,并使能够将消息从一个端点传递到另一个端点,kafka适合离线和在线消息消费。kafka消息保留在磁盘上,并在集群内复制以防止数据丢失。kafka构建在zookeeper同步服务之上。它与apache和spark非常好的集成,应用于实时流式数据分析。

  • Broker:kafka集群中包含一个或者多个服务实例,这种服务实例被称为Broker

  • Topic:每条发布到kafka集群的消息都有一个类别,这个类别就叫做Topic

    • kafka将消息以topic为单位进行归类
      topic特指kafka处理的消息源(feeds of messages)的不同分类。
      topic是一种分类或者发布的一些列记录的名义上的名字。kafka主题始终是支持多用户订阅的;也就是说,一 个主题可以有零个,一个或者多个消费者订阅写入的数据。
      在kafka集群中,可以有无数的主题。
      生产者和消费者消费数据一般以主题为单位。更细粒度可以到分区级别。
  • Partition:Partition是一个物理上的概念,每个Topic包含一个或者多个Partition

  • Producer:负责发布消息到kafka的Broker中。

  • Consumer:消息消费者,向kafka的broker中读取消息的客户端

  • Consumer Group:每一个Consumer属于一个特定的Consumer Group(可以为每个Consumer指定 groupName)
    : 消费组: 由一个或者多个消费者组成,同一个组中的消费者对于同一条消息只消费一次。

问题2、Kafka和sparkStreaming的整合,手动提交的offset调用了什么方法?

问题3、hive怎么消费kafka的数据的

问题4、kafka如何管理自身的offset

  • offset有两种存放地点,一种是存入一个topic中,该topic被分成50个分区。还有一种是存入zookeeper中,这种方式在javaApi中已经实现了

问题5、flume 如何保证数据的可靠性?

  • Channel提供两种:memory Channel、file Channel。file Channel能把event持久化到磁盘,避免数据丢失
  • Flume 使用事务的办法来保证 event 的可靠传递。Source 和 Sink 分别被封装在事务中,这些事务由保存 event 的存储提供或者由 Channel 提供。这就保证了 event 在数据流的点对点传输中是可靠的。

问题6、kafka如何保证数据不会出现丢失或者重复消费的情况?

  • 保证数据不丢失可以从三方面考虑
    • 生产者数据不丢失:
      • kafka的ack机制可以保证数据发送不丢失,它有三个值 0 1 -1
        • 0:生产者只负责发送数据,不关心数据是否丢失,响应的状态码为0
        • 1:partition的leader收到数据,响应的状态码为1
        • -1:所有的从节点都收到数据,响应的状态码为-1
      • 从数据发送方面考虑的话。有异步和同步发送的方式
        • 在同步的情况下:发送一批数据给kafka后,等待kafka返回结果(默认方式)
          • 生产者等待10s,如果broker没有给出ack相应,就认为失败。生产者重试3次,如果还没有相应,就报错
        • 异步:发送一批数据给kafka,只是提供一个回调函数。(在消息不是很重要的话,用异步)
          • 先将数据保存在生产者端的buffer中。buffer大小是2万条
          • 满足数据阈值或者数量阈值其中的一个条件就可以发送数据。
          • 发送一批数据的大小是500条
      • broker保证数据不丢失
        • 主要是通过副本因子(冗余),防止数据丢失
      • 消费者消费数据不丢失
        • 只要每个消费者记录好offset值即可,就能保证数据不丢失。
  • 保证不出现重复消费的话,要从消费者提交offset考虑(重复消费:consumer有些消息处理了,但是没来得及提交offset。等重启之后,少数消息就会再次消费一次。)
    • 那么我们就需要从幂等性角度考虑了。幂等性,我通俗点说,就一个数据,或者一个请求,无论来多次,对应的数据都不会改变的,不能出错。
    • 比如某个数据要写库,你先根据主键查一下,如果数据有了,就别插入了,update一下好吧
    • 比如你是写redis,那没问题了,反正每次都是set,天然幂等性
    • 对于消息,我们可以建个表(专门存储消息消费记录)
      • 生产者,发送消息前判断库中是否有记录(有记录说明已发送),没有记录,先入库,状态为待消费,然后发送消息并把主键id带上。
      • 消费者,接收消息,通过主键ID查询记录表,判断消息状态是否已消费。若没消费过,则处理消息,处理完后,更新消息记录的状态为已消费。

问题7、kafka消费数据是怎么消费的,用的是什么方式?

  • 自动提交offset(At-most-once(最多一次))
    • 客户端收到消息后,在处理消息前自动提交,这样kafka就认为consumer已经消费过了,偏移量增加。
//设置enable.auto.commit为true
props.put("enable.auto.commit", "true"); 
  • 手动提交offset(At-least-once(最少一次))
    • 可能出现消息处理完了,在提交offset前,网络中断或者程序挂了,那么kafka认为这个消息还没有被consumer消费,产生重复消息推送。
    //关闭自动提交确认选项
    props.put("enable.auto.commit",  "false");
    //手动提交offset值
    kafkaConsumer.commitASync();
    
  • Exactly-once(正好一次)
    • 保证消息处理和提交反馈在同一个事务中,即有原子性。例如在同一个事务中,把消息处理的结果存到mysql数据库同时更新此时的消息的偏移。
    • 考虑避免重复消费的解答
    //设置enable.auto.commit为false
    //保存ConsumerRecord中的offset到数据库
    //当partition分区发生变化的时候需要rebalance,有以下几个事件会触发分区变化
    //consumer通过调用seek(TopicPartition, long)方法,移动到指定的分区的偏移位置。
    

Kafka消费数据的方式主要包含如下几种:

1、指定多主题消费

consumer.subscribe(Arrays.asList(“t4”,“t5”));

2、指定分区消费

consumer.assign(list);

3、手动修改偏移量

consumer.commitSync();                //提交当前消费偏移量

consumer.commitSync(Map)    //提交指定偏移量

consumer.assign(Arrays.asList(tp));

4、seek,修改偏移量搜索指针,顺序读取数据

consumer.assign(Arrays.asList(tp));

    consumer.seek(tp,0);
import org.apache.kafka.clients.consumer.ConsumerRecord;

import org.apache.kafka.clients.consumer.ConsumerRecords;

import org.apache.kafka.clients.consumer.KafkaConsumer;

import org.apache.kafka.clients.consumer.OffsetAndMetadata;

import org.apache.kafka.common.TopicPartition;

 

import java.util.*;

 

public class NewConsumer {

    public static void main(String[] args) {

        Properties props = new Properties();

        props.put("bootstrap.servers","s102:9092,s103:9092,s104:9092");

        props.put("group.id", "g3");

        props.put("enable.auto.commit", "false");

        props.put("auto.commit.interval.ms", "100");

        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        KafkaConsumer consumer = new KafkaConsumer(props);

        //通过subscribe方法,指定多主题消费

        //consumer.subscribe(Arrays.asList("t4","t5"));

        //指定分区消费

//        ArrayList list = new ArrayList();

//        TopicPartition tp = new TopicPartition("t1", 0);

//        TopicPartition tp2 = new TopicPartition("t4", 0);

//        TopicPartition tp3 = new TopicPartition("t4", 1);

//        TopicPartition tp4 = new TopicPartition("t4", 2);

//        list.add(tp);

//        list.add(tp2);

//        list.add(tp3);

//        list.add(tp4);

//        consumer.assign(list);

        Map offset = new HashMap();

        //指定分区

        TopicPartition tp = new TopicPartition("t4", 0);

        //指定偏移量

        OffsetAndMetadata metadata = new OffsetAndMetadata(3);

        offset.put(tp,metadata);

        //修改偏移量

        consumer.commitSync(offset);

        //订阅主题

        //consumer.subscribe(Arrays.asList("t4"));

        consumer.assign(Arrays.asList(tp));

        //指定分区

//        TopicPartition tp = new TopicPartition("t4", 0);

//        consumer.assign(Arrays.asList(tp));

//        //修改搜索指针

//        consumer.seek(tp,10);

        while (true) {

            ConsumerRecords records = consumer.poll(5000);

            for (ConsumerRecord record : records)

                System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());

                consumer.commitSync();

        }

    }

}

问题8、Kafka为什么要分区,生产数据的分区策略

  • 采用分区的原因:
    1)方便在集群中扩展,每个partition可以调整适应其所在机器,而topic可以由多个partition组成,因此整个集群可以存储任意大小的消息数据。
    2)以partition为单位读写,可以提高并发。
  • 查看Partition接口的默认实现类DefaultPartitioner,可获知分区规则
    1)指定了patition号,则直接使用(直接将数据发送到指定的分区);
    2)未指定patition好但指定key,通过对key的value取hashCode来确定分区
    3)patition和key都未指定,使用轮询选出一个patition
    另外,还可以通过自定义Partition类进行分区。

问题9、Kafka消费者的分区分配策略

  • 默认为range范围策略
    分区数量除以消费者数量得到n和余数m,前m个消费者分配到n+1个分区,剩下的消费者分配到n个分区
  • roundrobin轮询策略
    所有消费者构成一个消费者闭环,将分区逐个轮流分配给环上的消费者。

问题10、传统的消息传递方法与kafka的不同

  • 传统消息队列一般是发布-订阅模式,如activeMQ ,消息生产者将消息发布到activeMQ服务器,所有订阅该相关主题的消费者将收到通知(广播),这一过程有事务的支持,主要用于业务系统中,消息的吞吐量不是很大。
  • Kafka采取的是push-pull模式,即生产者将消息推送到kafka集群的topic,消费者主动地去topic中拉取数据。相对于传统的消息传递方法。

问题11、Kafka的ISR机制

  • kafka 使用多副本保证消息不丢失,不是完全同步或者完全异步,而是使用ISR机制
    • leader会维护一个与其基本保持同步的Replica列表,该列表称为ISR(in-sync Replica),每个Partition都会有一个ISR,而且是由leader动态维护
    • 如果一个follower比一个leader落后太多,或者超过一定时间(500ms)未发起数据复制请求,则leader将其从ISR中移除
    • 当ISR中所有Replica都向Leader发送ACK后,leader才commit,这时producer才能认为一个请求中的消息成功提交到kafka中。
    • 注:根据配置replica.lag.time.max.ms,多久没同步,就会从ISR列表中剔除。以前还有根据落后多少条消息就踢出ISR,在1.0版本后就去掉了,因为这个值很难取,在高峰的时候很容易出现节点不断的进出ISR列表。
      在Zookeeper的/brokers/ids节点上注册Watch。当broker宕机,从zk的/brokers/topics/[topic]/partitions/[partition]/state中,读取对应partition的ISR列表,选一个出来做leader。
      Kafka的信息复制确保了任何已发布的消息不会丢失,并且可以在机器错误、程序错误或更常见些的软件升级中使用。

问题12、如何保证Kafka的消息有序

  • 一般情况下,Kafka对于消息的重复、丢失及顺序没有严格要求,kafka保证了一个partition中的消息是有序的,但存在多个partition时,不保证全局有序。
  • 需要消息有序被消费,有两个可行方案:
    1】设置topic只使用一个分区,这样所有消息都存储在同一分区中,是全局有序的。缺陷是消息只能被消费者组中的一个消费者处理,降低了性能,不适用高并发的情况。
    2】在producer发送消息时,给需要有序的消息指定分区,将消息发给同一个分区进行存储,这样也可以保证消息有序。Producer发送消息指定分区,可以有两种方式
    1)直接给定分区号
    2)不给定分区号,指定key,kafka会根据key的hashcode来确定分区。

问题13、Kafka的高吞吐怎么实现的

1】顺序写磁盘
Kafka的消息不断追加到文件中,在磁盘上只做Sequence I/O,顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,比随机读写磁盘(Random I/O)性能高上千倍。
2】使用PageCache功能,并采用了sendFile技术
PageCache把尽可能多的空闲内存都当做磁盘缓存来使用,这样避免在JVM内部缓存数据,JVM的GC机制会频繁扫描Heap空间,带来不必要的开销。
SendFile直接在内核空间完成数据拷贝,跳过用户空间的I/O操作,建立磁盘空间和内核空间缓存的直接映射,即零拷贝系统调用,大大提高性能
3】更高效的存储格式。
一般的JMS需要沉重的消息头,以及维护各种索引结构的开销。Kafka使用简明的offset机制来标识消息的位置,存储数据更高效。
4】文件分区分段
Kafka的topic可以划分多个partition,每个partition的文件有分为多个段(segment),队列中的消息实际保存多个片段文件中,每次对消息的消费都是对一个小文件的操作,非常轻便,增加了并行处理能力。
5】批量发送(异步方式生成消息)
Kafka可以设置批量发送消息,先将消息缓存在内存,等达到指定的数据量或者一定时间间隔进行发送,减少服务端的网络IO。
6】数据压缩
Kafka还支持对消息集合进行压缩,减少传输的数据量,减轻对网络传输的压力。

问题14、Kafka的工作流程分析

  • 生产过程
    1、写入方式
    producer 采用推(push)模式将消息发布到 broker,每条消息都被追加(append)到分
    区(patition)中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 高吞吐量)。
    2、写入流程:
    1】producer从zookeeper的”/brokers/…/state”节点找到消息对应partition的leader,将消息发送给leader
    2】leader将消息写入本地log,
    3】followers从leader拉取(pull)消息,写入本地log后向leader发送ACK应答
    4】leader收到所有ISR中的Relication的ACK后,向producer发送ACK,写入完成。

  • 消息保存过程
    1、存储方式
    topic分为一个或多个partition,每个partition对应一个文件夹,存储该分区的所有.log消息文件和.index索引文件。
    2、存储策略
    无论消息是否被消费,kafka都会保留所有消息,有两种策略可以删除旧数据:
    1】基于时间:log.retention.hours = 168 (一周)
    2】基于大小:log.retention.bytes = 1073741824 (1G)
    Kafka 读取特定消息的时间复杂度为 O(1),即与文件大小无关, 所以删除过期文件与提高 Kafka 性能无关

  • 消费过程
    1、消费消息的方式
    1】高级API
    不需要去自行去管理offset,系统通过zookeeper自行管理;
    不需要管理分区,副本等情况,系统自动管理;
    消费者断线会自动根据上一次记录在zookeeper中的offset去接着获取数据;
    不能自行控制offset,不能细化控制如分区、副本、zk等
    2】低级API
    能够开发者自己控制offset,自行控制连接分区,对分区自定义进行负载均衡,
    对zookeeper的依赖性降低;相对复杂,需要自行控制offset,连接哪个分区,找到分区leader 等
    2、消费者组
    消费者是以consumer group消费者组的方式工作,由一个或者多个消费者组成一个组,共同消费一个topic。每个分区在同一时间只能由group中的一个消费者读取,但是多个group可以同时消费这个partition。
    在这种情况下,消费者可以通过水平扩展的方式同时读取大量的消息。另外,如果一个消费者失败了,那么其他的group成员会自动负载均衡读取之前失败的消费者读取的分区。
    3、消费方式
    consumer采用pull(拉)模式从broker中读取数据,consumer可自主控制消费消息的速率,同时consumer可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。

问题15、Kafka怎么解决数据积压

  • 一般来说,生产消息的速度比消费消息的速度快,造成数据积压。
    解决方案:
    1】增加partitioner数量,从而提高consumer并行消费的能力,注意单纯增加消费者个数,并不能解决问题,反而会有资源浪费或者重复消费的问题。
    2】 消费者每次poll的数据业务处理时间不能超过kafka的max.poll.interval.ms,该参数在kafka0.10.2.1中的默认值是300s,要综合业务处理时间和每次poll的数据数量。
    注:max.poll.records默认是2147483647 (0.10.0.1版本),也就是kafka里面有多少poll多少,如果消费者拿到的这些数据在制定时间内消费不完,就会手动提交失败,数据就会回滚到kafka中,会发生重复消费的情况。如此循环,数据就会越堆越多。

问题16、Kafka为什么写入性能很高

一、顺序读写
Kafka就是使用了磁盘顺序读写来提升的性能,基于磁盘的随机读写确实很慢,但磁盘的顺序读写性能却很高
二、Page Cache
为了优化读写性能,Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存,避免了JVM的GC
三、零拷贝
Kafka利用 linux 操作系统的 “零拷贝(zero-copy)” 机制在消费端做的优化
四、分区分段
Kafka的message是按topic分类存储的,topic中的数据又是按照一个一个的partition即分区存储到不同broker节点。每个partition对应了操作系统上的一个文件夹,partition实际上又是按照segment分段存储的。
总结
Kafka采用顺序读写、Page Cache、零拷贝以及分区分段等这些设计,再加上在索引方面做的优化,另外Kafka数据读写也是批量的而不是单条的,使得Kafka具有了高性能、高吞吐、低延时的特点。这样,Kafka提供大容量的磁盘存储也变成了一种优点

问题17、kafka申请topic命令

bin/kafka-topic.sh \
	--create //操作类型,如果是修改的话用alter
	--zookeeper node01:2181  //kafka依赖的zookeeper集群地址
	--replication-factor 2 //副本因子
	--partitions 1 //分区数量
	--topic test //topic名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值