실제 기술 : 응용 프로그램 시나리오 데이터를 스트리밍 불꽃 모드 -Kafka 읽기

개인 블로그 탐색 페이지 (클릭 오른쪽에있는 링크를 개인 블로그를 엽니) : 다니엘은 기술 스택에 당신을 데려 갈 

개요

카프카, 수로, 소켓 스트림 등을 포함한 다양한 입력 소스 데이터를 읽어 실시간 스트리밍을 지원 스파크. 관여하지 않습니다 때문에 우리의 비즈니스 시나리오의 카프카 이외의 실시간 입력 소스 외에도이 논의되지 않습니다. 이 문서는 주로 현재의 비즈니스 시나리오에 초점을 맞추고 만 해당 스파크 스트리밍 카프카의 데이터를 읽습니다. 공식 이벤트에게 카프카의 데이터를 읽을 수있는 두 가지 방법을 스트리밍 스파크 :

  • 첫 번째 방법을 기반 수신기. 이러한 지원 제 공식 판독 모드의 종류, 그리고 스파크 1.2에서 데이터 손실 (제로 데이터 손실) 지원을 제공한다;
  • 먼저 직접 접근 (없음 수신기). 읽기 모드의이 종류는 스파크 1.3를 통합.

이 두 가지 매우 다른 방법의 존재는 물론, 장점과 단점의, 읽을 수 있습니다. 다음으로, 우리는이 두 가지 특정 데이터를 읽기 모드를 해부하자.

一, 수신자 - 기반 접근법

전술 한 바와 같이, 스파크 공식 카프카 먼저 소비 패턴에 따라 데이터 수신기를 제공한다. 그러나 프로그램이 1.2 스파크에서 구성 매개 변수의 도입 이후, 데이터 손실을 실패 할 수있을 것입니다 spark.streaming.receiver.writeAheadLog.enable이러한 위험을 방지하기 위해. 다음은 공식의 말씀입니다 :

