分区Delta表使用WriteSerializable时出现ConcurrentAppendException问题咨询
问题背景
现有Delta分区表定义如下:
CREATE TABLE sales_data ( sale_id STRING, customer_id STRING, amount DOUBLE, sale_date DATE, region STRING ) USING DELTA PARTITIONED BY (region) LOCATION 'dbfs:/mnt/datalake/sales_data';
使用以下代码进行毫秒级高频写入(每个写入操作对应唯一region分区):
new_data = [ ("S1001", "C2001", 99.99, "2025-08-10", "East"), ("S1002", "C2002", 149.49, "2025-08-10", "West") ] columns = ["sale_id", "customer_id", "amount", "sale_date", "region"] df = spark.createDataFrame(new_data, columns) df.write \ .format("delta") \ .mode("append") \ .saveAsTable("sales_data")
执行时触发delta.exceptions.ConcurrentAppendException异常,通过设置delta.isolationLevel = Serializable解决问题,但存在两个疑问:
- 默认隔离级别为
WriteSerializable,该级别下所有写入应按顺序执行,理论上不应出现此问题,是否正确? - 每个写入操作的分区键(region)唯一,为何仍会触发该异常?
问题解析
1. 关于WriteSerializable隔离级别的疑问
你的理解存在偏差:WriteSerializable的核心是保证最终写入结果等价于某一种串行执行顺序,而非强制所有写入操作严格按物理顺序依次执行。在Databricks Runtime 15中,WriteSerializable采用乐观并发控制机制:
- 写入操作先读取表的全局元数据(包括事务日志版本)
- 执行各自的写入逻辑(写入对应分区数据)
- 提交阶段检查全局元数据是否被其他事务修改
当毫秒级并发写入时,多个事务可能同时读取到相同的日志版本,随后各自完成分区数据写入,最后同时尝试提交更新全局元数据。此时后提交的事务会检测到元数据已被修改,从而抛出ConcurrentAppendException——WriteSerializable并未针对分区隔离做特殊优化,它的串行化保证是基于全局事务日志的,而非分区级。
2. 分区唯一仍触发异常的原因
Delta Lake的事务日志是全局统一管理的,所有写入操作(无论是否涉及不同分区)都会修改_delta_log下的全局事务日志文件。即使写入的region分区完全不重叠,每个写入操作在提交阶段都需要:
- 更新表的全局事务版本号
- 同步最新的分区信息到元数据
- 生成新的事务日志文件
这些全局元数据的修改是互斥操作,毫秒级的并发会导致多个事务同时进入提交阶段,触发乐观锁冲突,进而抛出ConcurrentAppendException。
类似问题情况
这类问题在高并发写入Delta分区表的场景中并不少见,尤其是在Databricks Runtime 14+版本中,由于事务日志的优化调整,部分场景下的并发冲突阈值有所变化,不少用户遇到了分区不重叠但仍触发并发异常的情况。
内容的提问来源于stack exchange,提问作者ng.newbie

