Kafka内容总结

一、kafka的消费模式

Kafka的消费模式主要有两种:一种是一对一的消费,也即点对点的通信,即一个发送一个接收。第二种为一对多(发布/订阅模式)的消费,即一个消息发送到消息队列,消费者根据消息队列的订阅拉取信息消费。

发布/订阅模式:即利用Topic存储消息,消息生产者将消息发布到Topic中,同时有多个消费者订阅此topic,消费者可以从中消费消息,注意发布到Topic中的消息会被多个消费者消费,消费者消费数据之后,数据不会被清除,而是按照时间策略来删除,Kafka会默认保留一段时间,然后再删除。

二、kafka架构

一个Topic会产生多个分区Partition,分区中分为Leader和Follower,消息一般发送到Leader,Follower通过数据的同步与Leader保持同步,消费的话也是在Leader中发生消费,如果多个消费者,则分别消费Leader和各个Follower中的消息,当Leader发生故障的时候,某个Follower会成为主节点。

  • 一个topic分成多个partition
  • 每个partition内部消息强有序
  • 其中的每个消息都有一个offset
  • 一个partition只对应一个broker
  • 一个broker可以管多个partition
  • 消息不经过内存缓冲,直接写入文件

三、Kafka的使用场景

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

四、生产者分区策略

kafka消费规则:每个分区只能被同一个消费者组内的一个consumer来消费。所以该如何分配同一个消费者组内的消费者去消费哪些分区的数据呢?

kafka内部的默认的分区分配策略:Range 和 RoundRobin(轮询)。

Range Startegy(根据范围消费):Range startegy是对每个主题而言的 , 首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母进行排序。然后用partitions的总数除以消费者的总数来决定每个消费者线程消费几个分区。如果有余数,那么前面的几个消费者线程将会多消费一个分区。弊端:可能会导致前面的几个消费者线程会多消费一些分区,个别线程压力会比较大。

RoundRobin strategy(轮询的消费策略):

在使用RoundRobin Starategy的时候我们必须满足两个条件:

1、同一个consumer Group里面的所有消费者的num.streams必须相等;

2、每个消费者订阅的主题必须相同。

原理:将所有主题的分区组成TopicAndPartition列表,然后对TopicAndPartition列表按hashcode进行排序。

五、kafka的ack机制

当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:

ack=0:意味着producer不等待broker同步完成的确认,继续发送下一条(批)信息,提供了最低的延迟。但是最弱的持久性,当服务器发生故障时,就很可能发生数据丢失。例如leader已经死亡producer不知情,还会继续发送消息broker接收不到数据就会数据丢失。

ack=1:意味着producer要等待leader成功收到数据并得到确认,才发送下一条message。此选项提供了较好的持久性较低的延迟性。Partition的Leader死亡,follwer尚未复制,数据就会丢失。

ack=-1(或all):意味着producer得到follwer确认,才发送下一条数据持久性最好,延时性最差。

三种机制性能递减,可靠性递增。

Kafka丢不丢数据?

1、消息写入kafka的过程可能发送丢失,通过ack设置来确保数据可靠性。

2、消息持久化broker时也可能发生丢失,在未写入硬盘前,机器挂掉也可能丢失数据,这种情况就认命吧,或者让acks更严格,消息未确认写入成功时能够继续重试。

3、消费的时候也可能发生丢失,kafka是通过pull的方式,由消费端从broker上拉取消息,而拉取哪些消息由消费端自己控制(存在zk也是自己控制),这就导致如果消费失败,且消费端没有做好相应处理,offset+1后,这条消息也就丢失了,所以对不允许数据丢失的业务,可以通过代码管理offset。

5.1 副本数据同步策略

何时发送ack?

确保有follower与leader同步完成,leader再发送ack,这样才能保证leader挂掉之后,能在follower中选举新的leader。

多少个follower同步完成之后发送ack?(两种方案)
1、半数follower同步完成即发送ack,延迟低

2、全部follower同步完成完成发送ack,容错率高

kafka选择的是第二种策略,原因如下:

1、同样为了容忍 n 台节点的故障,第一种方案需要 2n+1 个副本,而第二种方案只需要 n+1个副本,而 Kafka 的每个分区都有大量的数据,第一种方案会造成大量数据的冗余。

2、虽然第二种方案的网络延迟会比较高,但网络延迟对 Kafka 的影响较小。

