• 【spark】记录一次 spark sparkstreaming 使用命令行提交任务在Yarn集群模式无法正常消费kerberos kafka数据的问题


    前言

    最近在提交 spark 程序到 yarn 消费 kerberos 认证方式的 kafka 数据。由于配置文件 相对/绝对路径不正确配置 遇到了报错,这里整理并记录一下。

    环境信息

    • spark 2.4
    • hadoop 3.0
    • kafka 2.4

    问题原因:

    先提前说下问题的最终原因:由于 spark-submit 提交任务命令 kafka_client_jaas.conf配置文件 相对/绝对路径 不合理导致的。那么我原来的提交命令是什么

    问题复现:

    我们来重新复现下这个问题。之前用的错误的spark-submit 命令如下

    spark-submit 命令行

    spark-submit --class com.test.SparkTest \
    --principal "test@TEST.COM" \
    --keytab "/user/test/test.keytab" \
    --files "/etc/krb5.conf,/user/test/kafka_client_jaas.conf" \
    --conf "spark.driver.extraJavaOptions=-Djava.security.auth.login.config=kafka_client_jaas.conf" \
    --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=kafka_client_jaas.conf" \
    --conf "spark.driver.memoryOverhead=1024" \
    --conf "spark.executor.memoryOverhead=1024" \
    --master yarn \
    --deploy-mode cluster \
    --name SparkTestDemo \
    --driver-cores 1 \
    --driver-memory 1G \
    --executor-cores 1 \
    --executor-memory 1G \
    --queue test \
    --num-executors 1 \
    test-etl.jar
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里我用到如下几个配置文件:

    1. /etc/krb.conf
    2. kafka_client_jaas.conf
    3. test.keytab

    并且这几个配置文件需要在 driver 节点和 executor 节点上都需要有。

    kafka_client_jaas.conf

    KafkaClient {
       com.sun.security.auth.module.Krb5LoginModule required
       useKeyTab=true
       keyTab="/user/test/test.keytab"
       storeKey=true
       useTicketCache=false
       serviceName="kafka"
       principal="test@TEST.COM";
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    报错内容

    ERROR Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer)
    org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: Could not login: the client is being asked for a password, but the Kafka client code does not currently support obtaining a password from the user. not available to garner  authentication information from the user
            at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:160)
            at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:146)
            at org.apache.kafka.common.network.ChannelBuilders.serverChannelBuilder(ChannelBuilders.java:85)
            at kafka.network.Processor.<init>(SocketServer.scala:726)
            at kafka.network.SocketServer.newProcessor(SocketServer.scala:367)
            at kafka.network.SocketServer.$anonfun$addDataPlaneProcessors$1(SocketServer.scala:261)
            at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:158)
            at kafka.network.SocketServer.addDataPlaneProcessors(SocketServer.scala:260)
            at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1(SocketServer.scala:223)
            at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1$adapted(SocketServer.scala:220)
            at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
            at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
            at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
            at kafka.network.SocketServer.createDataPlaneAcceptorsAndProcessors(SocketServer.scala:220)
            at kafka.network.SocketServer.startup(SocketServer.scala:120)
            at kafka.server.KafkaServer.startup(KafkaServer.scala:255)
            at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:38)
            at kafka.Kafka$.main(Kafka.scala:84)
            at kafka.Kafka.main(Kafka.scala)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用 spark-local 模式

    我们使用 spark on yarn-cluster 任务无法执行,于是我们将任务改为 spark local[*] 模式,发现就没问题。

    问题解决

    经过问题定位终于发现是 kafka_client_jaas.confkeyTab="/user/test/test.keytab" 这一行的绝对路径导致的。

    因为: keytab文件配置文件是使用 YARN 资源分发。这些配置文件最终将位于 执行Spark YARN 容器的目录中,因此改行的内容应指定为相对路径 也就是 ./test.keytab

    另外如下的几个配置也需要改成相对路径

    --conf "spark.driver.extraJavaOptions=-Djava.security.auth.login.config=./kafka_client_jaas.conf"
    --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./kafka_client_jaas.conf"
    
    • 1
    • 2

    spark.driver.extraJavaOptionsspark.executor.extraJavaOptions 都需要改成相对路径。

    正确的kafka_client_jaas.conf

    KafkaClient {
       com.sun.security.auth.module.Krb5LoginModule required
       useKeyTab=true
       keyTab="./test.keytab"
       storeKey=true
       useTicketCache=false
       serviceName="kafka"
       principal="test@TEST.COM";
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里我们以为问题已经解决了,结果还是不行,后面经过查询我们还需要将keytab 文件也传递给 Yarn 服务。

    最终的spark-submit命令

    spark-submit \
    --class com.test.SparkTest \
    --principal "test@TEST.COM" \
    --keytab "/user/test/k-test.keytab" \
    --files "/etc/krb5.conf,/user/test/kafka_client_jaas.conf,/user/test/test.keytab" \
    --conf "spark.driver.extraJavaOptions=-Djava.security.auth.login.config=./kafka_client_jaas.conf -Djava.security.krb5.conf=/etc/krb5.conf" \
    --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./kafka_client_jaas.conf -Djava.security.krb5.conf=/etc/krb5.conf" \
    --conf "spark.driver.memoryOverhead=1024" \
    --conf "spark.executor.memoryOverhead=1024" \
    --master yarn \
    --deploy-mode cluster \
    --name SparkTestDemo \
    --driver-cores 1 \
    --driver-memory 1G \
    --executor-cores 1 \
    --executor-memory 1G \
    --num-executors 1 \
    --queue test \
    test-etl.jar
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    为了方便阅读,这里我将不同的地方贴出

    旧的命令行
    --keytab "/user/test/k-test.keytab"
    --files "/etc/krb5.conf,/user/test/kafka_client_jaas.conf"
    
    • 1
    • 2
    新的命令行
    --keytab "/user/test/k-test.keytab" 
    --files "/etc/krb5.conf,/user/rwms/kafka_client_jaas.conf,/user/test/test.keytab"
    
    • 1
    • 2

    注意:新的命令行 keytab “/user/test/k-test.keytab” 这个地方特别注意下,文件名字是不同的,但是文件内容是一致的,为什么要这么改,是因为当同时配置 --keytab “/user/test/test.keytab” 和 – files “/user/test/test.keytab” 会造成程序的异常退出。为了避免冲突,我们引入一个不同名但同根的keytab 文件即:k-test.keytab 和 test.keytab 但其实这俩文件没什么区别。

    举个例子:
    当spark提交任务时,yarn会将--keytab后面的keytab文件--files里的文件先后上传,即 hdfs.keytabrwms.keytab均会被上传,sparkkafka各取所需,即可正常工作。

    当spark与kafka要使用相同的keytab文件时,比如都用rwms.keytab,那么yarn会先后上传两次rwms.keytab,在spark正使用的时候更新了keytab,造成异常退出。

    下面列一下几种模式的不同:

    spark locol 模式
    在本地模式下,配置文件的相对/绝对路径,对程序没什么影响。

    spark-yarn-client 模式
    client 模式下,因为driver 端时在本地,本地的配置文件都有,所以spark.driver.extraJavaOptions 中的配置文件路径 相对/绝对 影响不大,spark.executor.extraJavaOptions 需要写成相对路径。

    spark-yarn-cluster 模式
    cluster模式下,driver 和 executor 节点都不在本地,所以配置文件都不存在,所以spark.driver.extraJavaOptions 需要写成相对路径,
    spark.executor.extraJavaOptions 需要写成相对路径。

    总结

    以上的问题,说白了就是在任务真正的执行节点,并没有成功从 绝对路径 中加载到对应的配置文件。

    我们在生产中将 jaas 配置文件和 keytab 作为本地资源文件传递。将 jaas 配置文件选项添加到为驱动程序和执行程序指定的 JVM 选项中

    因为别的节点并没有这些配置文件。所以需要用 --flies 将我们需要用到的配置都加载到yarn 服务上,然后 yarn 来将这些配置问价分发到真正执行任务的目录上。

    我们生产上使用的一些参数中指定的配置也最好写成相对路径。如:spark.driver.extraJavaOptionsspark.executor.extraJavaOptions

    参考

    • https://docs.cloudera.com/HDPDocuments/HDP2/HDP-2.4.3/bk_spark-guide/content/spark-streaming-kafka-kerb.html
    • https://blog.csdn.net/u012373717/article/details/115401706
  • 相关阅读:
    【约束布局】ConstraintLayout配合Guideline解决两个子控件其中一个被挤出屏幕的问题
    js的promise的究竟是同步还是异步的问题和promise.all可以同时请求多个接口是错误的回答的原因
    实训笔记9.1
    BehaviorTree之概念讲解(一)
    ALGO开发源码【node服务】
    项目优化之监听tab切出事件
    spring boot 整合 sentinel
    Linux中的DNS服务搭建与管理
    设计模式 - 工厂方法模式
    C嘎嘎~~[类 中篇]
  • 原文地址:https://blog.csdn.net/Mrerlou/article/details/126408647