Spark编程指南之七:RDD持久化及缓存

本文详细介绍了Spark中RDD的持久化策略,包括缓存机制、存储级别的选择及其对性能的影响。同时,探讨了如何将RDD数据高效地写入HDFS和MySql数据库,以及在数据写入过程中的一些最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RDD持久化

向HDFS写数据

向HDFS写数据时,当前RDD的分区即为HDFS上的文件数。
为避免生成多个小文件,可以先重分区。

rdd.repartition(4).saveAsTextFile("hdfs://bigdata01:9000/sparkdata)

向MySql写数据

写一个工具类连接数据库

import java.sql.*;
public class JdbcUtils {
	private static String url = "jdbc:mysql://bigdata01:3306/test";
	private static String user = "root";
	private static String pwd = "123456";
	private JdbcUtils(){
	}
	static {
		try{
			Class.forName("com.mysql.jdbc.Driver");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
			System.out.println("JDBC Connection Failed!");
		}
	}
	public static Connection getConnection() throws SQLException{
		return DriverManager.getConnection(url, user, pwd);
	}
	public static void main(String[] args){
		try{
			Connection conn = getConnection();
			String sql = "insert into textFile (value) values(?)";
			PreparedStatement pstmt;
			pstmt = (PreparedStatement) conn.preparedStatement(sql);
			pstmt.setString(1,"test");
			pstmt.executeUpdate();
			free(pstmt,conn);
			System.out.println("----"+conn);
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
	public static void free(Statement stat, Connection conn){
		try{ 
			if(stat != null)
				stat.close();
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			try{
				if(conn!=null) stat.close();
			}catch(SQLException e){
			e.printStackTrace();
			}
		}
	}
}

在foreach或foreachPartition方法中调用连接数据库

rdd.foreach(line => {                  //foreach每条记录创建一个连接
  val conn = JdbcUtils.getConnection()  //实际会使用连接池
  val sql = "insert into textFile (value) values(?)"
  var pstmt : PreparedStatement = null
  pstmt = conn.prepardStatement(sql)
  pstmt.setString(1,line+"")
  pstmt.executeUpdate
  JdbcUtils.free(pstmt, conn)
})
rdd.foreachPartition(partitions => {//foreachPartition每个分区创建一个连接
  val conn = JdbcUtils.getConnection()  //实际会使用连接池
  partitions.foreach(line => {
    val sql = "insert into textFile (value) values(?)"
    var pstmt : PreparedStatement = null
    pstmt = conn.prepardStatement(sql)
    pstmt.setString(1,line+"")
    pstmt.executeUpdate
  })
  JdbcUtils.free(pstmt, conn)
})

RDD缓存

同一个RDD有多个action时可以用缓存来提高性能。缓存默认保存在内存中,或者保存在磁盘中。

缓存的存储级别StorageLevel

在StorageLevel类中定义,默认是NONE

object StorageLevel{
	val NONE = new StorageLevel(false,false,false,false)//是否用磁盘、是否用内存、是否用堆外内存、是否序列化
	val DISK_ONLY = new StorageLevel(true,false,false,false)
	val DISK_ONLY_2 = new StorageLevel(true,false,false,false,2) //2是副本数量
	val MEMORY_ONLY = new StorageLevel(false,true,false,false)
	val MEMORY_ONLY_2 = new StorageLevel(false,true,false,false,2)
	...
}

RDD持久化存储级别如何选择:
Spark的存储级别是为了在内存使用和CPU效率之间提供不同的权衡,具体选择哪个存储级别,可以从以下方面考虑:
如果RDDs数据适合默认存储级别(MEMORY_ONLY),那么就是用默认存储级别。此时,RDD的运算速度最快;
如果没有,请尝试使用MEMORY_ONLY_SER并选择一个快速序列化库,以使对象更节省空间,但访问速度仍然相当快。(Java和Scala);
不要持久化到磁盘,除非计算数据集的函数很耗时,或者过滤了大量数据。因为,从磁盘读取分区,可能没有重新计算分区快;
如果需要快速的故障恢复,则使用副本存储级别。

cache()和persist()的区别是什么?

cache()等价于persist(MEMORY_ONLY)

def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)
def cache(): this.type = persist()

缓存什么时候失效?

Spark自动监控每个节点的缓存,并以LRU(最近最少使用)方法删除旧的数据分区。也可以手动删除缓存RDD.unpersist()。
如果内存不够用,Spark会优先保证计算内存。

RDD.cache后是否真正缓存?

否。cache之后需要action触发,如果只是一次action不需要cache。
缓存查看可以在Web页面查看storage菜单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值