Задание Python Shell не может использовать более одного DPU. Это означает, что у него есть ограничение в 16 ГБ памяти.
Ранее сегодня я подключил то, что считал скромной задачей ETL, к AWS Glue с 1 DPU. Он был написан на Python Shell. Оно длилось чуть больше 10 минут. Теоретически эта задача запрашивает Microsoft SQL Server, размещенный в EC2, создает 3 000 000 строк примерно с 250 столбцами и записывает их в CSV. CSV должен иметь размер около 2,5 ГБ. На практике я получаю
Команда не выполнена из-за нехватки памяти
из клея. Насколько я могу судить, эта ошибка возникает не из-за SQL; Это связано с тем, что 1 DPU недостаточно. Пакетирование запросов и запись в CSV устранили эту проблему, но мне не хотелось этого делать.
Это меня очень глубоко смущает. Я не считаю 2,5 ГБ данных необоснованным объемом для ETL. Как человек с опытом работы с SQL, я съедаю на завтрак 2,5 ГБ и выполнял ту же самую задачу в SSIS много лет назад. Python не выполняет каких-либо сложных манипуляций с данными. Он просто извлекает его из SQL и записывает в новые файлы CSV на S3.
Это дает мне мой вопрос. AWS Glue рекламируется как инструмент ETL облачного масштаба, но мой опыт, описанный выше, показывает, что он не может справиться с скромными задачами ETL. Чего мне не хватает и как можно преодолеть эти ограничения?
@ParmanM.Alizadeh Честно говоря, потому что мы не знаем ничего лучшего. Каждая задача Glue в компании выполняется на Python. Я даже не знаю, что такое Искра.
Задание Spark выполняется в среде Apache Spark, управляемой AWS Glue. Вы по-прежнему можете писать свой код на Python (используя pyspark), единственная разница — это базовая инфраструктура. Он хорошо оптимизирован для задач, интенсивно использующих память, а также оснащен оптимизированными встроенными соединителями для многих систем баз данных. см. здесь: medium.com/@shuvradipghosh97/…
@ParmanM.Alizadeh Должен ли я сделать вывод, что никто из тех, кто знает, что делает, на самом деле не использует Python Shell в Glue?
На самом деле это не так, задания оболочки Python просто имеют другой вариант использования и используются для задач с меньшим объемом данных. в то время как искровые задания могут использовать до 8 DPU (32 виртуальных ЦП, 128 ГБ памяти)
@ParmanM.Alizadeh Полезно знать. Я искал в графическом интерфейсе способы переключения с Shell на Spark, но не смог его найти. «Тип» установлен на «Python Shell» и просто не изменится. Думаю, мне нужно сделать это по-сложному и настроить JDBC, как подсказывает ваша ссылка.
Как вы создаете свои рабочие места? Через консоль или используете ли вы какие-либо инструменты инфраструктуры как кода для настройки своей работы?
@ParmanM.Alizadeh CloudFormation.
Хорошо, я опубликую ответ, используя CloudFormation.
Вы не можете реально подсчитать размер данных, которые вы обрабатываете, с точки зрения окончательного CSV. Кадр данных необходимо сохранить в Python, а затем обработать, и у Python, вероятно, есть некоторые накладные расходы для каждого столбца и т. д., поэтому я почти уверен, что 2,5 ГБ находятся в нижней части оценки для такого типа набора данных.
Основная проблема заключается в том, что вы используете простое задание оболочки Python, а управление памятью Python не всегда оптимизировано для эффективной обработки больших наборов данных. В этом случае вам следует настроить задание для запуска на движке Spark.
Задание Spark выполняется в среде Apache Spark, управляемой AWS Glue. Вы по-прежнему можете писать свой код на Python (используя pyspark), единственная разница — это базовая инфраструктура. Он хорошо оптимизирован для задач с интенсивным использованием памяти, а также оснащен оптимизированными встроенными соединителями для многих систем баз данных (подробнее см. здесь).
Существуют различные способы создания и настройки задания Glue.
Вы можете использовать визуальную консоль для создания задания. Вам нужно перейти к AWS Glue -> ETL Jobs -> Create job -> Author code с помощью редактора скриптов. Затем вам нужно настроить двигатель на Spark
вот так:
Если вы используете CloudFormation
или AWS CDK
, вам необходимо указать name
под command
до glueetl
, который установит искру в качестве двигателя, а не pythonshell
для заданий оболочки Python.
CloudFormation example:
MyJob:
Type: AWS::Glue::Job
Properties:
Command:
Name: glueetl
ScriptLocation: "s3://<your-S3-script-uri>"
DefaultArguments:
"--job-bookmark-option": "job-bookmark-enable"
ExecutionProperty:
MaxConcurrentRuns: 2
MaxRetries: 0
Name: cf-job1
Role: !Ref MyJobRole
Пример AWS CDK:
import aws_cdk.aws_glue as glue
myjob= glue.CfnJob(
self,
"MyJob",
command=glue.CfnJob.JobCommandProperty(
name = "glueetl",
python_version = "3",
script_location = "s3://<your-S3-script-uri>",
),
role=MyJobRole,
default_arguments = {
"--job-bookmark-option": "job-bookmark-disable",
},
execution_property=glue.CfnJob.ExecutionPropertyProperty(
max_concurrent_runs=1
),
glue_version = "4.0",
max_retries=0,
name = "cf-job1",
number_of_workers=2,
worker_type = "G.1X"
)
Простое задание по чтению из базы данных SQL Server может быть следующим:
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext, SparkConf
from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark.sql import SQLContext
from awsglue.dynamicframe import DynamicFrame
args = getResolvedOptions(sys.argv, ['JOB_NAME'])
sc = SparkContext()
glue_context = GlueContext(sc)
spark = glue_context.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)
connection_sqlserver_options = {
"url": "",
"dbtable": "",
"user": "",
"password": ""}
df= glue_Context.create_dynamic_frame.from_options(connection_type = "sqlserver",
connection_options=connection_sqlserver_options)
Вы также можете использовать любой пользовательский коннектор, указав путь к нему .jar
:
# Add the Spark SQL Server Connector package
spark.sparkContext.addPyFile("path/to/spark-sqlserver-connector.jar")
# Read data from SQL Server using the Spark SQL Server Connector
df = spark.read.format("com.microsoft.sqlserver.jdbc.spark") \
.option("url", "jdbc:sqlserver://your_sqlserver_host:1433;database=mydb") \
.option("dbtable", "mytable") \
.option("user", "your_username") \
.option("password", "your_password") \
.load()
# Write the data frame to S3 as Parquet files
s3_output_path = "s3://my-bucket/output/"
df.write.mode("overwrite").parquet(s3_output_path)
Должны ли соединения с базой данных быть особенными при настройке их для Spark? Я помню, что им нужно было что-то вроде JDBC. В Python Shell мне достаточно просто подключить подсети/VPC и подключиться через них.
@J.Mini Glue уже имеет разъемы JDBC для популярных RDMS. Но вы также можете указать это самостоятельно, как показано в коде. Другой способ заключается в том, что если у вас уже есть клеевое соединение с вашей базой данных, вы можете использовать искатель для каталогизации исходной таблицы и просто использовать каталогизированную таблицу для непосредственного чтения из нее. дайте мне знать, если это ваш случай, и я обновлю свой ответ, включив в него этот подход
@J.Mini Кроме того, вы все равно можете использовать тот же подход, который вы использовали в ванильном Python, для подключения к базе данных (например, pyodbc
) в задании склеивания Spark. Но для большей эффективности рекомендуется использовать клеевые соединители.
Отличные новости и ужасные новости. Хорошая новость заключается в том, что у меня есть Spark, работающий с минимальными изменениями в исходном коде. Это оказалось намного проще, чем я ожидал, и я не могу отблагодарить вас! Мне даже не пришлось менять соединения/драйвера! Ужасная новость заключается в том, что я, похоже, все же превысил лимит на тот же скромный набор данных. Новое сообщение об ошибке: «ОШИБКА [main] Glue.ProcessLauncher (Logging.scala:logError(77)): Неизвестная ошибка из Python: обратная трассировка ошибок недоступна».
@J.Mini Очень сложно понять проблему без отслеживания ошибок и реального кода для воспроизведения. Какую версию клея вы используете?
Почти уверен, что это было 4.
Я думаю, что основная проблема заключается в том, что вы используете простое задание оболочки Python, а управление памятью Python не всегда оптимизировано для эффективной обработки больших наборов данных. Есть ли какая-то особая причина, по которой вы выбрали задание оболочки вместо задания искры для такой ресурсоемкой интеграции данных?