spark RDD分区2GB限制(Size exceeds Integer.MAX_VALUE)

本文介绍了在使用Spark处理大数据文件时遇到的2GB限制问题及其解决办法。通过手动设置RDD分区数量为500,成功避免了因文件大小超过整型最大值导致的任务丢失警告。

最近使用spark处理较大的数据文件,遇到了分区2G限制的问题,spark日志会报如下的日志:
WARN scheduler.TaskSetManager: Lost task 19.0 in stage 6.0 (TID 120, 10.111.32.47): java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:828)
at org.apache.spark.storage.DiskStore.getBytes(DiskStore.scala:123)
at org.apache.spark.storage.DiskStore.getBytes(DiskStore.scala:132)
at org.apache.spark.storage.BlockManager.doGetLocal(BlockManager.scala:517)
at org.apache.spark.storage.BlockManager.getLocal(BlockManager.scala:432)
at org.apache.spark.storage.BlockManager.get(BlockManager.scala:618)
at org.apache.spark.CacheManager.putInBlockManager(CacheManager.scala:146)
at org.apache.spark.CacheManager.getOrCompute(CacheManager.scala:70)

解决方法:
手动设置RDD的分区数量。当前使用的Spark默认RDD分区是18个,后来手动设置为500个,上面这个问题就迎刃而解了。可以在RDD加载后,使用RDD.repartition(numPart:Int)函数重新设置分区数量。
val data_new = data.repartition(500)


下面是一些相关的资料,有兴趣的读者可以进一步的阅读:


