kafka用法及名词解析

Kafka

 consumer-group

消费者组,可以将多个消费者组成一个消费者组,同一个组内的消费者消费的数据是不同的,不同组的消费者消费的数据是重复的,而且分区和消费者组是绑定的。

比如一个topic有2个分区,一个消费者组有2个消费者,那么一个消费者消费一个分区

比如一个topic有1个分区,一个消费者组有2个消费者,那么一个消费者消费一个分区,另外那个消费者啥也不干

比如一个topic有3个分区,一个消费者组有2个消费者,那么其中一个消费者消费一个分区,另外一个消费者消费两个分区

结论,一个消费者组内的消费者消费的数据是瓜分消费,而且是对分区进行瓜分,而不是对分区内的数据进行瓜分,一个分区内的数据一定只能由一个消费者消费

partition是不能被切分的,只能有一个消费者去处理,partition是能被消费的最小粒度

broker

一个kafka集群由多个broker组成,每个broker是一台服务器

Topic-partition

 

 每个Topic都有多个分区,分区数据相互独立,数据到kafka之后,会根据一定策略,将数据分发到不同的分区(轮询、权重、哈希取余等等),因此一个topic中的数据是分区有序全局无序的,如果想有序那就设置一个分区

每个分区都可设置多个分区副本,副本之间内容一样

其中一个副本为leader副本,负责通信、写入写出,其余副本为follower负责数据存储和数据同步,如果leader副本故障,follower副本会重新推选一个leader

同一个分区的多个副本,正常来说会分布在不同的broker上

kafka-broker-topic-partition

每个Topic的partition分区的存储方式,这里分区的副本个数一定要小于kafka集群的broker个数

KafkaProducer producer = new KafkaProducer(props);

package com.ws.kafka

import java.util.Properties

import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
import org.apache.kafka.common.serialization.StringSerializer

object KProducer {
  def main(args: Array[String]): Unit = {
    val prop = new Properties()
    // 指定kafka的server地址
    prop.setProperty("bootstrap.servers","dream1:9092,dream2:9092,dream3:9092")
    // 设置反序列化组件 一下两种方式都可以
    prop.setProperty("key.serializer",classOf[StringSerializer].getName)
    prop.setProperty("value.serializer","org.apache.kafka.common.serialization.StringSerializer")
    // 主题名称
    val topic = "wordcount"
    // 创建生产者
    val producer: KafkaProducer[String, String] = new KafkaProducer[String, String](prop)
    for (i <- 1 to 10){
      // 指定编号的数据
      val record1 = new ProducerRecord[String,String](topic,1,System.currentTimeMillis(),"key"+i,"value"+i)
      // 轮询分区,根据分区编号
      val par = i % 3
      val record2 = new ProducerRecord[String,String](topic,par,System.currentTimeMillis(),"key"+i,"value"+i)
      // 根据key进行分区 key.hashcode % partationnum
      val record3 = new ProducerRecord[String,String](topic,"key","value"+i)
      // 什么都不指定,默认策略(轮询)
      val record4 = new ProducerRecord[String,String](topic,"value"+i)
      // 发送消息
      producer.send(record4)
    }
    producer.close()
  }
}

KafkaConsumer consumer = new KafkaConsumer(props);

package com.ws.kafka

import java.util
import java.util.Properties

import org.apache.kafka.clients.consumer.{ConsumerRecords, KafkaConsumer}
import org.apache.kafka.common.serialization.StringDeserializer

object KConsumer {
  def main(args: Array[String]): Unit = {
    val prop = new Properties()
    // 指定kafka的server地址
    prop.setProperty("bootstrap.servers","dream1:9092,dream2:9092,dream3:9092")
    // 设置反序列化组件 一下两种方式都可以
    prop.setProperty("key.deserializer",classOf[StringDeserializer].getName)
    prop.setProperty("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer")
    // 指定该消费者所在的消费者组
    prop.setProperty("group.id","1")
    // 指定消费者从哪开始消费[latest,earliest]
    // earliest 从头开始消费,--from beginnig
    // latestb 从该消费者启动之后开始消费
    prop.setProperty("auto.offset.reset","earliest")
    // 是否自动提交偏移量,默认是true,就是每消费一条数据后,就向kafka报告当前消费的偏移量,来控制消费果的数据不再重复消费
    // 我们一般设置为false,自己手动更新偏移量
    prop.setProperty("enable.auto.commit","true")
    //-------------------以上是消费者的配置代码-------------------------------
    // 创建一个消费者
    val kafkaConsumer = new KafkaConsumer[String, String](prop)
    // 指定要订阅的topic
    val topic: util.List[String] = util.Arrays.asList("wordcount")
    kafkaConsumer.subscribe(topic)
    // 监听数据产生,并拉取数据
    import scala.collection.JavaConversions._
    while (true) {
      // 超过2000就放弃
      val msg: ConsumerRecords[String, String] = kafkaConsumer.poll(2000)
      msg.foreach(ms=>println(ms))
    }
  }
}

Acks机制

原理,生产者收到ack消息后才会写入下一条数据

ack=0

kafka有没有保存好,直接返回ack,生产者发送下一条数据,这样快,丢失率高

ack=1

生产者等待接收分区的leader副本写入成功后,才返回ack,生产者才写入下一条,这样速度一般,丢失率很小

ack=-1/all

生产者待接收分区的所有副本写入成功后,才返回ack,生产者才写入下一条,这样速度较慢,数据安全,无丢失

前提是  min.insync.replicas >=2  这个参数的意思是 需要同步的副本数量,如果min.insync.replicas=1 那么ack=-1和ack=1的效果是一样的

kafka幂等性重复校验

生产者每生产一条数据,携带一个id值,下一条时,id自增1,kafka写入之成功后记录上次的id值(last_id),如果再来一条携带的id(now_id)值与上次的id(last_id)值相同,直接返回ack,不进行写入操作

写入数据流程

1、producer 汇集一个batch数据,交给kafka集群

2、kafka通过集群分区规则,找的所在分区的leader副本进行数据写入pagecatch

3、leader副本后台会将pagecatch的数据持久化到磁盘上,形成segment

4、followe副本会向leader副本拉取同步数据

读取数据流程

1、consumer根据 Topic,分区,offset找,负责的leader副本

2、首先去pagecatch里查,如果有直接返回

3、如果没有,根据offset找到 segment(segment是根据offset命名的),segment中包括index索引文件,.log数据文件。

4、先找index(索引文件),然后去.log 里查找对应的数据

持久化数据位置,config/server.properties

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值