kafka-connect-hive sink插件实现要点小结

Kafka Connect SMT数据塑形实战:语义清洗、结构扁平与契约治理 Kafka Connect的Simple Message Transform(SMT)是实现流式数据轻量级治理的核心能力,其本质是在消息流转链路最前端完成字段语义统一、嵌套结构扁平化与Schema演进兜底。相比Flink或KSQL后置处理,SMT以零GC开销、低延迟和强确定性保障数据‘可读、可验、可追溯’,支撑金融级数据管道的合规性与可观测性要求。本文聚焦data shaping与schema evolution两大高频技术诉求,详解ReplaceField、Flatten、InsertField等关键SM 阅读详情

面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>>   hot3.png

kafka-connect-hive sink插件实现了以ORC和Parquet两种方式向Hive表中写入数据。Connector定期从Kafka轮询数据并将其写入HDFS,来自每个Kafka主题的数据由提供的分区字段进行分区并划分为块,每个数据块都表示为一个HDFS文件,文件名由topic名称+分区编号+offset构成。如果配置中没有指定分区,则使用默认分区方式,每个数据块的大小由已写入HDFS的文件长度、写入HDFS的时间和未写入HDFS的记录数决定。

在阅读该插件的源码过程中,觉得有很多值得学习的地方,特总结如下以备后忘。

一、分区策略

该插件可以配置两种分区策略:

  • STRICT:要求必须已经创建了所有分区

  • DYNAMIC:根据PARTITIONBY指定的分区字段创建分区

STRICT策略

实现代码及注释如下:

package com.landoop.streamreactor.connect.hive.sink.partitioning

import com.landoop.streamreactor.connect.hive.{DatabaseName, Partition, TableName}
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.hadoop.hive.metastore.IMetaStoreClient

import scala.collection.JavaConverters._
import scala.util.control.NonFatal
import scala.util.{Failure, Success, Try}

/**
  * A [[PartitionHandler]] that requires any partition
  * to already exist in the metastore.
  *
  * 要求分区已经在metastore中存在
  */
object StrictPartitionHandler extends PartitionHandler {

  override def path(partition: Partition,
                    db: DatabaseName,
                    tableName: TableName)
                   (client: IMetaStoreClient,
                    fs: FileSystem): Try[Path] = {
    try {
      // 获取Hive metastore中表的存储位置,成功则返回
      val part = client.getPartition(db.value, tableName.value, partition.entries.map(_._2).toList.asJava)
      Success(new Path(part.getSd.getLocation))
    } catch { // 未找到表的存储位置,返回异常
      case NonFatal(e) =>
        Failure(new RuntimeException(s"Partition '${partition.entries.map(_._2).toList.mkString(",")}' does not exist and strict policy requires upfront creation", e))
    }
  }
}

DYNAMIC策略

实现代码及注释如下:

package com.landoop.streamreactor.connect.hive.sink.partitioning

import com.landoop.streamreactor.connect.hive.{DatabaseName, Partition, TableName}
import com.typesafe.scalalogging.slf4j.StrictLogging
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.hadoop.hive.metastore.IMetaStoreClient
import org.apache.hadoop.hive.metastore.api.{StorageDescriptor, Table}

import scala.collection.JavaConverters._
import scala.util.{Failure, Success, Try}

/**
  * A [[PartitionHandler]] that creates partitions
  * on the fly as required.
  *
  * The path of the partition is determined by the given
  * [[PartitionPathPolicy]] parameter. By default this will
  * be an implementation that uses the standard hive
  * paths of key1=value1/key2=value2.
  */