<think>我们正在解释两行PySpark代码的含义: 1. `from pyspark import StorageLevel` 2. `mapped_rdd.persist(StorageLevel.MEMORY_ONLY)` ### 1. 导入StorageLevel ```python from pyspark import StorageLevel ``` - **作用**:从PySpark库中导入`StorageLevel`类。这个类定义了RDD(弹性分布式数据集)在Spark集群中的存储级别。 - **存储级别的意义**:存储级别决定了RDD分区数据在集群中如何存储(例如:内存、磁盘、序列化方式、副本数量等)[^1]。 - **常见存储级别常量**: - `MEMORY_ONLY`: 只存储在内存中(反序列化形式) - `MEMORY_AND_DISK`: 优先存内存,内存不足时溢写到磁盘 - `MEMORY_ONLY_SER`: 序列化后存储在内存(节省空间) - `DISK_ONLY`: 只存储在磁盘 - 其他(如带副本的级别:`MEMORY_ONLY_2`表示存两份) ### 2. 设置RDD的存储级别 ```python mapped_rdd.persist(StorageLevel.MEMORY_ONLY) ``` - **`persist()`方法**:用于将RDD标记为持久化(缓存)。Spark在执行行动操作(Action)时,会将该RDD的计算结果按指定级别存储,避免后续重复计算。 - **参数**:`StorageLevel.MEMORY_ONLY`表示使用内存存储级别,具体行为如下: - 将RDD分区以**反序列化Java对象**的形式存储在Executor内存中。 - 若内存不足,则部分分区不缓存,需使用时重新计算。 - 不创建副本(单副本),无磁盘备份。 - **与`cache()`的区别**: ```python mapped_rdd.cache() # 等价于persist(StorageLevel.MEMORY_ONLY) ``` `cache()`是`persist()`的简写,默认使用`MEMORY_ONLY`级别。 ### 存储级别选择策略[^1] | 级别 | 适用场景 | |-----------------------|------------------------------------------------------------------------| | **MEMORY_ONLY**(默认) | | 内存充足且RDD对象较小 | | **MEMORY_ONLY_SER** | 对象较大时,序列化可减少内存占用(需权衡CPU开销) | | **MEMORY_AND_DISK** | 内存不足时部分数据存磁盘,避免重算大分区 | | **DISK_ONLY** | 内存严重不足且数据重用率低 | > **重要原则**:仅在RDD被多次使用时才持久化,并及时用`unpersist()`释放资源。 ### 代码执行示例 ```python # 创建RDD rdd = sc.parallelize([1, 2, 3, 4]) # 转换操作(不触发计算) mapped_rdd = rdd.map(lambda x: x * 2) # 设置持久化级别 mapped_rdd.persist(StorageLevel.MEMORY_ONLY) # 仅内存存储 # 行动操作触发缓存 result = mapped_rdd.collect() # 计算并缓存数据 print(result) # 输出: [2, 4, 6, 8] # 后续操作重用缓存 count = mapped_rdd.count() # 直接读取缓存,无需重算 print(count) # 输出: 4 # 释放缓存 mapped_rdd.unpersist() ``` ### 性能影响 - **优点**:减少重复计算,加速迭代算法(如机器学习训练)[^1]。 - **风险**:不合理缓存可能导致内存溢出或浪费资源。 --- §§相关问题§§ 1. 如何通过Spark UI监控已缓存的RDD存储状态? 2. 在什么场景下应选择`MEMORY_ONLY_SER`而非`MEMORY_ONLY`? 3. Spark中哪些操作会触发RDD的持久化生效? </think> ### 详细解释代码:`from pyspark import StorageLevel` 和 `mapped_rdd.persist(StorageLevel.MEMORY_ONLY)` #### 1. `from pyspark import StorageLevel` - **作用**:从 PySpark 库导入存储级别(`StorageLevel`)类,用于定义 RDD 的持久化策略。 - **关键概念**: - `StorageLevel` 是 Spark 的核心类,封装了数据存储的多种组合方式(内存、磁盘、序列化、副本数等)。 - 常用存储级别常量: - `MEMORY_ONLY`: 只存储在内存中(默认) - `MEMORY_AND_DISK`: 优先存内存,内存不足时溢写磁盘 - `DISK_ONLY`: 只存储在磁盘 - `MEMORY_ONLY_SER`: 序列化后存储在内存(节省空间) - **为何需要导入**: 不导入 `StorageLevel` 类,就无法使用 `StorageLevel.MEMORY_ONLY` 等常量指定存储级别。 #### 2. `mapped_rdd.persist(StorageLevel.MEMORY_ONLY)` - **作用**:将 RDD 标记为持久化,并指定存储级别为 `MEMORY_ONLY`。 - **分步解析**: 1. **`mapped_rdd`**: 通过 `map` 转换生成的 RDD(例如 `rdd.map(lambda x: x*2)`)。 2. **`.persist()`**: 方法调用,表示要求 Spark 持久化该 RDD。**注意**:此时并未真正存储数据,只是一个标记。 3. **`StorageLevel.MEMORY_ONLY`**: 指定持久化的具体策略: - **存储位置**:Executor 的 JVM 堆内存 - **存储形式**:反序列化的 Java 对象(非序列化字节) - **内存不足处理**:若分区无法放入内存,需使用时重新计算 - **副本数**:1(无冗余) - **磁盘使用**:❌ 不使用磁盘 - **执行流程**: ```mermaid graph LR A[触发行动操作] --> B{检查是否已持久化} B --> |否| C[计算RDD并存入内存] B --> |是| D[直接从内存读取数据] ``` 只有触发行动操作(如 `count()`, `collect()`)时,Spark 才会执行计算并缓存数据。 #### 3. 与 `cache()` 的关系 - **等价写法**: ```python mapped_rdd.cache() # 完全等价于 mapped_rdd.persist(StorageLevel.MEMORY_ONLY) ``` - **区别**: `cache()` 是 `persist(StorageLevel.MEMORY_ONLY)` 的简写,但显式使用 `persist` 可灵活指定其他存储级别。 #### 4. 存储级别的选择策略 | 存储级别 | 适用场景 | 性能特点 | |-------------------|--------------------------------------------------------------------------|------------------------------| | **`MEMORY_ONLY`** | 内存充足,RDD 重用率高且对象较小(默认) | 访问速度最快,CPU效率最高 | | **`MEMORY_ONLY_SER`** | 对象较大,内存紧张但 CPU 充足 | 空间节省,但需反序列化开销 | | **`MEMORY_AND_DISK`** | 部分分区过大无法全放内存 | 避免重算大分区,但有磁盘 I/O | | **`DISK_ONLY`** | 内存严重不足或数据重用率低 | 速度最慢,仅避免重复计算 | > **关键原则**:优先用默认的 `MEMORY_ONLY`,仅在内存不足时考虑序列化或磁盘方案。 #### 5. 完整代码示例 ```python from pyspark import SparkContext, StorageLevel sc = SparkContext("local", "example") # 创建原始RDD data = [1, 2, 3, 4, 5] rdd = sc.parallelize(data) # 转换操作:map生成新RDD mapped_rdd = rdd.map(lambda x: x * 2) # 此时未存储 # 显式持久化(默认MEMORY_ONLY) mapped_rdd.persist(StorageLevel.MEMORY_ONLY) # 触发行动操作:计算并缓存 print(mapped_rdd.collect()) # 输出: [2, 4, 6, 8, 10] # 后续重用缓存(无需重算) print(mapped_rdd.count()) # 输出: 5 # 释放缓存 mapped_rdd.unpersist() ``` #### 注意事项 1. **惰性生效**:持久化标记需行动操作触发才生效。 2. **内存监控**:通过 Spark UI 的 `Storage` 标签页观察缓存状态。 3. **及时释放**:用 `unpersist()` 手动释放不再使用的 RDD,避免资源浪费。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值