SparkSQL读取Kudu,写出到Kafka

背景:通过spark SQL读kudu表,写入到kafka

参考:1.spark向kafka写入数据 2.通过Spark向Kafka写入数据

1. pom.xml 依赖

    <dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency> <!-- scalikejdbc_2.11 -->
<dependency>
<groupId>org.scalikejdbc</groupId>
<artifactId>scalikejdbc_2.11</artifactId>
<version>2.5.0</version>
</dependency>
<!-- scalikejdbc-config_2.11 -->
<dependency>
<groupId>org.scalikejdbc</groupId>
<artifactId>scalikejdbc-config_2.11</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.1</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.0</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.3.0</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.3.0</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.kudu/kudu-client -->
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client</artifactId>
<version>1.9.0</version>
</dependency>
<!--spark集成kudu-->
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-spark2_2.11</artifactId>
<version>1.9.0</version>
</dependency> <!--执行sql脚本-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--读取配置-->
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.8</version>
</dependency> <!--clickhouse-->
<dependency>
<groupId>cc.blynk.clickhouse</groupId>
<artifactId>clickhouse4j</artifactId>
<version>1.4.4</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency> <!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--kafka-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 这是个编译scala代码的 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin> <!-- 这是个编译java代码的 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<!--注意这里使用jdk8,否则不能使用java8的lambda表达式和流API-->
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin> <!--maven-assembly-plugin不能打包spring Framework框架的项目,
可以使用maven-shade-plugin插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>com.tal.mysql2kudu.MysqlToKudu_v1</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

2.将KafkaProducer利用lazy val的方式进行包装, 创建KafkaSink

package com.tal.spark

import java.util.concurrent.Future
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord, RecordMetadata} class KafkaSink[K, V](createProducer: () => KafkaProducer[K, V]) extends Serializable {
/* This is the key idea that allows us to work around running into
NotSerializableExceptions. */
lazy val producer = createProducer() def send(topic: String, key: K, value: V): Future[RecordMetadata] =
producer.send(new ProducerRecord[K, V](topic, key, value)) def send(topic: String, value: V): Future[RecordMetadata] =
producer.send(new ProducerRecord[K, V](topic, value)) def send(topic: String, partition: Int, key: K, value: V): Future[RecordMetadata] =
producer.send(new ProducerRecord[K, V](topic, partition, key, value))
} object KafkaSink { import scala.collection.JavaConversions._ def apply[K, V](config: Map[String, Object]): KafkaSink[K, V] = {
val createProducerFunc = () => {
val producer = new KafkaProducer[K, V](config)
sys.addShutdownHook {
// Ensure that, on executor JVM shutdown, the Kafka producer sends
// any buffered messages to Kafka before shutting down.
println("KafkaSink close producer")
producer.close()
}
producer
}
new KafkaSink(createProducerFunc)
} def apply[K, V](config: java.util.Properties): KafkaSink[K, V] = apply(config.toMap)
}

3.利用广播变量,将KafkaProducer广播到每一个executor

完整代码

package com.tal.spark

