使用sparklyr连接Spark集群时遭遇内存及线程创建异常问题
问题分析与解决方案
结合你更换更大Spark集群后遇到的内存和线程创建问题,我从几个核心角度拆解原因,对应给出解决办法:
1. Client模式下驱动程序(R端)的内存配置不足
你用的是client模式,这意味着Spark驱动程序是运行在你的R生产服务器上,而非Spark集群节点内。更换更大集群后,你大概率会拉取更多数据,但驱动程序的JVM内存仍保持默认值,直接导致:
- 拉取数据时本地JVM堆内存耗尽,抛出
out of memory - 内存不足会连锁影响JVM创建GC线程或工作线程,进而出现
Out of memory unable to create new thread
解决办法:
- 在sparklyr连接时显式设置驱动内存和结果集大小限制:
library(sparklyr) config <- spark_config() # 根据R服务器内存调整,比如设为8G config <- spark_config_set(config, "spark.driver.memory", "8g") # 限制拉取到本地的结果集大小,避免一次性加载过多数据 config <- spark_config_set(config, "spark.driver.maxResultSize", "4g") sc <- spark_connect(master = "spark://<my server>:7077", config = config) - 尽量避免用
collect()一次性拉取全量数据,改用分批次拉取,或者先在Spark端完成过滤、聚合再拉取到R。
2. Spark Master节点的JVM内存配置过小
你重启Master后出现Cannot create GC thread. Out of system resources,说明Master进程的JVM内存不足,连必要的GC线程都无法创建——更大的集群需要Master管理更多Worker节点和任务,默认的Master内存配置肯定不够用。
解决办法:
- 修改Spark安装目录下的
conf/spark-env.sh(如果没有就复制spark-env.sh.template),添加Master的内存参数:
这里的export SPARK_MASTER_OPTS="-Xmx4g"4g可以根据集群规模调整,比如10+Worker的集群可以设到8G甚至更高。 - 保存后重启Spark Master服务:
$SPARK_HOME/sbin/stop-master.sh $SPARK_HOME/sbin/start-master.sh
3. Root用户的系统级资源限制未调整
虽然你说线程使用量没到用户上限,但Root用户的系统级限制(比如线程数、内存锁定)可能还是默认值,更大的集群会触发这些限制:
- Linux默认的
nproc(最大进程/线程数)限制较低,Spark创建大量线程时会触发 - 内存锁定限制可能导致JVM无法分配足够的内存块
解决办法:
- 修改
/etc/security/limits.conf,添加以下配置:root soft nproc 65535 root hard nproc 65535 root soft memlock unlimited root hard memlock unlimited - 检查
/etc/security/limits.d/目录下的配置文件,有没有覆盖上述设置,如果有就调整对应文件。 - 重新登录Root用户或者重启系统生效。
4. 老旧版本的已知Bug
你用的Spark 2.2.1和sparklyr 0.6.2都是比较老的版本,存在一些内存管理和Client模式的已知问题,比如:
- Spark 2.x早期版本在Client模式下的内存泄漏
- sparklyr早期版本与Spark集群的资源协商bug
解决办法:
- 如果业务允许,优先升级到较新的版本:Spark建议升级到2.4.x(长期支持版),sparklyr升级到1.0+版本,能解决很多老版本的内存问题。
- 如果暂时无法升级,严格按照前面的配置调整,同时避免在驱动端执行过重的计算。
内容的提问来源于stack exchange,提问作者Zafar
相关产品推荐
相关产品推荐