class DynamicPartitionHandler(pathPolicy: PartitionPathPolicy = DefaultMetastorePartitionPathPolicy)
  extends PartitionHandler with StrictLogging {

  override def path(partition: Partition,
                    db: DatabaseName,
                    tableName: TableName)
                   (client: IMetaStoreClient,
                    fs: FileSystem): Try[Path] = {

    def table: Table = client.getTable(db.value, tableName.value)

    def create(path: Path, table: Table): Unit = {
      logger.debug(s"New partition will be created at $path")

      // 设置的表的存储位置信息
      val sd = new StorageDescriptor(table.getSd)
      sd.setLocation(path.toString)

      val params = new java.util.HashMap[String, String]
      // 获取分区key的值、分区创建时间
      val values = partition.entries.map(_._2).toList.asJava
      val ts = (System.currentTimeMillis / 1000).toInt

      // 给表设置并创建新分区
      val p = new org.apache.hadoop.hive.metastore.api.Partition(values, db.value, tableName.value, ts, 0, sd, params)
      logger.debug(s"Updating hive metastore with partition $p")
      client.add_partition(p)

      logger.info(s"Partition has been created in metastore [$partition]")
    }

    // 获取分区信息
    Try(client.getPartition(db.value, tableName.value, partition.entries.toList.map(_._2).asJava)) match {
      case Success(p) => Try { // 成功则返回
        new Path(p.getSd.getLocation)
      }
      case Failure(_) => Try { // 失败则根据分区路径创建策略生成分区路径并返回
        val t = table
        val tableLocation = new Path(t.getSd.getLocation)
        val path = pathPolicy.path(tableLocation, partition)
        create(path, t)
        path
      }
    }
  }
}

该方式会以标准的Hive分区路径来创建分区,也就是分区字段=分区字段值的方式。

二、文件命名和大小控制

Kafka轮询数据并将其写入HDFS,来自每个Kafka主题的数据由提供的分区字段进行分区并划分为块,每个数据块都表示为一个HDFS文件,这里涉及到两个细节:

  • 如何给文件命名
  • 文件如何分块,文件大小及数量如何控制

接下来逐一看一下相关代码实现,文件命名部分实现代码如下:

package com.landoop.streamreactor.connect.hive.sink.staging

import com.landoop.streamreactor.connect.hive.{Offset, Topic}

import scala.util.Try

trait FilenamePolicy {
  val prefix: String
}

object DefaultFilenamePolicy extends FilenamePolicy {
  val prefix = "streamreactor"
}

object CommittedFileName {

  private val Regex = s"(.+)_(.+)_(\\d+)_(\\d+)_(\\d+)".r

  def unapply(filename: String): Option[(String, Topic, Int, Offset, Offset)] = {
    filename match {
      case Regex(prefix, topic, partition, start, end) =>
        // 返回主题名称、分区编号、起始offset和结束offset
        Try((prefix, Topic(topic), partition.toInt, Offset(start.toLong), Offset(end.toLong))).toOption
      case _ => None
    }
  }
}

从上面代码可以看出,文件名由topic名称+分区编号+offset构成。假设文件前缀是streamreactor,topic名称是hive_sink_orc,分布编号是0,当前最大的offset是1168,那么最终生成的文件名称就是streamreactor_hive_sink_orc_0_1168。

接下来看看文件的大小是如何控制的。在HDFS中一个块通常是64M、128M、256M,小文件会占用NameNode的大量元数据存储内存,增加文件数据块的寻址时间。文件的大小主要由sink插件的三个配置项决定,这些配置项信息如下:

  • WITH_FLUSH_INTERVAL:long类型,表示文件提交的时间间隔,单位是毫秒
  • WITH_FLUSH_SIZE:long类型,表示执行提交操作之前,已提交到HDFS的文件长度,单位是字节
  • WITH_FLUSH_COUNT:long类型,表示执行提交操作之前,未提交到HDFS的记录数,一条数据算一个记录

这些参数在CommitPolicy特质中被使用,该特质的信息及实现类如下:

package com.landoop.streamreactor.connect.hive.sink.staging

import com.landoop.streamreactor.connect.hive.TopicPartitionOffset
import com.typesafe.scalalogging.slf4j.StrictLogging
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.kafka.connect.data.Struct

import scala.concurrent.duration.FiniteDuration

/**
  * The [[CommitPolicy]] is responsible for determining when
  * a file should be flushed (closed on disk, and moved to be visible).
  *
  * Typical implementations will flush based on number of records,
  * file size, or time since the file was opened.
  *
  * 负责决定文件何时被刷新(在磁盘上关闭,以及移动到可见),一般情况下基于记录数量、文件大小和文件被打开的时间来刷新
  */
trait CommitPolicy {