import java.util.Properties
import com.alibaba.fastjson.JSONObject
import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.common.serialization.StringSerializer
import org.apache.spark.broadcast.Broadcast
import org.apache.spark.sql.{DataFrame, SparkSession}
import org.slf4j.{Logger, LoggerFactory} /**
* @description: TODO 读kudu写入kafka
* @author: HaoWu
* @create: 2021年06月30日
*/
object Kudu2Kafka {
private val logger: Logger = LoggerFactory.getLogger(Kudu2Kafka.getClass)
//kudu配置信息
private val kuduMaster = "hadoop101:7051"
//private val kuduTableName1 = "impala::dwddb.rt_dwd_rm_distribution_res_data_detail_new"
private val kuduTableName = "person" //kafka 配置信息
private val bootstrapServers = "hadoop102:9092"
private val topic = "kudu_to_kafka_test"
val schema = Array("id", "CompanyId", "WorkId", "Name", "Gender", "Photo") def main(args: Array[String]): Unit = { // 构建SparkSession
/* val spark: SparkSession = SparkSession
.builder()
.config("spark.default.parallelism", 200)
.config("spark.shuffle.file.buffer", "128k")
.config("spark.reducer.maxSizeInFlight", "96m")
.config("spark.shuffle.memoryFraction", 0.3)
.config("spark.storage.memoryFraction", 0.3)
.enableHiveSupport()
.getOrCreate()*/
//1. 构建SparkSession实例对象
val spark: SparkSession = SparkSession.builder()
.master("local[2]")
.config("spark.sql.shuffle.partitions", "2")
.config("spark.default.parallelism", 200)
.config("spark.shuffle.file.buffer", "128k")
.config("spark.reducer.maxSizeInFlight", "96m")
.config("spark.shuffle.memoryFraction", 0.3)
.config("spark.storage.memoryFraction", 0.3)
.getOrCreate() logger.info("加载kudu数据~~")
val time1 = System.currentTimeMillis()
val result: DataFrame = getKuduData(spark, kuduMaster, kuduTableName)
val time2 = System.currentTimeMillis()
val time = time2 - time1
logger.info("加载完成~~~:耗时:" + time + " ms!") logger.info("数据开始发送到kafka")
write2Kafka(result, spark, 3,bootstrapServers,topic)
logger.info("-----> 数据发送到kafka完成完成!!! <-------") spark.stop()
} /**
* TODO 获取 kudu DF
*
* @param spark
* @param kuduMaster
* @param kuduTableName
*/
def getKuduData(spark: SparkSession, kuduMaster: String, kuduTableName: String): DataFrame = {
import spark.implicits._
// 1. 定义 map 集合,封装 kudu的master地址.表名
val options = Map(
"kudu.master" -> kuduMaster,
"kudu.table" -> kuduTableName,
// 200M
"kudu.batchSize" -> "419430400",
// 10G
"kudu.splitSizeBytes" -> "10737418240",
"kudu.keepAlivePeriodMs" -> "36000000",
"kudu.scanRequestTimeoutMs" -> "36000000",
"kudu.faultTolerantScan" -> "true",
"kudu.scanLocality" -> "leader_only" // 设置, 否则可能出现scanner not found异常
)
// 2. 从Kudu表加载数据
val kuduDF: DataFrame = spark.read
.format("kudu")
.options(options)
.load()
//打印
// kuduDF.printSchema()
// kuduDF.show(10, truncate = false)
val tempView = "person"
kuduDF.createOrReplaceTempView(tempView)
val sql =
s"""
|select
| row_number() over(order by CompanyId) as id,
| CompanyId,
| WorkId,
| Name,
| Gender,
| Photo
|from ${tempView}
|""".stripMargin
val result: DataFrame = spark.sql(sql)
result
} /**
* TODO 写出 kafka
*
* @param result
* @param spark
* @param numPartitions
*/
def write2Kafka(result: DataFrame, spark: SparkSession, numPartitions: Int,bootstrapServers:String,topic:String): Unit = { // 广播KafkaSink
val kafkaProducer: Broadcast[KafkaSink[String, String]] = {
val kafkaProducerConfig = {
val p = new Properties()
p.setProperty("bootstrap.servers",bootstrapServers)
p.setProperty("key.serializer", classOf[StringSerializer].getName)
p.setProperty("value.serializer", classOf[StringSerializer].getName)
p
}
logger.warn("kafka producer init done!")
spark.sparkContext.broadcast(KafkaSink[String, String](kafkaProducerConfig))
} //输出到kafka
try {
result.foreach(
row => {
val jsonObj = new JSONObject()
schema.foreach(field => {
val fieldKey = field
val fieldValue = row.getAs[Any](fieldKey)
jsonObj.put(fieldKey, fieldValue)
})
kafkaProducer.value.send(topic,jsonObj.toString)
})
} catch {
case ex:Exception =>
logger.error("写入kafka异常,异常为:"+ex)
throw ex
}
}
}

