Как преодолеть крайние ограничения памяти AWS Glue?

Задание 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. Чего мне не хватает и как можно преодолеть эти ограничения?

Я думаю, что основная проблема заключается в том, что вы используете простое задание оболочки Python, а управление памятью Python не всегда оптимизировано для эффективной обработки больших наборов данных. Есть ли какая-то особая причина, по которой вы выбрали задание оболочки вместо задания искры для такой ресурсоемкой интеграции данных?

Parman M. Alizadeh 31.05.2024 22:08

@ParmanM.Alizadeh Честно говоря, потому что мы не знаем ничего лучшего. Каждая задача Glue в компании выполняется на Python. Я даже не знаю, что такое Искра.

J. Mini 31.05.2024 22:15

Задание Spark выполняется в среде Apache Spark, управляемой AWS Glue. Вы по-прежнему можете писать свой код на Python (используя pyspark), единственная разница — это базовая инфраструктура. Он хорошо оптимизирован для задач, интенсивно использующих память, а также оснащен оптимизированными встроенными соединителями для многих систем баз данных. см. здесь: medium.com/@shuvradipghosh97/…

Parman M. Alizadeh 31.05.2024 22:20

@ParmanM.Alizadeh Должен ли я сделать вывод, что никто из тех, кто знает, что делает, на самом деле не использует Python Shell в Glue?

J. Mini 01.06.2024 00:56

На самом деле это не так, задания оболочки Python просто имеют другой вариант использования и используются для задач с меньшим объемом данных. в то время как искровые задания могут использовать до 8 DPU (32 виртуальных ЦП, 128 ГБ памяти)

Parman M. Alizadeh 01.06.2024 09:19

@ParmanM.Alizadeh Полезно знать. Я искал в графическом интерфейсе способы переключения с Shell на Spark, но не смог его найти. «Тип» установлен на «Python Shell» и просто не изменится. Думаю, мне нужно сделать это по-сложному и настроить JDBC, как подсказывает ваша ссылка.

J. Mini 01.06.2024 16:08

Как вы создаете свои рабочие места? Через консоль или используете ли вы какие-либо инструменты инфраструктуры как кода для настройки своей работы?

Parman M. Alizadeh 03.06.2024 20:29

@ParmanM.Alizadeh CloudFormation.

J. Mini 03.06.2024 20:34

Хорошо, я опубликую ответ, используя CloudFormation.

Parman M. Alizadeh 03.06.2024 20:39

Вы не можете реально подсчитать размер данных, которые вы обрабатываете, с точки зрения окончательного CSV. Кадр данных необходимо сохранить в Python, а затем обработать, и у Python, вероятно, есть некоторые накладные расходы для каждого столбца и т. д., поэтому я почти уверен, что 2,5 ГБ находятся в нижней части оценки для такого типа набора данных.

siggemannen 08.07.2024 21:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
10
227
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Основная проблема заключается в том, что вы используете простое задание оболочки 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 06.06.2024 21:21

@J.Mini Glue уже имеет разъемы JDBC для популярных RDMS. Но вы также можете указать это самостоятельно, как показано в коде. Другой способ заключается в том, что если у вас уже есть клеевое соединение с вашей базой данных, вы можете использовать искатель для каталогизации исходной таблицы и просто использовать каталогизированную таблицу для непосредственного чтения из нее. дайте мне знать, если это ваш случай, и я обновлю свой ответ, включив в него этот подход

Parman M. Alizadeh 06.06.2024 21:24

@J.Mini Кроме того, вы все равно можете использовать тот же подход, который вы использовали в ванильном Python, для подключения к базе данных (например, pyodbc ) в задании склеивания Spark. Но для большей эффективности рекомендуется использовать клеевые соединители.

Parman M. Alizadeh 06.06.2024 21:30

Отличные новости и ужасные новости. Хорошая новость заключается в том, что у меня есть Spark, работающий с минимальными изменениями в исходном коде. Это оказалось намного проще, чем я ожидал, и я не могу отблагодарить вас! Мне даже не пришлось менять соединения/драйвера! Ужасная новость заключается в том, что я, похоже, все же превысил лимит на тот же скромный набор данных. Новое сообщение об ошибке: «ОШИБКА [main] Glue.ProcessLauncher (Logging.scala:logError(77)): Неизвестная ошибка из Python: обратная трассировка ошибок недоступна».

J. Mini 17.06.2024 23:03

@J.Mini Очень сложно понять проблему без отслеживания ошибок и реального кода для воспроизведения. Какую версию клея вы используете?

Parman M. Alizadeh 19.06.2024 09:54

Почти уверен, что это было 4.

J. Mini 19.06.2024 22:04

Другие вопросы по теме