Соединение Apache Airflow и Oracle

Я пытаюсь прочитать данные из локальной базы данных Oracle (база данных Oracle 11g, версия 11.2.0.4.0 — 64-битная версия).

Я создал свой собственный образ докера:

# Use the base Apache Airflow image
FROM apache/airflow:2.8.3
# Set environment variables for the Oracle Instant Client
ENV ORACLE_HOME=/opt/oracle
ENV LD_LIBRARY_PATH=$ORACLE_HOME/lib
# Switch to the root user temporarily
USER root
# Install required packages
RUN apt-get update && apt-get install -y \
    unzip \
    libaio1 \
    && rm -rf /var/lib/apt/lists/*
# Create the Oracle directory with proper permissions
RUN mkdir -p $ORACLE_HOME && chown -R airflow: $ORACLE_HOME
# Create the tmp directory with proper permissions
RUN mkdir -p /tmp && chown -R airflow: /tmp
# Switch back to a non-root user (e.g., "airflow")
USER airflow
# Install Python packages required for Oracle client and Airflow Oracle provider
RUN pip install oracledb apache-airflow-providers-oracle pandas sqlalchemy
# Download and install the Oracle Instant Client
# https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html
COPY instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/
COPY instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip /tmp/
RUN unzip /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME && \
    unzip -o /tmp/instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME 
# Delete ZIP Files
RUN rm -rf /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip
# Set environment variables for Oracle Instant Client
ENV PATH=$PATH:$ORACLE_HOME
ENV ORACLE_VERSION=19.22

Вкратце: в стандартный образ добавлены oracledb apache-airflow-providers-oracle pandas sqlalchemy, а также Instantclient-basic-linux.x64-19.22.0.0.0dbru.zip с oracle.com.

Сборка docker compose работает, init docker compose работает, компоновка docker работает без ошибок.

Oracle отображается как тип соединения, и я создал соединение:

Мой тестовый DAG выглядит так:

from datetime import datetime
from airflow import DAG
from airflow.decorators import task
from airflow.providers.oracle.hooks.oracle import OracleHook

table_name = "DB.TABLE"
@task
def get_data_from_oracle():
    oracle_hook=OracleHook(oracle_conn_id='Oracle_***')
    data = oracle_hook.get_pandas_df(sql=f"SELECT COUNT(1) FROM {table_name}")
    return data.to_dict()

with DAG('oracle_test', start_date=datetime(2022, 1, 1), schedule_interval='@once') as dag:
    data = get_data_from_oracle()

Если я запущу указанный DAG, я получу ошибки, которые не смогу устранить. Он работает около минуты и завершается с такими ошибками: (я предполагаю, что время ожидания истекло)

[2024-03-21T10:27:31.754+0000] {standard_task_runner.py:107} ОШИБКА — не удалось выполнить задание 8 для задачи get_data_from_oracle (DPY-6005: невозможно подключиться к базе данных (CONNECTION_ID=P26GiMCTIFWWPDhhkB4vZQ==). DPY-4011: база данных или сеть закрыли соединение. [Errno 104] Сброс соединения с помощью узла Помощь: https://python-oracledb.readthedocs.io/en/latest/user_guide/troubleshooting.html#dpy-4011; 534)

Или, в зависимости от конфигурации: (без тайм-аута)

[2024-03-21, 16:57:08 CET] {standard_task_runner.py:107} ОШИБКА — не удалось выполнить задание 16 для задачи get_data_from_oracle (DPY-6005: невозможно подключиться к базе данных (CONNECTION_ID=Ma2uz0YYUUhkdOMBsNNS0w==). DPY-6003: SID «**» не зарегистрирован в прослушивателе на хосте «10...» через порт 1524. (Аналогично ORA-12505); 5827)

Я дважды проверил IP, пинг, SID (через запрос) и так далее.

Я предполагаю, что делаю что-то ужасно неправильное либо

  1. Настройка контейнера
  2. ДАГ
  3. Связь с Oracle (что правда неясно в документация)

В любом случае интернет-исследования не привели к решению. Если кто-нибудь может дать мне советы или рабочий способ подключения к базе данных Oracle, я был бы благодарен. Пожалуйста, не заставляйте меня возвращаться в SSIS.

Обновление: тот же запрос к БД с Oracle Database 12c Release 12.1.0.1.0 — 64-битная версия работает без проблем. Похоже, проблема в версии/драйверах.

Судя по сообщению об ошибке, вы пытаетесь подключиться к Oracle через порт 1524. Вы на 100% уверены, что это правильно? Обычно Oracle работает на порту 1521.

Frank Schmitt 21.03.2024 17:10

Да, я проверил дважды и трижды. Я могу подключиться к указанному порту через DBeaver (и взаимодействовать с базой данных), а также TNSPING имени и получить порт 1524 в качестве ответа. У меня нет объяснений, почему этот порт был перенесен... может быть, нескольким экземплярам/службам на одном хосте Linux требуются разные порты? Попробую 1521 очень быстро, просто чтобы исключить это.

Michael 22.03.2024 08:05

Интересно: если я изменю порт, ошибка изменится: правый порт: на порту не зарегистрирован SID... неправильный порт: невозможно подключиться к БД. Итак, я предполагаю, что БД каким-то образом реагирует или, по крайней мере, до него доходит воздушный поток.

Michael 22.03.2024 08:13

Согласно python-oracledb.readthedocs.io/en/latest/user_guide/…, одна из возможных причин DPY-4011 заключается в том, что БД применяет собственное сетевое шифрование (NNE), которое не поддерживается в тонком режиме. Не могли бы вы запустить запрос SELECT network_service_banner FROM v$session_connect_info; в своей базе данных Oracle, чтобы проверить, включен ли NNE?

Frank Schmitt 22.03.2024 09:40

Я не уверен, как связать эту таблицу с «моей» попыткой подключения: > ВЫБЕРИТЕ ОТЛИЧНЫЙ OSUSER FROM v$session_connect_info Адаптер протокола TCP/IP NT для Linux: версия 11.2.0.4.0 — производственная Oracle Advanced Security: служба криптографического контрольного суммирования для Linux: версия 11.2.0.4.0 — производственная версия Oracle Advanced Security: служба шифрования для Linux: версия 11.2.0.4.0 — рабочая версия (обратите внимание на различия)

Michael 22.03.2024 14:54

База данных Oracle 12c, выпуск 12.1.0.1.0 — 64-битная версия <- Кажется, эта версия работает?! Так это похоже на проблему с версией БД?! Буду тестировать дальше.

Michael 22.03.2024 15:43
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
7
507
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я наконец понял это: соединение с правильным параметром (я допустил ошибку, потому что копипаст из tnsping, похоже, по умолчанию дает 2 хоста) дает вам эту ошибку:

DPY-3010: подключения к этой версии сервера базы данных не поддерживаются python-oracledb в тонком режиме.

Оракул утверждает:

Например, Oracle Call Interface 21 может подключаться к базе данных Oracle 12.1 или более поздней версии, а Oracle Call Interface 19.3 — к базе данных Oracle 11.2 или более поздней версии. Некоторые инструменты могут иметь другие ограничения.

Источник: https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html

Проблема с переходом на более раннюю версию заключается в том, что вы можете столкнуться с проблемами совместимости с более новыми версиями oracle или airflow. Таким образом, обходной путь заключается в использовании «толстого режима», который поддерживает более старые версии oracle.

С помощью Ошибка DPY-3010 при подключении python-oracledb к Oracle DB 11.2 вы попадаете на https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/connections/oracle. html, в котором объясняется, как получить доступ к базе данных Oracle через «толстый режим» в DAG:

def get_data_from_oracle():
oracle_hook=OracleHook(oracle_conn_id='Connection_Name', thick_mode=True)
data = oracle_hook.get_pandas_df(sql=f"SELECT COUNT(1) FROM {table_name}")
return data.to_dict()

Далее вам необходимо убедиться, что вы правильно настроили мгновенный клиент Oracle. Zip-архив oracle (instantclient-basic-linux.x64-19.22.0.0.0dbru.zip) содержит подпапку с названием версии. Если вы скопируете его содержимое в $ORACLE_HOME, airflow/python/oracle не сможет найти файлы в ожидаемой папке.

DPI-1047: Невозможно найти 64-разрядную клиентскую библиотеку Oracle: «/opt/oracle/lib/libclntsh.so: невозможно открыть общий объектный файл: нет такого файла или каталога».

Я навсегда исправил это с помощью unzip -j (сглаживание папок в ZIP) в моем файле docker:

# Use the base Apache Airflow image
FROM apache/airflow:2.8.3
# Set environment variables for the Oracle Instant Client
ENV ORACLE_HOME=/opt/oracle
ENV LD_LIBRARY_PATH=$ORACLE_HOME
# Switch to the root user temporarily
USER root
# Install required packages
RUN apt-get update && apt-get install -y \
    unzip \
    libaio1 \
&& rm -rf /var/lib/apt/lists/*
# Create the Oracle directory with proper permissions
RUN mkdir -p $ORACLE_HOME && chown -R airflow: $ORACLE_HOME
# Create the tmp directory with proper permissions
RUN mkdir -p /tmp && chown -R airflow: /tmp
# Switch back to a non-root user (e.g., "airflow")
USER airflow
# Install Python packages required for Oracle client and Airflow Oracle provider
RUN pip install cx_Oracle oracledb apache-airflow-providers-oracle pandas sqlalchemy
# Download and install the Oracle Instant Client
# https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html
COPY instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/
RUN unzip -j /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME 
# Delete ZIP Files
RUN rm -rf /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip
# Set environment variables for Oracle Instant Client
ENV PATH=$PATH:$ORACLE_HOME
ENV ORACLE_VERSION=19.22

При этом соединения со «старыми» (до 12.1) системами работают до тех пор, пока вы включаете толстый режим.

Следующие шаги:

  • Я уверен, что кто-то может придумать лучшее решение, чем распаковать -j
  • Возможно, есть способ ввести Thick_mode=true на уровне соединения воздушного потока, чтобы вам не приходилось вставлять это для каждого дага.

P.s. спасибо https://stackoverflow.com/users/610979/frank-schmitt за комментарии!

Некоторые дополнительные комментарии: (i) не устанавливайте ORACLE_HOME для Instant Client, поскольку это может привести к конфликтам. (ii) используйте ldconfig вместо LD_LIBRARY_PATH, поскольку последний имеет некоторые ограничения (например, сброс в некоторых средах). Несколько советов см. в разделе Docker для приложений баз данных Oracle на Node.js и Python.

Christopher Jones 11.04.2024 16:07

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