Kafka深入讲解

本文深入讲解Kafka的核心概念,包括broker、producer、consumer、topic和partition。详细阐述其容错性消费机制,消费者组的工作原理以及副本数的作用。还探讨了Kafka的offset管理和segment机制,并介绍了不同消费语义的特点与数据去重的方法。同时,提到了监控工具Kafka Eagle和CDH在监控Kafka中的应用,以及如何理解生产者和消费者的速度关系。

1.核心概念
broker: 进程
producer: 生产者
consumer: 消费者
topic: 主题
partitions: 分区  (副本数)

consumergroup:
1.容错性的消费机制
2.一个组内,共享一个公共的ID groupid
3.组内的所有消费者协调在一起,去消费topic的所有的分区
4.每个分区只能由同一个消费组的一个消费者来消费

副本数:每个分区有几个副本,以3为例:
发送123--> 0分区  在2,3机器上面也有个0分区,会备份123.   

offset: 每个partition的数据的id
kafka中的offset

segment: 
1.分为log和index文件
2.通过配置以下参数设置回滚
log.segment.bytes
log.roll.hours
3.命名规则: 上一个segment分组log文件的最大offset

2.消费语义

at most once: 最多消费一次  消费可能丢失  但是不会重复消费 ?-->适用于不重要的log,丢几条没事
at least once: 至少消费一次  消费不可能丢失 但是会重复消费 ?-->不用担心丢失,但数据会重复,需考虑去重
exactly once: 正好一次 消息不会丢失 也不会重复(这才是我们想要的)
          但0.10.0.1 不支持不能实现 0.11官方已支持

数据去重:1.HBase的put操作,MySQL的update insert操作。2.把数据放到redis,在redis中去重

consumer offset:
数据:1,2,3,4,5
传到:1,2,3consumer挂了,offset没有维护
那么重启后从上一次的更新的offset的位置去消费(断点还原) 

0.10版本的offset是存在kafka自己本身 
topic: test
内嵌一个topic:如

 

3.Flume-->Kafka-->Spark streaming 经典案例
Pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.ruozedata</groupId>
  <artifactId>DSHS</artifactId>
  <version>1.0-SNAPSHOT</version>
  <inceptionYear>2008</inceptionYear>

  <repositories>
    <repository>
      <id>scala-tools.org</id>
      <name>Scala-Tools Maven2 Repository</name>
      <url>http://scala-tools.org/repo-releases</url>
    </repository>
  </repositories>

  <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <scala.version>2.11.8</scala.version>
      <kafka.version>0.10.0.0</kafka.version>
      <spark.version>2.1.1</spark.version>
  </properties>


  <dependencies>

    <!-- scala-->
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>${scala.version}</version>
    </dependency>

    <!-- spark-->
    <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-sql_2.11</artifactId>
      <version>${spark.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-streaming_2.11</artifactId>
      <version>${spark.version}</version>
    </dependency>

    <!-- spark-streaming-kafka -->
    <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
      <version>${spark.version}</version>
    </dependency>



  </dependencies>

  <build>
    <plugins>

      <plugin>
        <groupId>org.scala-tools</groupId>
        <artifactId>maven-scala-plugin</artifactId>
        <version>2.15.2</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.19</version>
        <configuration>
          <skip>true</skip>
        </configuration>
      </plugin>

    </plugins>
  </build>


</project>

源码:

import java.util.Date
import org.apache.commons.lang3.time.FastDateFormat
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.{CanCommitOffsets, HasOffsetRanges, KafkaUtils}
import org.apache.spark.streaming.{Seconds, StreamingContext}


/**
  * By ruozedata-J  20180826
  */

object DSHS {
  def main(args: Array[String]): Unit = {
    //定义变量
    val timeFormat = FastDateFormat.getInstance("yyyy/MM/dd HH:mm:ss.SSS")
    println("启动时间:" + timeFormat.format(new Date()))
    //流间隔 batch的时间
    var slide_interval = Seconds(1) //默认 1秒
    if (args.length==1){
      slide_interval = Seconds(args(0).toLong) //自定义
    }
    val bootstrap_servers = "***.***.*.**:9092,***.***.*.**:9092,***.***.*.**:9092" //kakfa地址
    try {
      //1. Create context with 2 second batch interval
      val ss = SparkSession.builder()
        .appName("DSHS-0.1")
        .master("local[2]")
        .getOrCreate()
      val sc = ss.sparkContext
      val scc = new StreamingContext(sc, slide_interval)
      //2.设置kafka的map参数
      val kafkaParams = Map[String, Object](
        "bootstrap.servers" -> bootstrap_servers
        , "key.deserializer" -> classOf[StringDeserializer]
        , "value.deserializer" -> classOf[StringDeserializer]
        , "group.id" -> "use_a_separate_group_id_for_each_stream"

        , "auto.offset.reset" -> "latest"
        , "enable.auto.commit" -> (false: java.lang.Boolean)

        , "max.partition.fetch.bytes" -> (2621440: java.lang.Integer) //default: 1048576
        , "request.timeout.ms" -> (90000: java.lang.Integer) //default: 60000
        , "session.timeout.ms" -> (60000: java.lang.Integer) //default: 30000
      )
      //3.创建要从kafka去读取的topic的集合对象
      val topics = Array("onlinelogs")
      //4.输入流
      val directKafkaStream = KafkaUtils.createDirectStream[String, String](
        scc,
        PreferConsistent,
        Subscribe[String, String](topics, kafkaParams)
      )
      //坑  order window
      directKafkaStream.foreachRDD(
        rdd => {
          val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges //RDD的offset
           //rdd-->DF -->sql
          rdd.foreachPartition(rows => {
            rows.foreach { row =>
                println(row.toString) //打印
                //TODO 业务处理

            }
          })
          //该RDD异步提交offset
          directKafkaStream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)
        }
      )
      scc.start()
      scc.awaitTermination()
      scc.stop()
    } catch {
      case e: Exception =>
        println(e.getMessage)
    }
  }
}

auto.offset.reset:
latest 断点还原从最新的偏移量开始
earliest  断点还原从头开始=重新执行任务
none

enable.auto.commit: 一般设为false,如果设为true,易引发数据丢失
若设为true:
enable.auto.commit: true
auto.commit.interval.ms:5000   每个5s自动维护偏移量

生产:断批还原 +put 保证数据零丢失

举例:一个批次10000条数据,发送2000条后挂了。于是我们开始断批还原,从头传这个批次。那2000条数据,由于put命令的底层操作不会导致重复,后面的数据无缝对接传完。

4.监控 & 心得 
1.Kafka eagle:Kafka 消息监控 - Kafka Eagle
2.CDH 

通过以下语句构建图标实时监控:
SELECT total_kafka_bytes_received_rate_across_kafka_broker_topics ,total_kafka_bytes_fetched_rate_across_kafka_broker_topics
WHERE entityName = "kafka:onlinelogs" AND category = KAFKA_TOPIC

图:

1.生产者和消费者的速度是一样嘛?
由于趋势度吻合,所以速度一样的 

2.为什么消费者的曲线和生产者的曲线趋势度吻合?
可以及时消费,消费目前的数据量没有压力

3.为什么消费者的曲线和生产者的曲线要高?
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值