六、消费消息有没有顺序?

Kafka中分区只能被同一个消费者组中的一个消费者消费,但是可以被多个不同消费者组的消费者同时消费。如果消费者组中只有一个消费者,那么这个消费者可以消费所有的分区。

既然kafka允许多个消费者对多个分区同时消费,且生产者生产的消息也落于不同的分区中,那么在这种情况下,消费这些消息的顺序肯定是不可控的。
我们可以控制生产消息的过程中让消息落入同一个分区,通过设定消息的key让kafka生产者根据key进行hash选择要写入的分区,来保证消息写入的顺序以及消费的顺序。

七、消息传递语义

Kafka提供3种消息传输一致性语义:最多1次,最少1次,恰好1次。

最少1次:可能会重传数据,有可能出现数据被重复处理的情况。

最多1次:可能会出现数据丢失情况。如果生产者在ack超时或者返回错误的时候不重试发送消息,那么消息有可能最终并没有写入Kafka topic中。

恰好1次:并不是指真正只传输1次,即使生产者重试发送消息,也只会让消息被发送给消费者一次。确保不会出现“数据被重复处理”和“数据丢失”的情况。通过“幂等性”和“事务”这两个特性来实现恰好一次。

八、leader选举机制

Kafka在Zookeeper中为每一个partition动态的维护了一个ISR,这个ISR里的所有replica都跟上了leader,只有ISR里的成员才能有被选为leader的可能。

在ISR中至少有一个follower时,Kafka可以确保已经commit的数据不丢失,但如果某一个partition的所有replica都挂了,就无法保证数据不丢失了。这种情况下有两种可行的方案:

1、等待ISR中任意一个replica“活”过来,并且选它作为leader。可保障数据不丢失,但时间可能相对较长。

2、选择第一个“活”过来的replica(并不一定是在ISR中)作为leader。无法保障数据不丢失,但相对不可用时间较短。

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验环境: - Kafka版本:2.12-2.0.0 - JDK版本:1.8.0_211 - IDE版本:IntelliJ IDEA 2020.1.2 实验过程: 1. 创建一个Kafka主题 首先,我们需要创建一个Kafka主题来存储我们的消息。我们可以使用Kafka自带的命令行工具kafka-topics.sh来创建主题。执行以下命令: ``` ./kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test ``` 这个命令将在本地Kafka服务器上创建一个名为“test”的主题,它只有一个分区和一个副本分区。 2. 编写生产者代码 在Java中,我们可以使用Kafka提供的KafkaProducer类来创建一个生产者。以下是一个简单的生产者实现: ```java import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerRecord; import java.util.Properties; public class ProducerExample { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); // Kafka服务器地址和端口号 props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); // 消息键序列化类 props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); // 消息值序列化类 KafkaProducer<String, String> producer = new KafkaProducer<>(props); // 创建一个Kafka生产者 String topic = "test"; // Kafka主题名称 String message = "Hello, Kafka!"; // 消息内容 ProducerRecord<String, String> record = new ProducerRecord<>(topic, message); // 创建一个生产者记录 producer.send(record); // 发送消息 producer.close(); // 关闭生产者 } } ``` 这个实现非常简单,它创建了一个KafkaProducer对象,设置了Kafka服务器地址和端口号、消息键序列化类和消息值序列化类。然后,它创建了一个ProducerRecord对象,该对象包含了要发送的消息的主题和内容,并将该对象发送到Kafka服务器。 3. 运行生产者代码 我们可以使用以下命令编译和运行上面的代码: ``` javac ProducerExample.java java ProducerExample ``` 如果一切正常,那么你应该会在Kafka服务器的日志中看到以下输出: ``` [2019-07-12 13:44:07,634] INFO [Producer clientId=producer-1] Sending record {test=Hello, Kafka!} with callback org.apache.kafka.clients.producer.internals.RecordBatch$1@6a5fc7e (org.apache.kafka.clients.producer.internals.Sender) ``` 这表明消息已成功发送到Kafka服务器。 实验总结: 在本次实验中,我们学习了如何在Java中使用KafkaProducer类来实现Kafka生产者。我们创建了一个Kafka主题,并使用KafkaProducer类发送消息到该主题。这个实现非常简单,只需要几行Java代码就可以完成。在实际应用中,我们可能需要使用更复杂的实现来处理更多的业务逻辑和异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值