Spark(二十一)【SparkSQL读取Kudu,写入Kafka】的更多相关文章

  1. storm集成kafka的应用,从kafka读取,写入kafka

    storm集成kafka的应用,从kafka读取,写入kafka by 小闪电 0前言 storm的主要作用是进行流式的实时计算,对于一直产生的数据流处理是非常迅速的,然而大部分数据并不是均匀的数据流 ...

  2. 金融量化分析【day110】:Pandas-DataFrame读取与写入

    一.DataFrame DataFrame是一个表格型的数据结构,含有一组有序的列 DataFrame可以被看作是有Series组成的字典并且工用一个索引 1.创建方式 pd.DataFrame({' ...

  3. Flume 读取RabbitMq消息队列消息,并将消息写入kafka

    首先是关于flume的基础介绍 组件名称 功能介绍 Agent代理 使用JVM 运行Flume.每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks. Client ...

  4. Spark学习之数据读取与保存总结(二)

    8.Hadoop输入输出格式 除了 Spark 封装的格式之外,也可以与任何 Hadoop 支持的格式交互.Spark 支持新旧两套Hadoop 文件 API,提供了很大的灵活性. 要使用新版的 Ha ...

  5. Kafka设计解析(二十一)关于Kafka幂等producer的讨论

    转载自 huxihx,原文链接 关于Kafka幂等producer的讨论 众所周知,Kafka 0.11.0.0版本正式支持精确一次处理语义(exactly once semantics,下称EOS) ...

  6. 构建一个flink程序,从kafka读取然后写入MYSQL

    最近flink已经变得比较流行了,所以大家要了解flink并且使用flink.现在最流行的实时计算应该就是flink了,它具有了流计算和批处理功能.它可以处理有界数据和无界数据,也就是可以处理永远生产 ...

  7. spark基础知识介绍(包含foreachPartition写入mysql)

    数据本地性 数据计算尽可能在数据所在的节点上运行,这样可以减少数据在网络上的传输,毕竟移动计算比移动数据代价小很多.进一步看,数据如果在运行节点的内存中,就能够进一步减少磁盘的I/O的传输.在spar ...

  8. 牢记!SQL Server数据库开发的二十一条注意点

    如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL  Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS). ...

  9. SQL Server数据库开发的二十一条军规

    如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS).在这 ...

随机推荐

  1. undefined reference to `recvIpcMsg(int, ipc_msg*)'——#ifdef __cplusplus extern "C" { #endif

    最近在弄一个进程间通信,原始测试demon用c语言写的,经过测试ok,然后把接口封装起来了一个send,一个recv. 使用的时候send端是在一个c语言写的http服务端使用,编译ok没有报错,但是 ...

  2. Java RMI学习与解读(三)

    Java RMI学习与解读(三) 写在前面 接下来这篇就是最感兴趣的Attack RMI部分了. 前面也说过,RMI的通信过程会用到反序列化,那么针对于RMI的三个角色: Server/Regisrt ...

  3. (转)刚来的大神彻底干掉了代码中的if else...

    一旦代码中 if-else 过多,就会大大的影响其可读性和可维护性. 首先可读性,不言而喻,过多的 if-else 代码和嵌套,会使阅读代码的人很难理解到底是什么意思.尤其是那些没有注释的代码. 其次 ...

  4. GO 字符串反转

    字符串反转 即 abc 反转后成 cba 思路:两边都设置一个游标,然后互换位置,游标同步向中间移动,再互换. for i, j := 0, len(s)-1; i < j; i, j = i+ ...

  5. k8s入坑之路(10)kubernetes coredns详解

    概述 作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,那么就需要一个集群范围内的DNS服务来完成从服务名到ClusterIP的解析. DNS服务在kubernetes中经历了三个 ...

  6. PTA 7-4 最小生成树的唯一性 (35分)

    PTA 7-4 最小生成树的唯一性 (35分) 给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一.本题就要求你计算最小生成树的总权重,并且判断其是否唯一. 输入格式: ...

  7. 藏书馆App基于Rainbond实现云原生DevOps的实践

    我们需要的不是精通Kubernetes的工程师,我们需要一款小白都能用好的管理工具. -- 厦门正观易知科技有限公司运维负责人 郭传壕 大家好,我是厦门正观易知科技有限公司运维负责人郭传壕. 藏书馆是 ...

  8. pm2 重启策略(restart strategies)

    使用 PM2 启动应用程序 时,应用程序会在自动退出.事件循环为空 (node.js) 或应用程序崩溃时自动重新启动. 但您也可以配置额外的重启策略,例如: 使用定时任务重新启动应用程序 文件更改后重 ...

  9. CentOS7部署ceph

    CEPH 简介 不管你是想为云平台提供Ceph 对象存储和/或 Ceph 块设备,还是想部署一个 Ceph 文件系统或者把 Ceph 作为他用,所有 Ceph 存储集群的部署都始于部署一个个 Ceph ...

  10. 【CSP2019 D1T2】【括号树】

    题面 不再多说,想必大家都看过这个题 思路 我们可以手推几个满足条件的字符串 我们发现在这些字符串里 每个)都与离它最近的(的匹配 所以我们维护树上每个节点到根节点中没用使用过的(的位置(nl[n]) ...