ビッグデータの一般的なリアルタイム ストリーム処理方法 (Kafka+SparkStream または ETL+Kudu)

この 2 日間でプロジェクトを終了したところですが、プロジェクト終了後にそのプロジェクトを要約してレビューする習慣があります。

たまたまこの 2 日間何もすることがなかったので、プロジェクトの具体化とも言えるデモをプロジェクトに沿って作成しました。

1. プロジェクトのプロセス

プロジェクトの核心:リアルタイムデータストリームの従来の処理方法を示す

全体的なプロセス:
フローチャート

プロジェクトのプロセスを計画したら、それを分割して一つずつ実現していきます。


次に、シミュレーション データが UDP に送信されます。

UDPは、参照モデルにおけるコネクションレス型のトランスポート層プロトコルであり、主にパケットの連続到着を必要としない伝送に使用され、パケットの送信順序の検査や仕分けはアプリケーション層で完結するため、シンプルかつ信頼性の低いトランザクションを提供するを中心とした情報発信サービス。

SCADA (Supervisory Control And Data Acquisition) システム、つまりデータ収集および監視制御システム。SCADA システムは、コンピュータベースの DCS および電力自動化監視システムであり、幅広い用途があり、電力、冶金、石油、化学産業におけるデータ収集、監視制御、プロセス制御などの多くの分野で使用できます。 、ガス、鉄道、その他の分野。

UDP は Scada システムに特定のアプリケーションを備えているため、リアルタイム データ フローの一部として使用することもできます (指定されたポートに物理デバイスを送信し、基盤となるストレージがポートをリッスンしてデータを取得するなど) )。

データを作成するだけでなく、モデルを作成することもできます〜
時間、日付、ID、名前、値の 5 つの列を
設計しましたこのうち、時間は秒まで正確、日付は日付 (yyyy-mm-dd)、id Incremental int 型で、値はランダムな値によって生成されます。

これについて少し考えてみると、複雑さを軽減し、読みやすさを向上させるために、3 つのクラスまたはメソッドに分割できることがわかります。
彼らです:

  • 形式の日付クラス
  • ランダム値クラスを取得する
  • UDPクラスに送信

1.日付クラスのフォーマット

主な目的は、現在のタイムスタンプを取得し、それを第 2 レベルのデータと日付レベルのデータに変換することです。main メソッドは出力されるため、省略できます。

package com.example.utils;
import java.text.SimpleDateFormat;
public class TimeStampFormat {
    
    
    // 获取时间戳
    private Long timestamp = System.currentTimeMillis();
    // 时间戳转时间
    public String getTime() {
    
    
        SimpleDateFormat formatTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return formatTime.format(timestamp);
    }
    // 时间转日期
    public String getDate() {
    
    
        SimpleDateFormat formatTime = new SimpleDateFormat("yyyy-MM-dd");
        return formatTime.format(timestamp);
    }
    public static void main(String[] args) {
    
    
        String time = new TimeStampFormat().getTime();
        String date = new TimeStampFormat().getDate();
        System.out.println(time);
        System.out.println(date);
    }
}

2. 乱数値クラスの取得

getInt メソッドは、後で名前を作成するときにランダムな名前を取得するために使用され、姓と名の配列が存在します。

package com.example.utils;

public class GetRandom {
    
    
    // 获取一个随机数
    private double random = Math.random();

    // 随机数转整数,用于当索引下标
    public int getInt() {
    
    
        return (int)(random * 10);
    }

    // 随机数转固定位小数(6位)
    public Double getDouble() {
    
    
        return Double.valueOf(String.format("%.6f",random * 100));
    }

    public static void main(String[] args) {
    
    
        System.out.println(new GetRandom().getInt());
        System.out.println(new GetRandom().getDouble());
        System.out.println(new GetRandom().random);
    }
}

3. UDPクラスに送信

最初は送信メソッドが main に直接書き込まれていましたが、依然としてメソッドに描画されており、より直感的です。

ヒント: この送信メソッドには基本的に 2 つの新規があり、1 つは送信、もう 1 つはクローズです。リソースの占有と消費は比較的大きくなりますが、実際には、Java でオブジェクトを作成するコストを削減する方法を変更できます。

