Spark加载外部配置文件

--files path启动加载配置文件

在spark-streaming程序中需要配置文件中的数据来完成某项统计时,需要把配置文件打到工程里,maven的配置如下:

[html] view plain copy

  1. <build>    
  2.      <plugins>    
  3.          <plugin>    
  4.              <groupId>org.apache.maven.plugins</groupId>    
  5.              <artifactId>maven-surefire-plugin</artifactId>    
  6.              <configuration>    
  7.                  <skip>true</skip>    
  8.              </configuration>    
  9.          </plugin>    
  10.      </plugins>    
  11.      <resources>    
  12.          <resource>    
  13.              <directory>src/main/resources</directory>    
  14.              <includes>    
  15.                  <include>**/*.txt</include>    
  16.                  <include>*.txt</include>    
  17.              </includes>    
  18.              <filtering>true</filtering>    
  19.          </resource>    
  20.      </resources>    
  21. </build>    

这样在local模式下运行时没问题的,但是要放在yarn集群上就会出问题,需要用如下方式来调用:

[plain] view plain copy

  1. spark-submit --class com.kingsoft.server.KssNodeStreaming   
  2. --master yarn-cluster   
  3. --driver-memory 2G   
  4. --executor-memory 5G   
  5. --num-executors 10   
  6. --jars /home/hadoop/spark-streaming-flume_2.10-1.0.1.jar,/home/hadoop/avro-ipc-1.7.5-cdh5.1.0.jar,/home/hadoop/flume-ng-sdk-1.5.0.1.jar,/home/hadoop/fastjson-1.1.41.jar   
  7. --files /home/hadoop/idc_ip.txt,/home/hadoop/ipdata.txt   
  8. /home/hadoop/SparkStreaming-0.0.1-SNAPSHOT.jar   
  9. 0.0.0.0   
  10. 58006  

Spark中addFile加载配置文件

      我们在使用Spark的时候有时候需要将一些数据分发到计算节点中。一种方法是将这些文件上传到HDFS上,然后计算节点从HDFS上获取这些数据。当然我们也可以使用addFile函数来分发这些文件。注意,如果是spark程序通过yarn集群上加载配置文件,path必须是集群hdfs的绝对路径,如:viewfs://58-cluster//home/hdp_lbg_supin/resultdata/zhaopin/recommend/config/redis.properties。

扫描二维码关注公众号,回复: 19964 查看本文章

addFile

  addFile方法可以接收本地文件(或者HDFS上的文件),甚至是文件夹(如果是文件夹,必须是HDFS路径),然后Spark的Driver和Exector可以通过SparkFiles.get()方法来获取文件的绝对路径(Get the absolute path of a file added through SparkContext.addFile()),addFile的函数原型如下:

[java] view plain copy

  1. def addFile(path: String): Unit  
  2. def addFile(path: String, recursive: Boolean): Unit  

      addFile把添加的本地文件传送给所有的Worker,这样能够保证在每个Worker上正确访问到文件。另外,Worker会把文件放在临时目录下。因此,比较适合用于文件比较小,计算比较复杂的场景。如果文件比较大,网络传送的消耗时间也会增长。

      path:可以是local、hdfs(任何hadoop支持的文件系统)、HTTP、HTTPS、FTP等。local方式时,在windows下使用绝对路径时需要加个“/”,如“d:/iteblog.data”得写成“/d:/iteblog.data”或“file:///d:/iteblog.data”。

   recursive:如果path是一个目录,那么我们可以设置recursive为true,这样Spark会递归地分发这个路径下面的所有文件到计算节点的临时目录。

   通过SparkFiles.get(path:String)获取添加的文件路径。

[java] view plain copy

  1. var path = "/user/iteblog/ip.txt"  
  2. sc.addFile(path)  
  3. val rdd = sc.textFile(SparkFiles.get(path))  

      上面的实例展示了如何在Driver中获取分发出去的文件,我们还可以在Exector获取到分发的文件:

[java] view plain copy

  1. var path = "/user/iteblog/ip.txt"  
  2. sc.addFile(path)  
  3. val rdd = sc.parallelize((0 to 10))  
  4. rdd.foreach{ index =>  
  5.     val path = SparkFiles.get(path)  
  6.     ......  
  7. }  

      如果我们添加的是压缩文件,比如.tar.gz.tgz或者.tar,Spark会调用Linux的解压缩命令tar去解压缩这些文件。

addJar

  addJar添加在这个SparkContext实例运行的作业所依赖的jar。,其函数原型如下:

[java] view plain copy

  1. def addJar(path: String)  

      path:可以是本地文件(local file)、HDFS文件(其他所有的Hadoop支持的文件系统也可以)、HTTP、 HTTPS 或者是FTP URI文件等等。

   其实Spark内部通过spark.jars参数以及spark.yarn.dist.jars函数传进去的Jar都是通过这个函数分发到Task的。

将配置文件打到工程jar包里

      注意:IntelliJ IDEA创建Maven项目时,必须是Java项目,否则不能将配置文件打到工程jar包。

      redis.properties配置文件示例如下:

[html] view plain copy

  1. redis.host=xx.xx.xxx.x  
  2. redis.port=6380  
  3. redis.password=6f3d16c5119bb946  
  4. redis.maxActive=500  
  5. redis.maxWait=10000  
  6. redis.maxidle=500  
  7. redis.minidle=10  
  8. redis.maxtotal=500  

      RedisClient.scala加载配置文件示例如下:

[java] view plain copy

  1. package com.bj58.adsp.dp.files.redis  
  2.   
  3. import java.io.{InputStream, BufferedInputStream, FileInputStream}  
  4. import java.util.Properties  
  5.   
  6. import org.apache.commons.pool2.impl.GenericObjectPoolConfig  
  7. import redis.clients.jedis.JedisPool  
  8. import scala.collection.JavaConversions._  
  9.   
  10. /** 
  11.  * Created by Administrator on 2015/10/23. 
  12.  */  
  13. object RedisClient extends Serializable {  
  14.     
  15.   val properties: Properties = new Properties  
  16.   val in: InputStream = getClass.getResourceAsStream("/redis.properties")  
  17.   properties.load(new BufferedInputStream(in))  
  18.   val redisHost = properties.getProperty("redis.host")  
  19.   val redisPort = properties.getProperty("redis.port")  
  20.   val redisPwd = properties.getProperty("redis.password")  
  21.   val redisTimeout = 30000  
  22.   val config = new GenericObjectPoolConfig()  
  23.   config.setTestOnBorrow(true)  
  24.   config.setMaxIdle(properties.getProperty("redis.maxidle").toInt)  
  25.   config.setMinIdle(properties.getProperty("redis.minidle").toInt)  
  26.   config.setMaxTotal(properties.getProperty("redis.maxtotal").toInt)  
  27.     
  28.   lazy val pool = new JedisPool(config, redisHost, redisPort.toInt, redisTimeout, redisPwd)  
  29.   
  30.   lazy val hook = new Thread {  
  31.     override def run = {  
  32.       println("Execute hook thread: " + this)  
  33.       pool.destroy()  
  34.     }  
  35.   }  
  36.   sys.addShutdownHook(hook.run)  
  37. }  

      如果是读取配置文件内容,可以直接:

