Header
Body
食用指南
环境
一些神奇的环境变量
export HADOOP_HOME=D:\Users\Dell\.hadoop
export HADOOP_USER_NAME=root
在我们的开发环境中,Hadoop 集群使用的是 Simple
认证。即,你说你是谁,Hadoop 就认为你是谁。Spark 默认使用的是系统的环境变量中的 USERNAME
来获取用户名,这里也可以通过设置 HADOOP_USER_NAME
变量来调整用户名。
代码
最简单的 Hadoop 操作代码
// 构建应用
val configuration = new SparkConf()
.setMaster("local[*]")
.setAppName("Koi")
val context = SparkContext.getOrCreate(configuration)
context.hadoopConfiguration.set("fs.defaultFS", "hdfs://172.18.38.198:8020")
// 构建文件系统
val fileSystem = FileSystem.get(context.hadoopConfiguration)
// 访问文件系统
val outer = fileSystem.create(
new Path("hdfs://172.18.38.198:8020/$/20231006.txt")
)
outer.write(response.body)
outer.close()
请注意,在这个例子中,第 8 行是很关键的一行,这一行设置了默认文件系统的位置,这样后续才可以访问这个文件系统。
当然,除了使用代码配置外,你还可以选择直接将 Hadoop 的配置文件复制到程序的资源目录下来实现自动配置。网络上有很多教程,这里就不再赘述。
命令
Spark 任务提交命令
# 这个命令是这么构成的 spark-submit --master ${谁来运行} --class ${运行谁} ${要运行的类从哪来} ${应用的运行参数}
spark-submit --master yarn --class tech.giant.zoo.fish.koi.Launcher ./koi_2.13-0.1.0-SNAPSHOT.jar updateSites
问题
常规问题汇总分析
Exception in thread "main" java.lang.NoSuchMethodError: scala.runtime.RichInt$.to$extension(II)Lscala/collection/immutable/Range$Inclusive;
这是因为打包出来的 Jar 包中没有携带依赖,遇到这种情况有两种方案处理
- 把所有依赖包都复制到服务器上,然后在
spark-submit
时使用 --jar 参数携带这些依赖 - 打包 Fat Jar,直接把所有依赖包都带上
做为一个大懒蛋,我肯定选择 Creating a Fat JAR Using SBT | Baeldung on Scala 啦。
分享一下我的项目配置:
ThisBuild / scalaVersion := "2.13.12"
ThisBuild / version := "Build20231006.GJY"
ThisBuild / assemblyMergeStrategy := { name => MergeStrategy.preferProject }
libraryDependencies ++= Seq(
"org.scalaj" %% "scalaj-http" % "2.4.2",
"org.apache.spark" %% "spark-core" % "3.5.0" % "provided"
)
lazy val root = (project in file("."))
.settings(
name := "Koi",
idePackagePrefix := Some("tech.giant.zoo.fish.koi"),
assembly / mainClass := Some("tech.giant.zoo.fish.koi.Main"),
)
好好好,还是报相同的错误。这时候我仔细看了下报错信息,发现在堆栈的最底部,SparkSubmit 也正在使用 Scala。我强烈怀疑是 Spark 集群的 Scala 版本与我本地开发所使用的版本不一致导致的错误,于是我便查看了 Spark 使用的 Scala 版本。
还真是版本不对,😂,抓紧换一下本地的试试。
~其实我们最终的解决方案是升级了下 CDP 集群~
离谱问题大赏
File has reached the limit on maximum number of blocks (dfs.namenode.fs-limits.max-blocks-per-file): 10000 >= 10000
23/10/08 01:59:21 ERROR logging.DriverLogger$DfsAsyncWriter: Failed writing driver logs to dfs
org.apache.hadoop.ipc.RemoteException(java.io.IOException): File has reached the limit on maximum number of blocks (dfs.namenode.fs-limits.max-blocks-per-file): 10000 >= 10000
at org.apache.hadoop.hdfs.server.namenode.FSDirWriteFileOp.validateAddBlock(FSDirWriteFileOp.java:186)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getAdditionalBlock(FSNamesystem.java:2815)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.addBlock(NameNodeRpcServer.java:874)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.addBlock(ClientNamenodeProtocolServerSideTranslatorPB.java:589)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:533)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1070)
at org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:989)
at org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:917)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1898)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2894)
at org.apache.hadoop.ipc.Client.getRpcResponse(Client.java:1562)
at org.apache.hadoop.ipc.Client.call(Client.java:1508)
at org.apache.hadoop.ipc.Client.call(Client.java:1405)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:233)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:118)
at com.sun.proxy.$Proxy13.addBlock(Unknown Source)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.addBlock(ClientNamenodeProtocolTranslatorPB.java:523)
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:431)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invokeMethod(RetryInvocationHandler.java:166)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invoke(RetryInvocationHandler.java:158)
at org.apache.hadoop.io.retry.RetryInvocationHandler$Call.invokeOnce(RetryInvocationHandler.java:96)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:362)
at com.sun.proxy.$Proxy14.addBlock(Unknown Source)
at org.apache.hadoop.hdfs.DFSOutputStream.addBlock(DFSOutputStream.java:1122)
at org.apache.hadoop.hdfs.DataStreamer.locateFollowingBlock(DataStreamer.java:1880)
at org.apache.hadoop.hdfs.DataStreamer.nextBlockOutputStream(DataStreamer.java:1682)
at org.apache.hadoop.hdfs.DataStreamer.run(DataStreamer.java:719)
我算是总结出来一个道理,程序崩溃必然选择三更半夜。
这个崩溃的原因是因为 Spark 会把 driver 的日志输出存在 Hadoop /usr/spark/driverLogs
目录下。我们这是一个爬虫程序,运行了一段时间后由于输出了大量的日志导致超过了 Hadoop 单文件大小限制于是便出现了上述问题。
在程序启动时我发现了这条日志,也证明了这个问题。
23/10/08 11:55:57 INFO logging.DriverLogger$DfsAsyncWriter: Started driver log file sync to: /user/spark/driverLogs/local-1696766155850_driver.log
重启程序,解决问题。