package com.example.service;

import com.example.utils.GetRandom;
import com.example.utils.TimeStampFormat;

import java.io.IOException;
import java.net.*;
import java.util.concurrent.TimeUnit;


public class SendToUDP {
    
    
    // IP
    private static String IP = "10.168.1.xx";
//    private static String IP = "127.0.0.1";

    // port
    private static String PORT = "3927";

    private static void send(byte[] sendValue) throws SocketException, UnknownHostException {
    
    
        // 创建socket对象
        DatagramSocket ds = new DatagramSocket();

        // 打包数据
        DatagramPacket datagramPacket = new DatagramPacket(sendValue, sendValue.length, InetAddress.getByName(IP), Integer.parseInt(PORT));

        // send
        try {
    
    
            ds.send(datagramPacket);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            ds.close();
        }
    }

    public static void main(String[] args) throws InterruptedException, SocketException, UnknownHostException {
    
    
        // 创建数据  1 时间戳;2 时间;3 ID;4 Name ;5 Values;
        int i = 0;
        String[] surNameList = "李、王、张、刘、陈、杨、赵、黄、周、吴".split("、");
        String[] nameList = "梦琪、忆柳、之桃、慕青、问兰、尔岚、元香、初夏、沛菡、傲珊".split("、");

        while (true) {
    
     // 一直发送数据
            TimeStampFormat ts = new TimeStampFormat();
            GetRandom rd = new GetRandom();

            // 1 time
            String time = ts.getTime();

            // 2 date
            String date = ts.getDate();

            // 3 id
            i ++ ;

            // 4 Name  name = surNameList[i] + nameList[index]
            String name = surNameList[rd.getInt()] + nameList[rd.getInt()];

            // 5 values
            Double doubleValues = rd.getDouble();

            // 拼接数据
            byte[] sendValue = String.format("%s,%s,%s,%s,%s", time, date, i, name, doubleValues).getBytes();

            System.out.println(String.format("%s,%s,%s,%s,%s", time, date, i, name, doubleValues));

            send(sendValue);
            // 休眠1纳秒再发送
            TimeUnit.NANOSECONDS.sleep(1);
        }
    }
}

実行結果:
UDPに送信する

3. UDP を解析して Kafka に送信します。

この部分は比較的単純で、Kafka プロデューサーを直接構成し、受信した UDP パケットをカンマ区切り形式に解析して、Kafka に送信します。

1. Kafka ヘルパー クラス

package com.example.utils;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;


import java.util.Properties;

public class KafkaUtils {
    
    
    public Producer getProducer() {
    
    
        // 实例化配置类
        Properties props = new Properties();
        //集群地址,多个服务器用","分隔
        props.put("bootstrap.servers", "10.168.1.xx:9092");
        //key、value的序列化,此处以字符串为例,使用kafka已有的序列化类
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        //props.put("partitioner.class", "com.kafka.demo.Partitioner");//分区操作,此处未写
        props.put("request.required.acks", "1");

        Producer<String, String> kafkaProducer = new KafkaProducer<String, String>(props);

        return kafkaProducer;
    }