  /**
    * This method is invoked after a file has been written.
    *
    * If the output file should be committed at this time, then this
    * method should return true, otherwise false.
    *
    * Once a commit has taken place, a new file will be opened
    * for the next record.
    *
    * 该方法在文件被写入之后调用,在这时如果文件应该被提交,该方法返回true,否则返回false。一旦发生了提交,新文件将为下一个记录打开
    *
    * @param tpo   the [[TopicPartitionOffset]] of the last record written 最后一次记录的TopicPartitionOffset
    * @param path  the path of the file that the struct was written to 文件写入的路径
    * @param count the number of records written thus far to the file 到目前为止写入文件的记录数
    *
    */
  def shouldFlush(struct: Struct, tpo: TopicPartitionOffset, path: Path, count: Long)
                 (implicit fs: FileSystem): Boolean
}

/**
  * Default implementation of [[CommitPolicy]] that will flush the
  * output file under the following circumstances:
  * - file size reaches limit
  * - time since file was created
  * - number of files is reached
  *
  * CommitPolicy 的默认实现,将根据以下场景刷新输出文件:
  * 文件大小达到限制
  * 文件创建以来的时间
  * 达到文件数量
  *
  * @param interval in millis 毫秒间隔
  */
case class DefaultCommitPolicy(fileSize: Option[Long],
                               interval: Option[FiniteDuration],
                               fileCount: Option[Long]) extends CommitPolicy with StrictLogging {
  require(fileSize.isDefined || interval.isDefined || fileCount.isDefined)

  override def shouldFlush(struct: Struct, tpo: TopicPartitionOffset, path: Path, count: Long)
                          (implicit fs: FileSystem): Boolean = {
    // 返回文件状态
    val stat = fs.getFileStatus(path)
    val open_time = System.currentTimeMillis() - stat.getModificationTime // 计算文件打开时间

    /**
      * stat.getLen:文件长度,以字节为单位
      * stat.getModificationTime:文件修改时间,以毫秒为单位
      */
    fileSize.exists(_ <= stat.getLen) || interval.exists(_.toMillis <= open_time) || fileCount.exists(_ <= count)
  }
}

现在来分析一下DefaultCommitPolicy类的实现逻辑:

首先,返回HDFS上文件的状态,接着计算文件被打开的时间,最后使用exists函数来执行以下逻辑判断:

  • fileSize.exists(_ <= stat.getLen):已提交到HDFS的文件长度stat.getLen是否大于设置的文件长度阈值fileSize
  • interval.exists(_.toMillis <= open_time):文件打开时间open_time是否大于设置的文件打开时间阈值interval
  • fileCount.exists(_ <= count):未提交到HDFS的记录数count是否大于设置未提交到HDFS的记录数阈值fileCount

以上三个判断条件只要任何一个成立,就返回true,接着执行flush操作,将文件刷新到HDFS的对应目录中,这样就很好地控制了文件的大小以及数量,避免过多小文件的产生。

三、异常处理策略

异常处理不当的话,会直接影响服务的高可用,产生不可预估的损失。kafka-connect在处理数据读写的过程中产生的异常默认是直接抛出的,这类异常容易使负责读写的task停止服务,示例异常信息如下:

[2019-02-25 11:03:56,170] ERROR WorkerSinkTask{id=hive-sink-example-0} Task threw an uncaught and unrecoverable exception (org.apache.kafka.connect.runtime.WorkerTask:177)
MetaException(message:Could not connect to meta store using any of the URIs provided. Most recent failure: org.apache.thrift.transport.TTransportException: java.net.ConnectException: Operation timed out (Connection timed out)
	at org.apache.thrift.transport.TSocket.open(TSocket.java:226)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.open(HiveMetaStoreClient.java:477)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.<init>(HiveMetaStoreClient.java:285)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.<init>(HiveMetaStoreClient.java:210)
	at com.landoop.streamreactor.connect.hive.sink.HiveSinkTask.start(HiveSinkTask.scala:56)
	at org.apache.kafka.connect.runtime.WorkerSinkTask.initializeAndStart(WorkerSinkTask.java:302)
	at org.apache.kafka.connect.runtime.WorkerSinkTask.execute(WorkerSinkTask.java:191)
	at org.apache.kafka.connect.runtime.WorkerTask.doRun(WorkerTask.java:175)
	at org.apache.kafka.connect.runtime.WorkerTask.run(WorkerTask.java:219)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Operation timed out (Connection timed out)
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at org.apache.thrift.transport.TSocket.open(TSocket.java:221)
	... 13 more
)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.open(HiveMetaStoreClient.java:525)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.<init>(HiveMetaStoreClient.java:285)
	at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.<init>(HiveMetaStoreClient.java:210)
	at com.landoop.streamreactor.connect.hive.sink.HiveSinkTask.start(HiveSinkTask.scala:56)
	at org.apache.kafka.connect.runtime.WorkerSinkTask.initializeAndStart(WorkerSinkTask.java:302)
	at org.apache.kafka.connect.runtime.WorkerSinkTask.execute(WorkerSinkTask.java:191)
	at org.apache.kafka.connect.runtime.WorkerTask.doRun(WorkerTask.java:175)
	at org.apache.kafka.connect.runtime.WorkerTask.run(WorkerTask.java:219)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
