如何复现PostgreSQL与Spark JDBC的连接数超限异常?
问题原因分析
你之前的尝试未触发连接数超限,核心原因是Spark实际并行执行的任务数远低于设置的numPartitions,导致同时打开的JDBC连接数始终达不到PostgreSQL的max_connections上限:
- 你的SparkSession配置了
master("local[2]"),意味着本地模式下最多同时运行2个任务——哪怕把numPartitions设为200,Spark也会串行或少量并行执行分区任务,同时打开的JDBC连接最多仅2个,远低于100的上限。 - 双线程并行场景中,受限于本地核心数限制,两个线程的任务加起来最多同时运行2个,连接数依然未达阈值。
另外补充:PostgreSQL默认会为超级用户预留3个连接(superuser_reserved_connections参数),普通用户实际可用连接数为max_connections - superuser_reserved_connections,但这不是你未触发异常的主要原因。
复现连接数超限的方法
方法1:调整Spark并行度,让任务并发数突破连接上限
修改SparkSession的本地核心数配置,使其大于max_connections,同时保持numPartitions超过实际可用连接数:
object ScalaSession { val reader = SparkSession .builder() .master("local[100]") // 调整为大于max_connections的数值 .appName("spark test") .config("spark.sql.legacy.sizeOfNull", false) .getOrCreate() }
执行单线程的JDBC读取任务后,Spark会同时启动100个任务(每个任务占用一个JDBC连接),超过普通用户可使用的97个连接上限,触发连接超限异常。
方法2:直接用JDBC客户端创建大量持久连接(最直接)
跳过Spark,编写简单程序直接创建超过max_connections的JDBC连接并保持,快速触发异常:
import java.sql.DriverManager object ConnectionTest { def main(args: Array[String]): Unit = { val url = "jdbc:postgresql://localhost:5432/test" val user = "test" val password = "test" val connections = new scala.collection.mutable.ListBuffer[java.sql.Connection]() // 尝试创建101个连接(超过max_connections=100) for (i <- 1 to 101) { try { val conn = DriverManager.getConnection(url, user, password) connections += conn println(s"成功创建第${i}个连接") } catch { case e: Exception => println(s"创建第${i}个连接失败: ${e.getMessage}") } } // 最后关闭连接 connections.foreach(_.close()) } }
运行该程序时,创建到第98个连接时就会抛出FATAL: sorry, too many clients already的异常。
方法3:多线程Spark任务+足够并行度
若要保留多线程Spark场景,除了将Spark master设为local[100],还需将每个任务的numPartitions设为50,两个线程同时执行后,总并发连接数会达到100,触发超限。
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