기본 구성에서,이 방법은, 당신은 추가로이 동 ​​기적으로 수신 된 모든 카프카 데이터를 저장 (스파크 1.2에서 소개). 스트리밍 스파크에서 쓰기에 앞서 로그를 활성화해야합니다. (수신기 안정성을 참조 실패에서 데이터가 손실 될 수 있습니다 제로 데이터 손실을 보장하기 위해 분산 파일 시스템에 쓰기 앞서 로그 (예 : HDFS), 그래서 모든 데이터는 실패 복구 할 수있다.

수신기 기반의 읽기 모드

카프카에 기초하여 소비 데이터를 얻기 위해 카프카 카프카 고차 (하이 레벨) API를 판독 수신기 기반 방법. 태스크 스트리밍 스파크를 제출 한 후, 점화 클러스터 구체적 수신기 연속 비동기 판독 카프카 데이터가 각각 판독 범위의 파라미터에 의해 구성 될 수있는 시간 간격 및 오프셋을 판독 지정에 방치한다. 수신기, 판독 데이터를 특정의 저장 StorageLevel과 같은 사용자가 지정한 방식 MEMORY_ONLY등이있다. 데이터 수신기의 드라이버 트리거 배치 작업은 실행의 실행자의 나머지 부분에 전송됩니다합니다. 수행 한 후, 수신기는 사육사의 오프셋 따라 업데이트됩니다. 당신은 반드시 적어도 읽기 모드에서 한번 설정 될 수 있음을 확인하려면 spark.streaming.receiver.writeAheadLog.enabletrue로. 수신기의 특정 구현 프로세스는 다음과 같이 :

캡션을 입력

달성 판독 수신기 기반

카프카의 높은 수준의 데이터 모드는 사용자가 코드의 양과 사용자의 작업 부하와 상대적으로 간단 감소 관심 또는 유지 보수 오프셋 소비자,없이, 읽기 데이터에 초점을 읽을 수 있도록 허용합니다. 따라서, 스파크 스트리밍 계산 엔진의 도입의 시작 부분에, 우리는 데이터 읽기에 우선 순위를 부여하기 위해이 방법을 사용, 특정 코드는 다음입니다 :

 /*读取kafka数据函数*/
  def getKafkaInputStream(zookeeper: String,
                            topic: String,
                            groupId: String,
                            numRecivers: Int,
                            partition: Int,
                            ssc: StreamingContext): DStream[String] = {
    val kafkaParams = Map(
      ("zookeeper.connect", zookeeper),
      ("auto.offset.reset", "largest"),
      ("zookeeper.connection.timeout.ms", "30000"),
      ("fetch.message.max.bytes", (1024 * 1024 * 50).toString),
      ("group.id", groupId)
    )
    val topics = Map(topic -> partition / numRecivers)

    val kafkaDstreams = (1 to numRecivers).map { _ =>
      KafkaUtils.createStream[String, String, StringDecoder, StringDecoder](ssc,
        kafkaParams,
        topics,
        StorageLevel.MEMORY_AND_DISK_SER).map(_._2)
    }

    ssc.union(kafkaDstreams)
  }

상기 코드의 함수로서 getKafkaInputStream제공하는 zookeepertopicgroupIdnumReceiverspartitionssc에 대응하는 함수에 전달되는 :

  • 사육사 : 사육사 연결 정보
  • 주제 : 주제 정보 카프카의 ENTERED
  • 의 groupId : 소비자 정보
  • numReceivers :에 의도 된 수신기의 수, 동시성을 조정하는 데 사용
  • 파티션 : 카프카는 파티션 항목의 수에 해당하는

주요 매개 변수는 몇 카프카 카프카보다 더 많은 연결하여 데이터를 읽는 데 사용. 다음과 같이 수행하는 특정 단계가있다 :

  • 상기 카프카 관련 파라미터를 판독  zookeeper.connect, 즉 사육사 입력 파라미터를 전달 auto.offset.reset화제로부터 판독 된 최신의 데이터의 시작을 설정하는 단계; zookeeper.connection.timeout.ms네트워크의 불안정성을 방지하기 zookeepr 접속 타임 아웃 기간을 말하며 fetch.message.max.bytes한 판독 데이터를 의미 크기, group.id이것은 소비자로 지정된다.
  • 지정 동시 주제의 수, 때 지정된 수신자의 수 있지만, 각 수신기가 다른 파티션을 읽기 위해 해당 스레드 위 재생할 수 있도록 수신기의 수는 적은 파티션 항목의 수보다 때문이다.
  • 카프카는 우리가 수신기로, 수신기는 애플리케이션 처리량을 향상시키기 위해보다 개방 얼마나 많은 집행자 지정해야이 데이터, numReceivers 매개 변수를 참조하십시오.
  • 데이터 수신기의 복수의 연관 연합 읽기

수신기 기반의 독서 질문

우리의 장면 중 일부의 요구를 충족하기 위해 Reveiver 기반의 방법을 사용하고, 마이크로 배치의이 추상 일부를 기반으로, 메모리 내 모델을 계산. 특정 시나리오에서, 우리는 몇 가지 최적화를 수행하는이 방법에 있습니다 :

  • 데이터 손실 방지. 체크 포인트의 운영 및 구성 수행 spark.streaming.receiver.writeAheadLog.enable매개 변수를;
  • 수신기 데이터 처리량을 개선. 사용 MEMORY_AND_DISK_SER데이터를 판독, 단일 수신기 메모리 향상 또는 수신기에 복수의 데이터 분배 병렬 큰 정도를 옮긴다.

어느 정도 상기 방법은, 이러한 모델을 계산 마이크로 배치와 같은 메모리 우리 애플리케이션 시나리오를 충족. 그러나 동시에 이러한 두 가지 요인뿐만 아니라 문제의 다른 측면은 다양한 상황의 원인이됩니다 :

  • 구성 spark.streaming.receiver.writeAheadLog.enable파라미터는 상기 처리 데이터 처리의 효율을 감소 로그 디렉토리의 체크 포인트에 각각 배치하기 전에 백업 할 차례로 압력 수신단 증가, 또한 데이터 백업 메커니즘 때문에, 부하의 영향을받을 것이다 고부하 지연의 위험은 응용 프로그램이 충돌의 결과로 발생합니다.
  • 사용 MEMORY_AND_DISK_SER감소 메모리 요구 사항을. 그러나 어느 정도 충돌 속도 계산,
  • 단일 수신기 메모리. 수신기가 실행 프로그램의 일부이기 때문에, 스루풋 증가시키기 위해, 수신기 메모리 향상. 그러나 각 배치 컴퓨팅에서, 일괄 계산에 참여하고 자원의 심각한 낭비의 결과로, 너무 많은 메모리를 사용하지 않습니다.
  • 병렬 과정 수신기 카프카 복수의 데이터를 저장하는데 사용된다. 수신기는 데이터가 비동기 및 계산에 참여하지 않습니다 읽어 보시기 바랍니다. 병렬 처리의 개방 정도는 가치가 없다 처리량 높은 균형을합니다.
  • 비동기 수신기 실행자 컴퓨팅 지연으로 이어지는 네트워크에서 발생 계산하고 인과 적 요인, 컴퓨팅 큐는 수신기가 수신 된 데이터로 하였지만, 매우 쉽게 프로그램 충돌이 발생하도록 증가하고있다.
  • 프로그램 복구에 실패하면,이 바닥의 데이터의 부분 일 수 있지만 프로그램이 실패 수, 오프셋의 경우는 리드 데이터의 중복 사용량을 업데이트하지 않는다.

위의 문제의 조항으로 돌아가려면, 자원의 사용을 줄이고, 우리 나중에 채택 직접 접근 카프카는 특히 다음 정교한 데이터를 읽을 수 있습니다.

二, 직접 접근 (없음 수신기)

데이터 소비의 수신기 기반의 방법과는 달리, 1.3 스파크에서 카프카 데이터 소비 직접 모드의 공식 소개 스파크. 수신기 기반의 접근 방식에 상대, 직접 모드는 다음과 같은 분야에서 장점이 있습니다 :

  • (간체 병렬)을 간략화 평행. 지금은 여러 개의 입력과 조합 소스 파티션의 카프카 주제 및 파티션 RDD-한 대응을 만들 필요가 없습니다, 공식은 다음으로 설명 :

필요가 다수의 카프카 스트림 입력과 조합을 만들 수 없습니다. 모든 병렬 카프카로부터 데이터를 읽 소비 카프카 파티션이 있기 때문에 directStream으로 스파크 스트리밍 RDD 많은 파티션으로 생성한다. 그래서 이해하고 조정하기가 쉽습니다 카프카와 RDD 파티션 사이의 일대일 매핑이 있습니다.

  • 효율성 (효율성). 데이터 손실 (제로 데이터 손실)을 구성 할 필요가 있도록 수신기 기반 spark.streaming.receiver.writeAheadLog.enable데이터의 두 복사본을 저장하는 방법이 필요하여 효율에도 영향을 저장 공간의 낭비. 이 문제가 존재하지 않습니다 직접적인 방법.

첫 번째 방법에서 데이터를 제로 데이터 손실을 달성하는 것이 필요한 상기 데이터를 복제 미리 기록 로그에 저장한다. 이 데이터를 효율적으로 두 번 복제됩니다 같은 사실은 비효율적이다 - 일단 카프카에 의해, 그리고 앞서 쓰기로 로그인 한 번 더. 미리 쓰기 로그에 대한 필요 때문에 아무 수신기도없고, 같이이 두 번째 접근 방식은 문제가 없습니다. 만큼 당신이 충분한 카프카의 보유를 가지고있는 메시지는 카프카에서 복구 할 수 있습니다.

  • 강한 일관된 의미 (정확하게 회 의미). 높은 수준의 데이터 만 오프셋이 스파크에 의해 유지는 사육사에 의해 소비 스트리밍. 매개 변수로 구성 소비자 일단 이러한 상황이 소비 데이터를 반복 할 수있다 - 적어도 달성 될 수있다.

첫 번째 방법은 사육사에서 소비 오프셋을 저장하는 카프카의 높은 수준의 API를 사용합니다. 이것은 전통적으로 카프카의 데이터를 소비 할 수있는 방법입니다. (쓰기 앞서 로그와 함께)이 접근 방식은 데이터 손실을 보장 할 수 있지만 (즉, 의미를 한번 적어도), 일부 레코드는 약간의 실패에서 두 번 소비 얻을 수있는 작은 기회가있다. 이는 사육사 추적 확실하게 스파크 스트리밍 데이터 수신 오프셋 간의 불일치로 인해 발생한다. 따라서,이 두 번째 접근 방식에서 우리는 사육사를 사용하지 않는 간단한 카프카의 API를 사용합니다. 오프셋은 체크 포인트 내에서 스트리밍 스파크에 의해 추적됩니다. 스파크 스트리밍 및 사육사 / 카프카 간의을 제거해 불일치, 각 레코드는 실패에도 불구하고 효과적으로 정확히 한 번만 스트리밍 스파크에 의해 수신 될 수 있도록. 결과의 출력을 정확히-한 번 의미를 달성하기 위해,

직접 읽기 모드

직접 모드는이 방법은 더 이상 지속적으로 데이터를 읽을 수 수신기를 전문이 필요합니다, 사육사를 거치지 않고 데이터를 읽을 수있는 카프카의 소비자 API를 간단한 방법을 사용하지 않습니다. 일괄 작업을 트리거하면, 데이터는 집행 인에 의해 읽고, 갈 데이터 계산 과정의 다른 집행자에 참여한다. 얼마나 많은 오프셋을 결정하는 드라이버를 읽고, 오프셋 유지하기 위해 체크 포인트라고. 다음 배치 작업을 트리거 한 후 집행 인에 의해 카프카와 계산 된 데이터를 읽습니다. 이 과정에서 우리는, 데이터를 읽을 필요없이 방법을 직접 수신기를 찾을 수 있지만, 필요 데이터 계산을 읽을 수있는 데이터 소비 직접 적은 메모리의 방법을 요구하고, 만 계산에 필요한 메모리 캔 배치를 고려할 필요가 있으므로 또 다른 배치 작업이 축적 될 때, 데이터 축적에 영향을 미치지 않습니다. 다음과 같은 특정도 읽

캡션을 입력

직접 읽기 실현

스파크 스트리밍 오버로드 데이터의 수는 우리의 응용 프로그램 시나리오에서 사용되는 카프카의 방법이 스칼라 기반의 접근 방식에 대한 본 논문의 초점을 읽기 제공, 특정 방법 코드는 다음입니다 :

  • 방법 createDirectStreamsscStreamingContext, kafkaParams구체적인 구성은 동일하여, 수신기 계 중에서 구성 참조, 즉 주목하여야가 fromOffsets 오프셋로부터 데이터를 판독 시작을 지정하기 위해 사용된다.
def createDirectStream[
    K: ClassTag,
    V: ClassTag,
    KD <: Decoder[K]: ClassTag,
    VD <: Decoder[V]: ClassTag,
    R: ClassTag] (
      ssc: StreamingContext,
      kafkaParams: Map[String, String],
      fromOffsets: Map[TopicAndPartition, Long],
      messageHandler: MessageAndMetadata[K, V] => R
  ): InputDStream[R] = {
    val cleanedHandler = ssc.sc.clean(messageHandler)
    new DirectKafkaInputDStream[K, V, KD, VD, R](
      ssc, kafkaParams, fromOffsets, cleanedHandler)
  }
  • CreateDirectStream 방법,이 방법은 세 가지 매개 변수를 필요로 kafkaParams변화가없는 것을 여전히 동일을, 그러나 어떤이 구성이있다 auto.offset.reset최대 또는 최소가에서 데이터를 읽기 시작 지정하는 데 사용할 수있다 topic토픽 카프카을 의미한다, 당신은 더 지정할 수 있습니다. 다음과 같이 특정 코드의 방법은 다음과 같습니다 :
def createDirectStream[
    K: ClassTag,
    V: ClassTag,
    KD <: Decoder[K]: ClassTag,
    VD <: Decoder[V]: ClassTag] (
      ssc: StreamingContext,
      kafkaParams: Map[String, String],
      topics: Set[String]
  ): InputDStream[(K, V)] = {
    val messageHandler = (mmd: MessageAndMetadata[K, V]) => (mmd.key, mmd.message)
    val kc = new KafkaCluster(kafkaParams)
    val fromOffsets = getFromOffsets(kc, kafkaParams, topics)
    new DirectKafkaInputDStream[K, V, KD, VD, (K, V)](
      ssc, kafkaParams, fromOffsets, messageHandler)
  }

실제 응용 시나리오에서, 우리는 두 가지 방법, 대략 두 가지 측면으로 나누어 방향의 조합을 사용합니다 :

  • 응용 프로그램 시작. 큰 프로그램의 개발에 줄이면서 카프카 소비 데이터가 현재 데이터를 읽을 때, 두 번째 방법;
  • 응용 프로그램 다시 시작합니다. 다른 이유로 자원, 프로그램을 다시 시작 실패의 결과로 네트워크가,이 때 이전의 오프셋에서 데이터를 읽기 시작해야합니다 때 우리는 우리의 현장 있도록 첫 번째 방법을 사용해야합니다.

전반적으로 방향, 우리는 우리의 요구를 충족하기 위해 위의 방법을 사용, 물론, 우리는이 블로그 항목에서 논의되지 않은 특정 전략을 소개하는 특별한 후속 기사가있을 것입니다. 카프카의 데이터 코드는 최대 규모를 읽거나 작은는 다음을 달성 :

/**
    * 读取kafka数据,从最新的offset开始读
    *
    * @param ssc         : StreamingContext
    * @param kafkaParams : kafka参数
    * @param topics      : kafka topic
    * @return : 返回流数据
    */
private def getDirectStream(ssc: StreamingContext,
                            kafkaParams: Map[String, String],
                            topics: Set[String]): DStream[String] = {
  val kafkaDStreams = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
    ssc,
    kafkaParams,
    topics
  )
  kafkaDStreams.map(_._2)
}