    public void closeRes(Producer kafkaProducer) {
    
    
        if (kafkaProducer != null) {
    
    
            try {
    
    
                kafkaProducer.close();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

2. UDP を解析して Kafka に送信する

package com.example.dao;

import com.example.utils.KafkaUtils;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveUDPSendToKafka {
    
    
    public static void main(String[] args) throws IOException {
    
    
        Logger.getLogger("org").setLevel(Level.INFO);
        // 定义一个接收端
        DatagramSocket ds = new DatagramSocket(3927);

        // 获取Kafka配置
        Producer producer = new KafkaUtils().getProducer();

        while (true) {
    
    
            // 接收数据
            byte[] bytes = new byte[1024];
            // dp
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            ds.receive(dp);

            // 解析
            byte[] data = dp.getData();
            int length = dp.getLength();

            //输出
            String outData = new String(data, 0, length);
//            System.out.println(outData);

            // key
            String key = outData.split(",")[2];

            // ProducerRecord 这里需要三个参数,第一个:topic的名称,第二个参数:表示消息的key,第三个参数:消息具体内容
            try {
    
    
                producer.send(new ProducerRecord<String, String>("demoTopic", key, outData));
                System.out.println("发送成功:" + outData);
            } catch (Exception e) {
    
    
                try {
    
    
                    new KafkaUtils().closeRes(producer);
                } catch (Exception e1) {
    
    
                    e.printStackTrace();
                }
            }
        }
    }
}

ヒント: この監視は... IP を指定できないようです? したがって、これを実行したい場合は、UDP に送信するアドレスをローカル マシンに変更するか、UDP を解析するプログラムをパッケージ化して、UDP を送信する IP サーバー上で実行する必要があります。

実行中の効果: Kafka 上でコンシューマー ビューを直接シミュレートします。
カフカ

4. SDC は Kafka を解析し、Kudu に書き込みます

StreamSets Data Collector (SDC) は、現在最も先進的なビジュアル データ収集構成ツールであり、バッチ データ収集とランディングなしのデータ ETL を考慮したリアルタイム データ収集に非常に適しています。Flume、Logstash、Sqoop、Canal などの前世代のデータ収集ツールを使用している場合は、アップグレードの代替として SDC を使用することをお勧めします。

Apache Kudu は、急速に変化するデータに対する高速分析を簡単に実行できるオープンソースの分散データ ストレージ エンジンです。OLAD と OLTP の両方を考慮してください。

どちらの種類のデータについても、ETL を使用することを検討します。

  • データソースはたくさんあります。たとえば、MySQL 内のすべてのデータベースのデータをビッグ データ プラットフォームに移行する必要があります。
  • データは構造化データに処理されており、リアルタイム要件は第 2 レベルにあり、サーバー リソースは豊富です。

前者の場合は、データが多すぎるため、コードを書くとバージョンが多くなったり、スクリプトを実行する必要があるため、ETL ; One を使用してマスターすることを検討しますが、多くのリソースを消費します

ヒント: Planting Grass は中国語の Web サイトで、非常に使いやすく、非常に包括的です。
StreamSets 中国語サイト: リンク: http://streamsets.vip/

この部分では主に ETL を使用してデータを処理します。ビジュアル ETL は SDC、NIFI に加えて、非ビジュアル ETL は Sqoop と Flume を考慮できます。

1. データソース

入力ソース

2. プロセッサー

Kafka のデータはカンマで区切られているため、カンマを直接区切り文字として使用し、列名をバインドします。
プロセッサー

3. 出力ソース

まず kudu テーブルを作成します。

CREATE TABLE kafka_to_kudu(
id int,
point_date STRING,
point_time STRING,
name STRING,
value DOUBLE,
PRIMARY KEY (id,point_date))
PARTITION BY HASH (id) PARTITIONS 10,
RANGE (point_date) (
    PARTITION "2021-07-19" <= VALUES < "2021-07-19\000",
    PARTITION "2021-07-20" <= VALUES < "2021-07-20\000",
    PARTITION "2021-07-21" <= VALUES < "2021-07-21\000",
    PARTITION "2021-07-22" <= VALUES < "2021-07-22\000",
    PARTITION "2021-07-23" <= VALUES < "2021-07-23\000",
    PARTITION "2021-07-24" <= VALUES < "2021-07-24\000",)
STORED AS KUDU
TBLPROPERTIES ('kudu.master_addresses'='10.168.1.12:7051');

impalaで作成したkuduテーブルです Impala+Kuduはメモリを大量に消費します(私はCDHを直接インストールしました) 条件が許せない場合はhiveに直接書き込むことを推奨します。

出力ソース構成:
出力ソース

実行効果 (IDEA が今実行し、UDP にメッセージを送信したため、エラー レポートが表示されます。その後、サーバー上に配置されたプログラムが解析されて kafka に送信され、SDC 解析によって kudu に書き込まれますが、 kudu の ID はすでに存在するため、エラーが報告されます...):
実行結果

4. パーティションを自動的に作成する

レンジャー パーティションは 24 番目までしか到達せず、24 番目を超えるデータは挿入できません。新しいスクリプトを作成して定期的に実行できます。
スクリプト: 毎日 3 日後に新しいパーティションを作成する

#!bin/bash
add=$(date -d +3day "+%Y-%m-%d")
nohup impala-shell -q "alter table default.kafka_to_kudu  add range partition '${add}' <= VALUES < '${add}\000'" >> /dev/null &

タイミングタスク: 1 日 1 回実行

0 1 * * * sh /root/kudutool/kuduParitition.sh &

5. Spark Streaming は Kafka を解析し、Kudu に書き込みます

この部分が核となる内容で、StreamingContextを作成し、Kafkaを受け取り、受け取ったデータをDFに変換し、ネイティブAPIを使用して保存するのが主な処理です。

package com.example.dao

import java.lang

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructField
import org.apache.spark.sql.types.DataTypes
import org.apache.log4j.{
    
    Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.sql.{
    
    Row, SparkSession}
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka010.{
    
    ConsumerStrategies, KafkaUtils, LocationStrategies}
import org.apache.spark.streaming.{
    
    Seconds, StreamingContext}

object Kafka_To_Kudu {
    
    
  Logger.getLogger("org").setLevel(Level.WARN)

  def getSparkSess(): StreamingContext = {
    
    
    val ssc = new StreamingContext(new SparkConf().setMaster("local[*]").setAppName("Kafka_To_Kudu")
      // 不加这个set,会报错:对象不可序列化
      .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
      , Seconds(1))

    // checkpoint
    ssc.checkpoint("hdfs://10.168.1.xx/data/spark/checkpoint/kafka-to-kudu")
    // return
    ssc
  }

  def getKafkaConf(): Map[String, Object] = {
    
    
    val kafkaConfig = Map[String, Object](
      "bootstrap.servers" -> "10.168.1.13:9092"
      , "key.deserializer" -> classOf[StringDeserializer] // 指定序列化的方式
      , "value.deserializer" -> classOf[StringDeserializer] // 指定反序列化方式
      , "group.id" -> "group01"
      // 指定消费位置
      , "auto.offset.reset" -> "latest"
      // 提交方式  true :自动提交
      , "enable.auto.commit" -> (true: lang.Boolean)
    )
    kafkaConfig
  }

  def main(args: Array[String]): Unit = {
    
    
    val topic = Array("demoTopic")
    val ssc = getSparkSess()

    // 配置消费
    val streams: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream(
      ssc, LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe(topic, getKafkaConf())
    )

    // insert kudu
    // 先转为DF,不然不能保存
    streams.foreachRDD {
    
     rdd =>
      // get ss
      val ss = SparkSession.builder().config(rdd.sparkContext.getConf).getOrCreate()
      // 处理
      val value = rdd.map(_.value().split(",")).map(x => // 动态编码
        Row(x(2).trim.toInt, x(1), x(0), x(3), x(4).trim.toDouble))
      //        .toDF("time", "date", "id", "name", "value")  // Bean + 反射,略

      val schema = StructType(List(
        StructField("id", DataTypes.IntegerType, false),
        StructField("point_date", DataTypes.StringType, false),
        StructField("point_time", DataTypes.StringType, false),
        StructField("name", DataTypes.StringType, false),
        StructField("value", DataTypes.DoubleType, false)
      ))

      // 绑定
      val frame = ss.createDataFrame(value, schema)

      // frame.printSchema()
      // frame.show()

      // 保存
      try {
    
    
        frame.write.options(Map("kudu.master" -> "10.168.1.xx"
          , "kudu.table" -> "impala::default.spark_to_kudu"))
          .mode("append")
          .format("org.apache.kudu.spark.kudu")
          .save()
        println("保存成功" + frame)
      } catch {
    
    
        case e: Exception => {
    
    
          try {
    
    
            ss.stop()
          } catch {
    
    
            case e1: Exception => {
    
    
              e1.printStackTrace()
            }
          }
          e.printStackTrace()
        }
      }
    }

    // start
    ssc.start()
    ssc.awaitTermination()
  }
}

メイブン:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ScalaSparkStremingConsumerKafka</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <scala.version>2.11.12</scala.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
            <version>2.4.4</version>
        </dependency>

        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.1.0-cdh6.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.4.0-cdh6.3.1</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17-cloudera1</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.4.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.example.dao.Kafka_To_Kudu</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

上記のkuduテーブル作成ステートメントに従って、kuduに新しいspark_to_kuduを作成します

このチェックポイントは、Kafka によって消費されるオフセットを記録するために使用され、作成する必要があり、アクセス許可は 777 に変更されます。

実行結果:
実行結果

カウント

6、StructuredStreaming 処理を使用する

2021-07-27に追加されました。
コード:

package com.example.dao

import org.apache.log4j.{
    
    Level, Logger}
import org.apache.spark.sql.streaming.Trigger
import org.apache.spark.sql.types.{
    
    DataTypes, StructField, StructType}
import org.apache.spark.sql.{
    
    DataFrame, Row, SaveMode, SparkSession}

object Kafka_To_Kudu_Structured {
    
    
  Logger.getLogger("org").setLevel(Level.ERROR)

  def getSparkSess(): SparkSession = {
    
    
    val ss = SparkSession.builder().master("local[*]")
      .appName("Kafka_To_Kudu_Structured").getOrCreate()
    ss
  }

  def loadKafkaSession(ss: SparkSession): DataFrame = {
    
    
    val df = ss.readStream.format("kafka")
      .option("kafka.bootstrap.servers", "10.168.1.xx:9092") // boker server
      .option("subscribe", "demoTopic") // topic
      .option("startingOffsets", "latest") // 从最新的地方开始消费
      .load()
    df
  }

  def main(args: Array[String]): Unit = {
    
    
    val ss = getSparkSess()
    val df = loadKafkaSession(ss)

    // 隐式转换
    import ss.implicits._

    // 输出测试
    /*    df.selectExpr("CAST(value AS STRING)").as[String]
          .writeStream.outputMode("append").format("console")
          .trigger(Trigger.ProcessingTime(0L))
          .option("checkpointLocation","hdfs://10.168.1.12:8020/data/spark_check_point")
          .option("truncate",false)
          .start()*/


    /**
     * 处理 + 保存到kudu
     * kudu表:structured_to_kudu
     * 因为structured不支持kudu,所以先输出到memory,然后再保存到Kudu
     * Tips1:如果数据过大,会造成内存溢出
     * Tips2:如果对数据没有处理(筛选、聚合),建议直接用SparkStreaming即可
     * Tips3:此处采用的是foreachBatch方式,批量保存到kudu...
     **/
    df.selectExpr("CAST(value AS STRING)").as[String]
      .map(line => {
    
    
        val arr: Array[String] = line.split(",")
        // 输出查看
        // println(arr(2).toInt, arr(1), arr(0), arr(3), arr(4).toDouble)
        (arr(2).toInt, arr(1), arr(0), arr(3), arr(4).toDouble)
      }).toDF("id", "point_date", "point_time", "name", "value")
      .writeStream.outputMode("append").foreachBatch((df, batchId) => {
    
     // 当前分区id, 当前批次id
      if (df.count() != 0) {
    
    
        df.cache() // 加载到内存,速度更快
        df.write.mode(SaveMode.Append).format("org.apache.kudu.spark.kudu")
          //设置master(ip地址)
          .option("kudu.master", "10.168.1.xx")
          //设置kudu表名
          .option("kudu.table", "impala::default.structured_to_kudu")
          //保存
          .save()
        println("保存成功!" + df)
      }
    })
      .trigger(Trigger.ProcessingTime(0L))
      .start()


    // run
    ss.streams.awaitAnyTermination()
  }
}

メイブン:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ScalaSparkStremingConsumerKafka</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <scala.version>2.11.12</scala.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
            <version>2.4.4</version>
        </dependency>

        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.1.0-cdh6.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.4.0-cdh6.3.1</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17-cloudera1</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.4.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.example.dao.Kafka_To_Kudu</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>



最後に...パッケージ化してサーバー上で実行するつもりですが...エラーが発生し続けます。

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44491709/article/details/119010253