[2019-02-25 11:03:56,172] ERROR WorkerSinkTask{id=hive-sink-example-0} Task is being killed and will not recover until manually restarted (org.apache.kafka.connect.runtime.WorkerTask:178)

在以上异常信息可以看到,由于连接Hive metastore超时,因此相关的Task被杀死,需要我们手动重启。当然这只是kafka-connect在运行中发生的一个异常,对于这类容易使Task停止工作的异常,需要设置相关的异常处理策略,sink插件在实现中定义了三种异常处理策略,分别如下:

  • NOOP:表示在异常发生后,不处理异常,继续工作
  • THROW:表示在异常发生后,直接抛出异常,这样会使服务停止
  • RETRY:表示在异常发生后,进行重试,相应地,需要定义重试次数,来避免无限重试情况的发生

基于以上三种异常处理策略,sink插件相关的实现类如下:

/*
 *  Copyright 2017 Datamountaineer.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.datamountaineer.streamreactor.connect.errors

import java.util.Date

import com.datamountaineer.streamreactor.connect.errors.ErrorPolicyEnum.ErrorPolicyEnum
import com.typesafe.scalalogging.slf4j.StrictLogging
import org.apache.kafka.connect.errors.RetriableException

/**
  * Created by andrew@datamountaineer.com on 19/05/16. 
  * kafka-connect-common
  */
object ErrorPolicyEnum extends Enumeration {
  type ErrorPolicyEnum = Value
  val NOOP, THROW, RETRY = Value
}

case class ErrorTracker(retries: Int, maxRetries: Int, lastErrorMessage: String, lastErrorTimestamp: Date, policy: ErrorPolicy)

trait ErrorPolicy extends StrictLogging {
  def handle(error: Throwable, sink: Boolean = true, retryCount: Int = 0)
}

object ErrorPolicy extends StrictLogging {
  def apply(policy: ErrorPolicyEnum): ErrorPolicy = {
    policy match {
      case ErrorPolicyEnum.NOOP => NoopErrorPolicy()
      case ErrorPolicyEnum.THROW => ThrowErrorPolicy()
      case ErrorPolicyEnum.RETRY => RetryErrorPolicy()
    }
  }
}

/**
 * 不处理异常策略
 */
case class NoopErrorPolicy() extends ErrorPolicy {
  override def handle(error: Throwable, sink: Boolean = true, retryCount: Int = 0){
    logger.warn(s"Error policy NOOP: ${error.getMessage}. Processing continuing.")
  }
}

/**
 * 异常抛出处理策略
 */
case class ThrowErrorPolicy() extends ErrorPolicy {
  override def handle(error: Throwable, sink: Boolean = true, retryCount: Int = 0){
    throw new RuntimeException(error)
  }
}

/**
 * 异常重试处理策略
 */
case class RetryErrorPolicy() extends ErrorPolicy {

  override def handle(error: Throwable, sink: Boolean = true, retryCount: Int) = {
    if (retryCount == 0) {
      throw new RuntimeException(error)
    }
    else {
      logger.warn(s"Error policy set to RETRY. Remaining attempts $retryCount")
      throw new RetriableException(error)
    }
  }
}

四、总结

基于kafka-connect实现相关数据同步插件时,应该尽可能地利用Kafka的topic信息,并对异常进行适当地处理,这样才可以保证插件的可扩展、高可用。

Kafka核心原理与大数据架构实践指南 分布式消息系统作为现代数据架构的中枢神经,通过解耦生产消费关系实现系统弹性扩展。Kafka凭借其分布式提交日志的设计原理,将传统消息队列的吞吐量提升至百万级TPS,同时提供消息持久化和回溯能力,成为流式数据处理的基础设施。在技术实现上,分区机制和零拷贝传输保障了水平扩展性与网络效率,顺序写入则最大化磁盘I/O性能。这些特性使Kafka在金融实时风控、电商推荐系统等场景展现巨大价值,能够处理10亿级日消息量。与Flink、Spark等计算引擎的深度集成,更使其成为Lambda架构中连接实时与离线处理的关键组件 阅读详情