다음과 같이 논리 코드를 다시 시작 실패 :

/**
    * 如果已有offset,则从offset开始读数据
    *
    * @param ssc         : StreamingContext
    * @param kafkaParams : kafkaParams配置参数
    * @param fromOffsets : 已有的offsets
    * @return : 返回流数据
    */
private def getDirectStreamWithOffsets(ssc: StreamingContext,
                                       kafkaParams: Map[String, String],
                                       fromOffsets: Map[TopicAndPartition, Long]): DStream[String] = {
  val kfkData = try {
    KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder, String](
      ssc,
      kafkaParams,
      fromOffsets,
      (mmd: MessageAndMetadata[String, String]) => mmd.message()
    )
  } catch { //offsets失效, 从最新的offsets读。
    case _: Exception =>
    val topics = fromOffsets.map { case (tap, _) =>
      tap.topic
    }.toSet
    getDirectStream(ssc, kafkaParams, topics)
  }
  kfkData
}

코드 fromOffsets외부 기억 처리로부터 취득한 매개 변수를 다음과 같이 변환 코드가 필요 :

val fromOffsets = offsets.map { consumerInfo =>
  TopicAndPartition(consumerInfo.topic, consumerInfo.part) -> consumerInfo.until_offset
}.toMap

방법은 카프카가 데이터의 지정된 오프셋 (offset)에서 읽을 수 있습니다. 당신이 비정상적인 읽기 데이터를 찾을 수 있다면, 우리는 그 오프셋이 예외를 잡을 수있는 실패, 이러한 상황을 생각 카프카는 최대 규모의 사무실에서 데이터를 읽습니다.

