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. 在c中使用正则表达式

    今天学习编译原理的时候,用c写一个简易的文法识别器实验遇到了一个问题:要用正则表达式去识别正则文法里面的A->ω,A->Bω, 其中ω属于T的正闭包,也就是说我们对正则文法的产生式进行抽象 ...

  2. insertion-sort-list leetcode C++

    Sort a linked list using insertion sort. C++ /** * Definition for singly-linked list. * struct ListN ...

  3. cf Make It Nondeterministic (简单贪心)

    有N个人.每个人都有两个名字. 给出这N个人的一个排列.p[1]...p[N]. 现在让每个人挑自己丙个名字中的一个名字.问是否存在一种方案,使得挑出来的N个名字按字典序排完以后正好是p[1]...p ...

  4. Jmeter下载安装(一)

    一.JMeter介绍       JMeter使用了不同技术和协议,是一款可以进行配置和执行负载测试.性能测试和压力测试的工具.负载测试.性能测试和压力测试概念: 负载测试: 这类测试使系统或者应用程 ...

  5. eclipse查看jar包源代码

    方法一:将jd-gui集成在Eclipse中 https://jingyan.baidu.com/article/b24f6c8275536686bfe5daed.html    下载2个反编译文件, ...

  6. MySQL用limit代替SQL Server :top

    mysql 中不支持top,而是用limit代替 若要查询前10条记录,mysql用limit 10 LIMIT可以实现top N查询,也可以实现M至N(某一段)的记录查询,具体语法如下: SELEC ...

  7. [luogu7207]Sob

    为了方便,先将$n$减小1,即两者范围分别为$[0,n]$和$[m,m+n]$ 结论:取$u=\min_{i\in [m,m+n],n\& i=n}i$,则$\forall 0\le i\le ...

  8. littlevgl架构浅析

    一.   littlevgl有几个线程,作用是什么? 三个,主线程一个,和在主线程的hal_init函数中创建的另两个sdl线程. 主线程完成一系列初始化工作后,循环每10ms调用在lv_init函数 ...

  9. LifseaOS 悄然来袭,一款为云原生而生的 OS

    作者:黄韶宇.初扬 审核&校对:溪洋.海珠 编辑&排版:雯燕 LifseaOS 在刚刚过去的云栖大会上,一款新的 Linux Base 操作系统悄悄发布,它就是 LifseaOS(Li ...

  10. 6.K8s集群升级、etcd备份和恢复、资源对象及其yaml文件使用总结、常用维护命令

    1.K8s集群升级 集群升级有一定的风险,需充分测试验证后实施 集群升级需要停止服务,可以采用逐个节点滚动升级的方式 1.1 准备新版本二进制文件 查看现在的版本 root@k8-master1:~# ...