🗒️Spark|执行计划缓存带来的一致性问题
2023-7-20
| 2023-7-24
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password

背景介绍

技术群里看的一个问题:
notion image
简单描述一下就是两个 beeline 里查询到的统计数据不一致,这个问题会发生在查询 parquet 和 Hudi 表的时候。
看文字不太好理解,简单复现一下:
  1. 预先建好一个 paruqet 表
  1. 在第一个和第二个 beeline 连接里都去执行下面查询,得到相同的结果
  1. 在第一个 beeline 连接里,插入一条数据并查询
  1. 在第二个 beeline 连接里,继续查询统计数据,得到下面的结果
有点蹊跷,为什么第二个 beeline 的查询还是 0 呢,难道第一个 beeline 的插入数据对它不可见吗?

原因分析

问题的原因在于两个 beeline 之前都查询过这张表,而第一个 beeline 在 insert 数据之后自动刷新了表的缓存,而第二个 beeline 里缓存的表信息没有被刷新,所以再去查询就会使用之前的结果。
那么,SparkSession 里缓存的究竟是什么呢?可以通过什么办法绕开呢?
经过一番查找,找到了 spark.sql.filesourceTableRelationCacheSize 这个参数:
从字面上,可以看出用来控制缓存的表的逻辑计划的数量,默认值是 1000。
这个参数控制的缓存使用的是 guava cache,有缓存时间限制:
对于缩短cache时间,需要调整spark.sql.metadataCacheTTLSeconds这个参数。
看下缓存的创建时机:
可以看到,这里是使用 cached.getOrElse 方法,key 则是database 和 table 名的联合。
缓存的使用也是有限制的:只有当查询的 path,schema,patition 一致才会取缓存,另外只有需要转换的才会走缓存,也就是配置了 spark.sql.hive.convertMetastoreParquet、spark.sql.hive.convertMetastoreOrc 才会走缓存,但是这几个默认值都是 true,所以 parquet、orc 类型的都会走缓存。
当然,使用 text 格式不会出现这个问题。

总结

spark.sql.filesourceTableRelationCacheSize 控制了缓存 LogicalPlan 的个数。
对于SparkThriftServer、Zeppelin Spark 这种常驻应用,开启这个缓存可能导致数据不一致的情况,可以考虑设置成 0,避免不一致的问题。
 
  • Spark
  • Spark|类型转换踩坑记录SparkSQL|explain语法
    Loading...
    目录