相关推荐

超越DataX:实时数据同步方案深度对比与选型指南

数据同步是构建数据仓库、实现业务解耦和实时分析的基础技术,其核心在于将数据从源端稳定高效地迁移到目标端。传统批处理工具在应对海量数据和实时性要求时面临性能瓶颈与运维挑战。随着技术演进,基于分布式计算和变更数据捕获(CDC)的流式架构成为解决高吞吐、低延迟同步需求的关键。这些技术通过解耦数据生产与消费、支持水平扩展,为实时监控、风控等场景提供了毫秒级数据新鲜度保障。本文聚焦Apache SeaTunnel、Apache InLong及Debezium+Kafka Connect等方案,深入解析其架构差异与适用

weixin_33853794的博客 536

日志数据从kafka到hive是如何实现的

http://www.aboutyun.com/forum.php?mod=viewthread&tid=20701 背景 公司的系统是一个对外提供服务的接口,每一次调用日志都需要保存到hive中,以便后期做数据分析。每天的调用量在亿级,日志数据量100G以上,在量级还没有这么大的时候,采取的办法比较原始:直接通过log4j打印到日志文件,然后通过抽数工具同步到hive中,每天凌晨同步前一

大数据技术杂谈 9170

Kafka从消息队列到数据中枢:核心原理、应用场景与实战指南

消息队列作为分布式系统解耦与异步通信的核心组件,其核心原理在于通过发布-订阅或点对点模式实现应用间的可靠数据传递。在技术演进中,传统消息队列逐渐演变为高吞吐、可持久化的流数据平台,这一转变带来了巨大的技术价值——它不仅解决了系统间的通信问题,更成为实时数据管道和流式应用的基础设施。在应用场景上,这类技术广泛应用于日志收集、实时监控、事件驱动架构和大数据流处理等领域。以Apache Kafka为例,它通过分布式日志存储、零拷贝技术和消费者组模型,实现了从简单的消息传递到实时数据中枢的跨越,支撑着电商实时推荐、

weixin_34204722的博客 423

kafka-connect-hive sink插件入门指南

面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>> kafka-connect-hive是基于kafka-connect平台实现的hive数据读取和写入插件,主要由source、sink两部分组成,source部分完成hive表数据的读取任务,kafka-connect将这些数据写入到其他数据存储层中,比如hive到ES数据的流入。sink部分完成向hive表...

Viking的博客 2894

Kafka在MLOps中的核心作用:构建高可靠实时特征数据链路

消息队列是支撑现代机器学习工程化落地的关键基础设施,其本质是解决数据在训练与推理之间的时间一致性、格式可演化性及流量弹性问题。Kafka凭借分区有序日志、精确一次语义和Schema Registry治理能力,成为MLOps中事实标准的实时数据中枢。它不仅承载原始事件流,更驱动特征实时计算、模型服务解耦接入与反馈闭环监控,显著提升模型线上稳定性与迭代效率。本文聚焦Kafka在MLOps场景下的分层定位、Topic设计规范、Avro Schema治理及生产调优实践,覆盖从埋点采集到漂移告警的完整链路。

weixin_30251829的博客 620

现代数据工程师必掌握的5大核心大数据框架

大数据框架是构建可扩展、高可靠数据基础设施的基石。从分布式存储(HDFS)到实时消息管道(Kafka),再到批流一体计算引擎(Spark/Flink)和统一SQL层(Hive),这些技术共同定义了数据处理的底层语义与工程边界。其核心价值在于支撑PB级数据规模下的低延迟、强一致性与可运维性,广泛应用于实时推荐、用户行为分析、风控建模与电商大屏等关键场景。本文聚焦Apache Spark、Flink、Kafka、Hive和Hadoop五大工业级框架,深入解析其在真实生产环境中的关键配置、性能命门与典型故障模式,

dielucui7698的博客 602

Flume对接Hive(Sink)遇到的坑,以及最终放弃hive选用hdfs。欢迎讨论指点

