【问题标题】:Uploading to MS SQL from Dataflow runs fine with DirectRunner but not DataflowRunner (using pyodbc / msodbcsql18)使用 DirectRunner 但不能使用 DataflowRunner 从 Dataflow 上传到 MS SQL 运行良好(使用 pyodbc / msodbcsql18)
【发布时间】:2022-09-29 18:07:11
【问题描述】:

我们正在尝试使用 Dataflow 将数据从 BigQuery 上传到 Microsoft SQL 服务器。我们使用我安装了 pyodbc 和 msodbcsql18 的 Dataflow flex 环境。

在交互式会话中使用 docker 容器内的 DirectRunner 运行我们的 Dataflow 脚本时,我们没有问题:读取 BigQuery,转换数据并最终上传到 SQL 服务器。

但是,在交互式会话中使用 DataflowRunner 运行相同的脚本时,我们会收到此错误:

Traceback (most recent call last):
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/sdk_worker.py\", line 267, in _execute
    response = task()
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/sdk_worker.py\", line 340, in <lambda> 
    lambda: self.create_worker().do_instruction(request), request)
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/sdk_worker.py\", line 581, in do_instruction
    getattr(request, request_type), request.instruction_id)
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/sdk_worker.py\", line 618, in process_bundle
    bundle_processor.process_bundle(instruction_id))
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/bundle_processor.py\", line 996, in process_bundle
    element.data)
  File \"/usr/local/lib/python3.7/site-packages/apache_beam/runners/worker/bundle_processor.py\", line 221, in process_encoded
    self.output(decoded_value)
  File \"apache_beam/runners/worker/operations.py\", line 346, in apache_beam.runners.worker.operations.Operation.output
  File \"apache_beam/runners/worker/operations.py\", line 348, in apache_beam.runners.worker.operations.Operation.output
  File \"apache_beam/runners/worker/operations.py\", line 215, in apache_beam.runners.worker.operations.SingletonConsumerSet.receive
  File \"apache_beam/runners/worker/operations.py\", line 707, in apache_beam.runners.worker.operations.DoOperation.process
  File \"apache_beam/runners/worker/operations.py\", line 708, in apache_beam.runners.worker.operations.DoOperation.process
  File \"apache_beam/runners/common.py\", line 1200, in apache_beam.runners.common.DoFnRunner.process
  File \"apache_beam/runners/common.py\", line 1281, in apache_beam.runners.common.DoFnRunner._reraise_augmented
  File \"apache_beam/runners/common.py\", line 1198, in apache_beam.runners.common.DoFnRunner.process
  File \"apache_beam/runners/common.py\", line 718, in apache_beam.runners.common.PerWindowInvoker.invoke_process
  File \"apache_beam/runners/common.py\", line 843, in apache_beam.runners.common.PerWindowInvoker._invoke_process_per_window
  File \"/usr/local/lib/python3.7/site-packages/mssql.py\", line 30, in process
    connection = mssql_client.connect(host, database, userid, password)
  File \"/usr/local/lib/python3.7/site-packages/mssql_client.py\", line 5, in connect
    connection = pyodbc.connect(connection_string)
pyodbc.Error: (\"01000 [while running \'Upload to SQL server in 10 threads-ptransform-22\']\", \"[01000] [unixODBC][Driver Manager]Can\'t open lib \'/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.1.so.1.1\' : file not found (0) (SQLDriverConnect)\")

在将图像/模板部署到我们的 GCP 项目时,我们看到了相同的错误。谷歌搜索错误消息显示这是一个相当普遍的问题,并且有不同的解决方案。但它在 DirectRunner 中有效,但在 DataflowRunner 中无效,是不是因为代码在不同的工作程序上运行(由于某种原因没有安装 libmsodbcsql-18.1.so.1.1)而不是在我们的映像上运行已经用下面的 Dockerfile 创建了吗?是执行用户没有适当的文件权限吗?

我们的 Dockerfile:

FROM gcr.io/dataflow-templates-base/python3-template-launcher-base:20220418_RC00

ARG WORKDIR=/dataflow/template
RUN mkdir -p ${WORKDIR}
WORKDIR ${WORKDIR}

COPY transfer.py .
COPY mssql_client.py .

ENV FLEX_TEMPLATE_PYTHON_PY_FILE=\"${WORKDIR}/transfer.py\"

RUN apt-get update -y
RUN apt-get install -y git

RUN pip install -U apache-beam==2.39.0
RUN pip install -U pyodbc==4.0.34

# Install dependency for apt-key
RUN apt-get install -y gnupg2 
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
# Install Microsoft SQL ODBC (dependency for pyodbc)
RUN curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update -y
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql18

mssql_client.py:

# File mssql_client.py
import pyodbc

def connect(host, database, userid, password):
    connection_string = \'DRIVER={/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.1.so.1.1};SERVER=\'+host+\';DATABASE=\'+database+\';UID=\'+userid+\';PWD=\'+password
    connection = pyodbc.connect(connection_string)
    return connection

我们还尝试将DRIVER 参数设置为{ODBC Driver 18 for SQL Server}

我们没有 requirements.txt,而是使用 setuptools:

# File setup.py 

import setuptools

setuptools.setup (
   name=\'setup\',
   version=\'1.0.0\',
   install_requires=[ \'pyodbc\' ],
   packages=setuptools.find_packages(),
)

我也尝试过在install_requires 中添加\'msodbcsql18\',但之后工作就永远挂起。

  • 嗨@OnionJack,问题似乎是找不到路径。你能检查一下驱动程序的路径吗?

标签: python docker google-cloud-dataflow pyodbc


【解决方案1】:

我的问题几乎要解决了

但它在 DirectRunner 中有效,但在 DataflowRunner 中无效,是不是因为代码在不同的 worker 上运行(由于某种原因没有安装 libmsodbcsql-18.1.so.1.1)而不是在我们创建的图像上使用下面的 Dockerfile?

似乎documentation 明确表示只有 requirements.txt 依赖项可用于 Beam 容器:

作为 Dockerfile 的一部分,您需要安装 apache-beam 来生成作业图。请注意,使用 Dockerfile 构建的 Flex Template 容器仅用于创建作业图和启动 Dataflow 作业。安装在 Flex Template 容器中的包在 Beam 容器中不可用。

要使包成为 Beam 容器的一部分,您必须将它们指定为 requirements.txt 文件的一部分。确保您没有将 apache-beam 指定为 requirements.txt 文件的一部分。 Beam 容器已经有 apache-beam。

因为我需要 msodbcsql18,它只能通过 apt 存储库获得,所以我对customizing Beam containers 进行了更多研究。

我终于通过自定义基础容器让它工作了

FROM apache/beam_python3.7_sdk:2.39.0

RUN apt-get update -y

# Install various dependencies for pyodbc
RUN apt-get install -y gnupg2
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update -y
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql18
RUN apt-get install -y unixodbc-dev

RUN pip install -U pyodbc==4.0.34

确保您使用的基础映像包含相同的 Python 和 Dataflow 版本,在我的情况下,我分别使用了 v3.7 和 2.39(请查看原始帖子中 Dockerfile 中的 FROMpip install apache-beam)。

然后,一旦您构建了映像并将其推送到您的 docker 存储库,添加一个附加参数 sdk_container_image 以使用 DataflowRunner 启动您的管道:

--runner=DataflowRunner --sdk_container_image=[your-image-name]

【讨论】:

    猜你喜欢
    • 2023-03-29
    • 2018-01-26
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    相关资源
    最近更新 更多