Spark Executor中访问SparkSession抛出AttributeError问题求助
错误根因
Spark Driver和Executor是相互独立的运行进程,仅Driver端持有初始化完成的活跃
SparkSession实例,Executor进程内的SparkSession._activeSession默认值为None。你当前在Executor侧执行的get_row_group_info方法调用的日志逻辑直接访问_activeSession的sparkContext属性,因此抛出空类型属性错误。
额外注意:你提供的logger函数存在参数名笔误,入参定义为mssg,但函数内部调用时使用的是msg,调整代码时需要同步修正。
可行解决方案
方案1:替换为Python原生日志模块,不依赖Spark上下文
这是改造成本最低的方案,直接用Python自带的logging模块实现Executor侧日志输出,完全规避获取SparkSession的问题:
import logging # 自定义日志输出格式和级别 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def get_file_system(): # 替换原有日志调用 logger.info("Triggered") return fs
- 优势:无需修改原有业务逻辑流程,日志会输出到Executor的标准输出/错误日志中,可直接通过Spark UI的Executor日志面板查看。
方案2:日志带回Driver侧统一上报
如果必须使用自定义的JVM日志上报接口,可以把需要上报的日志内容作为返回值的一部分带回Driver端,在Driver侧统一调用上报方法:
def get_row_group_info(path): # 用临时列表存储当前任务的所有待上报日志 task_logs = ["Triggered"] fs = get_file_system() relative_path = os.path.relpath(path, base_path) pq_file = fs.open(path) num_row_groups = pq.read_metadata(pq_file).num_row_groups pq_file.close() # 把日志和业务结果一起返回 return relative_path, num_row_groups, task_logs # Driver侧处理逻辑 result_with_logs = spark_context.parallelize(paths, len(paths)) \ .map(get_row_group_info) \ .collect() # 分离业务结果和日志,统一上报日志 row_groups = [] from pyspark.sql import SparkSession log_event = SparkSession.getActiveSession().sparkContext._jvm.com.package.logInfoEvent for rel_path, group_cnt, logs in result_with_logs: row_groups.append((rel_path, group_cnt)) for msg in logs: log_event(msg)
- 优势:可以复用原有自定义JVM日志上报逻辑,不需要调整底层日志上报实现。
方案3:Executor侧动态创建SparkSession
适合Spark 2.0+版本,修改日志逻辑用官方提供的getOrCreate()方法获取SparkSession,不要直接访问私有属性_activeSession:
def logger(msg): from pyspark.sql import SparkSession # Executor侧不存在活跃会话时会自动创建临时会话 spark = SparkSession.builder.getOrCreate() spark.sparkContext._jvm.com.package.logInfoEvent(msg)
- 注意:该方案会在每个Executor进程创建一个SparkSession实例,有额外的资源开销,不适合超大规模集群场景使用。
内容的提问来源于stack exchange,提问作者Manjur
相关产品推荐
相关产品推荐