项目中打算使用Flume把数据直接传到Hive表而不是HDFS上,使用Hive作为Sink,Flume版本为1.9.0。 前期启动遇到各种报错: NoClassDefFoundError: org/apache/hadoop/hive/ql/session/SessionState NoClassDefFoundError: org/apache/hadoop/hive/cli/CliSessionState NoClassDefFoundError: org/apache/hadoop/hive/

mathlpz126的博客 2355

【信息科学与工程学】【数据科学】第一百二十二篇 大数据产品中的函数与算法01

它通常指。下面按照你给出的表格列💡 说明:下表中的"产品"以开源/主流商业组件为具象载体(Hadoop、Spark、Flink、Kafka、Hive、HBase、Iceberg、Atlas、Ranger、TensorFlow 等),它们共同构成一个完整的大数据产品家族;代码为实现示例,用于说明算法在工程系统中的落地方式。

weixin_49199313的博客 197

通过 Kafka Connect 将 Kafka 主题中的数据导出到 Hive 是一种常见的数据集成模式

通过 Kafka Connect 将 Kafka 主题中的数据导出到 Hive 是一种常见的数据集成模式,它允许用户将实时数据流无缝地存储到 Hive 中,以便进行批处理和数据仓库操作。- 对于将数据从 Kafka 导出到 Hive,你需要配置 Connector 以从 Kafka 主题读取数据,并将其写入到 Hive 表中。通过这种方式,Kafka Connect 提供了一个强大而灵活的框架,允许你将实时数据流与数据仓库技术相结合,实现数据的实时分析和历史分析。

靡不有初,鲜克有终 596

HiveKa:Kafka 作为 Hive 存储