[java] view plain copy

  1. val properties: Properties = new Properties  
  2. val in: InputStream = getClass.getResourceAsStream("/redis.properties")  
  3. properties.load(new BufferedInputStream(in))  

      如果是只加载配置文件,可以直接:

[java] view plain copy

  1. public static RedisClient init() {  
  2.    RedisClient client = null;  
  3.    try {  
  4.       // 根据配置文件初始化Redis客户端  
  5.       client = RedisClient.getInstance(getClass.getResource("/redis.properties"));  
  6.    } catch (Exception e) {  
  7.       e.printStackTrace();  
  8.    }  
  9.    return client;  
  10. }  

直接将配置文件内容写到程序中

示例如下:

[java] view plain copy

  1. lines.foreachRDD(rdd => {  
  2.   //embedded function  
  3.   def func(records: Iterator[String]) {  
  4.     var conn: Connection = null  
  5.     var stmt: PreparedStatement = null  
  6.     try {  
  7.       val url = "jdbc:mysql://xx.xxx.xx.xxx:3307/supindb"  
  8.       val user = "root"  
  9.       val password = "root"  
  10.       conn = DriverManager.getConnection(url, user, password)  
  11.       records.flatMap(_.split(" ")).foreach(word => {  
  12.         val sql = "insert into mytable(word) values(?)"  
  13.         stmt = conn.prepareStatement(sql)  
  14.         stmt.setString(1, word)  
  15.         stmt.executeUpdate()  
  16.       })  
  17.     } catch {  
  18.       case e: Exception => e.printStackTrace()  
  19.     } finally {  
  20.       if (stmt != null) {  
  21.         stmt.close()  
  22.       }  
  23.       if (conn != null) {  
  24.         conn.close()  
  25.       }  
  26.     }  
  27.   }  
  28.   
  29.   val repartitionedRDD = rdd.repartition(4)  
  30.   repartitionedRDD.foreachPartition(func)  
  31. })  

使用addFile("__app__.jar")方式

      如果程序中调用其他服务,而其他服务需要加载配置文件,则可以将程序打成jar包,并命名为__app__.jar,使用sc.addFile("__app__.jar")方式即可。

Refer:

http://blog.csdn.net/aaa1117a8w5s6d/article/details/43090017

http://www.iteblog.com/archives/1704

猜你喜欢

转载自my.oschina.net/sniperLi/blog/1633385