Spark 是一个分布式数据处理引擎,因此当您处理数据或将其保存在文件系统上时,它会使用其所有执行程序来执行任务。
Spark JDBC 很慢,因为当您建立 JDBC 连接时,其中一个执行程序会建立到目标数据库的链接,从而导致速度缓慢和失败。
要克服这个问题并加快数据写入数据库的速度,您需要使用以下方法之一:
方法一:
在这种方法中,您需要使用 postgres COPY 命令实用程序 以加快写入操作。这要求您的 EMR 集群上有 psycopg2 库。
COPY 实用程序的文档是here
如果您想了解基准差异以及为什么复制速度更快,请访问here!
Postgres 还建议使用 COPY 命令进行批量插入。现在如何批量插入火花数据帧。
现在要实现更快的写入,首先将您的 spark 数据帧以 csv 格式保存到 EMR 文件系统,然后重新分区您的输出,以便没有文件包含超过 100k 行。
#Repartition your dataframe dynamically based on number of rows in df
df.repartition(10).write.option("maxRecordsPerFile", 100000).mode("overwrite").csv("path/to/save/data)
现在使用 python 读取文件并为每个文件执行复制命令。
import psycopg2
#iterate over your files here and generate file object you can also get files list using os module
file = open('path/to/save/data/part-00000_0.csv')
file1 = open('path/to/save/data/part-00000_1.csv')
#define a function
def execute_copy(fileName):
con = psycopg2.connect(database=dbname,user=user,password=password,host=host,port=port)
cursor = con.cursor()
cursor.copy_from(fileName, 'table_name', sep=",")
con.commit()
con.close()
为了获得额外的速度提升,由于您使用的是 EMR 集群,您可以利用 python 多处理一次复制多个文件。
from multiprocessing import Pool, cpu_count
with Pool(cpu_count()) as p:
print(p.map(execute_copy, [file,file1]))
这是推荐的方法,因为由于连接限制,无法调整 spark JDBC 以获得更高的写入速度。
方法二:
由于您已经在使用 AWS EMR 集群,因此您始终可以利用 hadoop 功能更快地执行表写入。
所以在这里我们将使用 sqoop export 将我们的数据从 emrfs 导出到 postgres db。
#If you are using s3 as your source path
sqoop export --connect jdbc:postgresql:hostname:port/postgresDB --table target_table --export-dir s3://mybucket/myinputfiles/ --driver org.postgresql.Driver --username master --password password --input-null-string '\\N' --input-null-non-string '\\N' --direct -m 16
#If you are using EMRFS as your source path
sqoop export --connect jdbc:postgresql:hostname:port/postgresDB --table target_table --export-dir /path/to/save/data/ --driver org.postgresql.Driver --username master --password password --input-null-string '\\N' --input-null-non-string '\\N' --direct -m 16
为什么是sqoop?
因为 sqoop 会根据指定的 mapper 数量打开与数据库的多个连接。因此,如果您将 -m 指定为 8,那么将有 8 个并发连接流,它们会将数据写入 postgres。
此外,有关使用 sqoop 的更多信息,请参阅AWS Blog、SQOOP Considerations 和 SQOOP Documentation。
如果您可以用自己的方式编写代码,那么方法 1 肯定会为您提供所需的性能提升,如果您对 SQOOP 等 hadoop 组件感到满意,那么请使用第二种方法。
希望对你有帮助!