Kafka 的 Hive 存储处理程序 HiveKa 是 Apache Hive 的存储处理程序,它在 Apache Hive 中添加了从 Apache Kafka 查询数据的支持。 这为 Kafka 用户提供了一个机会来检查 Kafka 摄取的数据,而无需编写复杂的 Kafka 消费者。 Hive 使跨各种数据源(如 HDFS、Solr、Hbase 等)运行复杂的分析查询成为可能。HiveKa 将此支持扩展到 Kafka。 访问我们的。 要在 Hive 中创建 Kafka 表,请运行: create external table test_kafka (a int, b string) stored by 'org.apache.hadoop.hive.kafka.KafkaStorageHandler' tblproperties('kafka.service.uri'='hi

使用GEOquery包下载原始数据

使用GEOquery包下载原始数据

m0_75172651的博客 1887

kafka-connect-hive sink实现要点小结

  kafka-connect-hive sink插件实现了以ORC和Parquet两种方式向Hive表中写入数据。Connector定期从Kafka轮询数据并将其写入HDFS,来自每个Kafka主题的数据由提供的分区字段进行分区并划分为块,每个数据块都表示为一个HDFS文件,文件名由topic名称+分区编号+offset构成。如果配置中没有指定分区,则使用默认分区方式,每个数据块的大小由已写入H...

li123128的博客 992

采购订单定价策略 超详细

‘需求’字段里填写的是一个例程编号(例程是一段判断程序),如果我们在需求中维护了例程编号,那只有这个例程条件被满足时,这个条件表才会被系统自动读取。一部分的条件表只有在凭证项目满足一定的条件时才会被读取。 ‘排斥的’字段如果别勾中的话,那表明如果这个条件表被系统成功读取到数据后,系统将停止这个存取顺序的执行,否则,系统将继续执行下去。 注意:a、如果我们给某个条件类型设定了有效期的话,那我们必须给这个条件类型分配一个存取顺序。 b、不能给一个抬头条件分配存取顺序。 是...

竹大的博客 1万+

kafka-connect-hive Sink插件入门指南

  kafka-connect-hive是基于kafka-connect平台实现的hive数据读取和写入插件,主要由source、sink两部分组成,source部分完成hive表数据的读取任务,kafka-connect将这些数据写入到其他数据存储层中,比如hive到ES数据的流入。sink部分完成向hive表写数据的任务,kafka-connect将第三方数据源(如MySQL)里的数...

weixin_30278311的博客 308

一键转换B站M4S缓存为MP4:无需FFMPEG命令的简易工具

本文介绍了一款专为B站用户设计的绿色工具,可将缓存的M4S视频和音频文件一键转换为通用MP4格式。该工具完全图形化操作,无需学习复杂的FFmpeg命令,解决了普通用户处理B站缓存视频的痛点。文章详细讲解了从下载、配置到转换的完整流程,并提供了常见问题排查与安全使用建议,帮助用户高效、安全地管理离线视频内容。

joy55的博客 479

nvlddmkm事件ID14报错排查全指南:从找不到描述到显卡驱动崩溃

系统日志中的“无法找到描述”往往让人一头雾水,但这类提示其实隐藏着驱动故障的关键线索。Windows事件查看器通过事件源和ID记录系统异常,其中显卡驱动相关的内核模式驱动组件一旦超时失败,就会触发TDR机制,产生13、14、153等不同事件ID。理解这些ID的含义,比纠结“找不到描述”本身更重要。对于频繁出现的驱动崩溃问题,可以从日志频率和发生场景判断方向,再通过安全模式下彻底清理驱动、关闭冲突软件、检查供电和温度等步骤逐层定位。无论是游戏满载黑屏,还是睡眠唤醒后闪退,掌握NVIDIA驱动日志的解读逻辑,都

weixin_30545945的博客 406

Kafka Connect相关插件配置文档

Kafka Connect相关插件配置文档 文章目录Kafka Connect相关插件配置文档前言一、HDFS 2 Sink 插件1.1主要功能点1.2 环境准备1.3 HDFS 2 Sink 安装1.4 快速开始1.5 HDFS 2连接器配置选项1.5.1 HDFS1.5.2 安全1.5.3 连接器1.5.4 存储1.5.5 分区器1.5.6 Hive1.5.7 Schema1.6 格式和分区1.7 蜂巢整合1.8 安全的HDFS和Hive Metastore1.9 模式演变二 、JDBC Source

Tu_maimes 1797

基于单片机直流电机调速控制系统设计

*单片机设计介绍,基于单片机直流电机调速控制系统设计。

2201_75940997的博客 2779

Kafka零ETL写入Iceberg:从数据管道到数据直通车的架构演进与实践

在实时数据集成领域,数据管道是连接消息队列与数据存储的核心组件,其设计直接影响数据处理的时效性与运维复杂度。传统基于Flink或Spark Streaming的ETL链路,虽能实现数据流转,但常伴随开发运维成本高、数据延迟与端到端一致性难保证等挑战。其技术价值在于通过简化架构,降低运维负担,提升数据入湖效率。具体原理是借助Kafka Connect框架与Iceberg Sink Connector,将Kafka中的消息自动解析、映射并写入Iceberg表,实现近乎实时的结构化数据同步。这一方案尤其适用于日志

快马扬鞭须努力! 349

【VoxCPM2】在Windows上从零搭建VoxCPM2 语音生成和语音克隆AI算法

建议你了解清楚VoxCPM2,再来考虑是否需要自己在本地搭建。

AnChenliang_1002的博客 750

Ubuntu22.04安装ros(一键搞定)

然后发现可以一键安装,话不多说,直接终端输入如下指令。回车之后系统会自动安装ros。

m0_47313541的博客 7413

30.kafka数据同步Elasticsearch深入详解(ES与Kafka同步)

1、kafka同步到Elasticsearch方式?目前已知常用的方式有四种: 1)logstash_input_kafka插件; 缺点:不稳定(ES中文社区讨论) 2)spark stream同步; 缺点:太庞大 3)kafka connector同步; 4)自写程序读取、解析、写入  本文主要基于kafka connector实现kafka到Elasticsearch全量、增量同步。2、从co...

zkf541076398的博客 1万+

手把手教你学simulink实例--基于Simulink的储能系统性能评估与仿真

储能系统是现代能源体系中的关键组成部分,广泛应用于可再生能源并网、电网调峰调频、电力质量改善以及电动汽车充电等领域。为了提高储能系统的运行效率和可靠性,对其性能进行准确评估至关重要。基于MATLAB/Simulink平台,可以构建储能系统的动态模型,并通过仿真分析其在不同工况下的性能表现。本项目旨在研究储能系统的建模方法、控制策略及其性能评估指标,并通过Simulink仿真验证系统的动态特性和稳态性能。

MHD0815的博客 194
上一篇: kafka-connect-hive sink插件入门指南
下一篇: Hadoop NameNode、DataNode热迁移方案
Viking_bird
博客等级 码龄11年 92粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值