직접 읽기 문제

실제 응용 프로그램에서 직접 장점은 다음과 같은 분야에서가, 수신기 기반 모드에 비해, 우리의 요구를 충족 할 수있는 좋은 방법 접근 :

  • 자원을 줄일 수 있습니다. 계산 작업에 참여하는 모든 응용 프로그램의 수신기, 실행자를 필요로하지 직접, 수신기 기반이 계산 데이터에 참여하지 않는 카프카 특별한 수신기를 읽을 필요가있다. 그래서 같은 자원을 신청, 직접 큰 사업을 지원할 수.

  • 메모리를 줄일 수 있습니다. 수신기 기반의 다른 Exectuor에 수신기는 비동기이며, 교통 체증, 수신기의 메모리를 개선 할 필요가 발생하지만, 집행자의 계산에 관여하는 경우, 다행히도 비즈니스 시나리오의 작은 볼륨에 데이터를 수신하기 위해 계속 할 수는 그다지 필요 메모리. 그리고 직접 수신기 만 읽은 데이터의 계산, 직접 계산, 낮은 메모리 요구 사항이 없기 때문입니다. 실제 응용 프로그램은 우리가 10G가 2-4G에 대한 아래로 지금 원본을 넣을 수 있습니다.

  • 더 강력한. 수신기 기반의 방법은 작업이 발생 실시간 누적 결과는 스토리지 부하 비동기 연속 데이터 네트워크 발생 요인을 판독하는 수신기를 필요로하지만, 수신기는 여전히 데이터를 읽는 것을 계속 이러한 상황이 쉽게 계산의 붕괴를 초래할 수있다. 트리거 배치 드라이버 작업을 계산할 때, 데이터와 계산을 읽 그런 우려를 직접하지 않습니다. 큐 축적하지 프로그램의 실패 원인 않습니다 발생합니다.

이러한 간략화 된 병렬 (병렬 간체) 효율 (효율)과 강하게 일관된 의미 다른 이점에 관해서는 (정확하게 회 의미) 전에 열거하고 설명되지 않을 것이다. 직접 이러한 장점을 가지고 있지만, 일부 결함이 있지만, 같은 다음과 같습니다 :

  • 비용을 증가시킨다. 사육사에 의해 오프셋이 증가 사용자의 개발 비용을 유지하기 위해 직접 오히려 수신기 기반보다, 오프셋 (offset)을 유지하기 위해 체크 포인트 또는 타사 스토리지를 채택하는 사용자가 필요합니다.
  • 시각화를 모니터링. 직접 더이 완료 모니터링 및 시각화 경우, 당신은 인간 발달을 넣어 편리 필요가 같은없는 동안 지정된 소비자의 소비 수신기 기반으로 지정된 주제는 사육사에 의해 모니터링 할 수 있습니다.

첨부 자바 / C / C ++ / 기계 학습 / 알고리즘 및 데이터 구조 / 프런트 엔드 / 안드로이드 / 파이썬 / 프로그래머 읽기 / 하나의 책 책 Daquan의 :

(건조 개인 블로그에이 열 오른쪽 클릭) : 기술 건조한 꽃을
===== >> ① [자바 다니엘은 진보의 길에 당신을 데려] << ====
===== >> ② [+ ACM 알고리즘 데이터 구조 다니엘 진보에 도로에 걸릴] << ===
===== >> ③ [데이터베이스 다니엘 진보에 도로에 걸릴] << == ===
===== >> ④ [다니엘 웹 프런트 엔드는 고급가는 길에 당신을 데려 갈 수 있습니다] << ====
===== >> ⑤ [기계 학습 파이썬 다니엘은 당신에게 항목을 고급 도로] << ====
===== >> ⑥ [건축가 다니엘은 진보의 길에 당신을 데려] << =====
===== >> ⑦ [C ++ 다니엘은 도로에 당신을 데려 갈 고급] << ====
===== >> ⑧ [다니엘은 진보의 길에 당신을 데려 갈 IOS] << ====
=====> > ⑨ [웹 보안 다니엘은가는 길에 당신을 데려 갈 고급] << =====
===== >> ⑩ [리눅스 운영 체제와 다니엘은 진보의 길에 당신을 데려] << = ====

더 불로 과일이 없다, 당신이 젊은 친구가, 친구가 기술을 배우고 싶은 희망, 도로의 방법으로 모든 장애물을 극복, 기술에 묶어 책을 이해 한 다음 코드에 노크, 원리를 이해하고 연습을 갈 것입니다 결정 그것은 당신의 미래, 당신에게 꿈을 생활, 직장을 가져올 것이다.

게시 47 개 원래 기사 · 원의 칭찬 0 · 조회수 284

추천

출처blog.csdn.net/weixin_41663412/article/details/104860416