无法使用来自 AWS Glue 的 cx_oracle 连接 oracle 数据库

Unable to connect oracle database using cx_oracle from AWS Glue

我正在尝试使用 cx_oracle 从 AWS glue 连接 oracle 数据库,但我收到此错误消息

DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file: No such file or directory". See https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html for help

我尝试按照文档下载 so 文件并将其存储在已使用 --extra-files 参数链接到 Glue 的 S3 中,但仍然收到相同的错误消息

我已经尝试过这个 Whosebug question 并且还尝试使用 s3 url 设置 rpath 但没有成功。任何想法都会有帮助

学分

这个答案是 this and this 的汇编,并且在评论中围绕前者进行了大量讨论。 rpath 补丁解决方案归功于上述答案的原作者 @harjeet-singh,libaio 归功于@good-will,但围绕这些问题仍有一些步骤令人困惑的解决方案,这就是为什么我要在此处将所有内容合并为一个 step-by-step 答案。

背景

为了使用 cx-Oracle 从 Python shell AWS Glue 作业连接到 Oracle 数据库,我们需要将 oracle 客户端库与其捆绑在一起。此外,库必须使用正确的 rpath 进行修补才能正确加载,因为在 Glue 运行时中,我们只有 /tmp 的文件系统写入权限,这是我们的存档所在的位置,但是 cx-Oracle 不知道这一点,默认情况下需要一个不同的目录。 LD_LIBRARY_PATH hack 无法实施,因为我们无法控制 Glue 作业的启动方式。

Step-By-Step指南

  1. here 下载适用于 x86-64 Linux 的即时客户端基本 ZIP 包。本指南使用版本 21.5.0.0.0
wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip
  1. 解压缩存档
unzip instantclient-basic-linuxx64.zip 
  1. 从存档中删除符号链接并将它们指向的文件(在本例中 libclntsh.so.21.1 移动到您使用 cx-Oracle 时要查找的文件:libclntsh.so ).这样做是因为无论什么动态加载这些库显然都不会解析符号链接。也许将来会,但我必须这样做才能让它发挥作用。
cd instantclient_21_5/
find . -type l -name "libclntsh.so*" -delete
mv libclntsh.so.21.1 libclntsh.so

如果在完成整个指南和运行你的工作后,你仍然对像

这样的库有问题,那么对其他带有符号链接的文件执行相同的操作

DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libsomething.so: cannot open shared object file: No such file or directory"

  1. 修补 rpath 以指向我们将在 Glue 作业中使用的静态目录 例如,如果您的存档名为 instant-client-basic-linux.x64-21.5.0.0.0,并且它包含一个名为 instantclient_21_5 的文件夹,其中包含所有库。当作业运行时,该存档将在 /tmp 下的随机目录中可用(更多内容见下文。我们需要在这些目录之一中找到我们的存档并将其解压缩到 [=24 下的静态目录中=],例如 /tmp/libs。那么,您的 rpath 将是 /tmp/libs/instant-client-basic-linux.x64-21.5.0.0.0/instantclient_21_5,因为它位于客户端库的绝对路径中。
sudo apt-get update
sudo apt-get install patchelf -y
patchelf --set-rpath /tmp/libs/instant-client-basic-linux.x64-21.5.0.0.0/instantclient_21_5 libclntsh.so
  1. libaio.so.1放入存档
cd ..
wget https://src.fedoraproject.org/lookaside/pkgs/libaio/libaio-0.3.110.tar.gz/2a35602e43778383e2f4907a4ca39ab8/libaio-0.3.110.tar.gz
tar xzvf libaio-0.3.110.tar.gz
cd libaio-0.3.110
make prefix=`pwd`/usr install 
find ./usr/lib/ -type l -name "libclntsh.so*" -delete
mv ./usr/lib/libaio.so.1.0.1 ../instantclient_21_5/libaio.so.1

注意: 如果有更新版本的 libaio,您可能需要检查一下。 6.压缩存档

cd ..
zip -T -r instantclient-basic-linuxx64_patched.zip instantclient_21_5/
  1. 下载cx-Oracle wheel
wget https://files.pythonhosted.org/packages/a9/b7/c2d0223fb4f1013b090cf82f3ce56f36f33b79a48f9c33b36717c2977b04/cx_Oracle-8.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
  1. 上传存档并cx-Oracle到S3
aws s3 cp instantclient-basic-linuxx64_patched.zip s3://<mybucket>/glue_libs
aws s3 cp cx_Oracle-8.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl s3://<mybucket>/glue_libs
  1. 配置您的 Glue 作业

我假设您的粘合作业已经创建,我们将对其进行配置。

  • 将 S3 URL 放入“引用文件路径”配置参数中的存档
  • 将S3URL放到“Python库路径”配置参数cx-Oracle
  1. 向粘合作业添加一些代码以设置库。 此代码必须在使用 cx-Oracle 之前执行。它可以在导入之后执行,但在使用之前执行。

遍历 /tmp 中的随机目录,找到您创建的存档并将其解压缩到我们之前在 rpath 中设置的静态目录中。然后初始化 cx-Oracle 客户端,你就可以开始了。 下面是一个实现示例:

import zipfile

from pathlib import Path

import cx_Oracle

filename = 'instantclient-basic-linuxx64_patched.zip'
oracle_archive = next(Path('./tmp').glob(f'**/{filename}'))
with zipfile.ZipFile(oracle_archive, 'r') as f:
    Path('./tmp/libs').mkdir()
    f.extractall('./tmp/libs')

cx_Oracle.init_oracle_client(lib_dir=f'/tmp/libs/{filename}/instantclient_21_5')

TLDR

运行 这个在你的 Linux 机器上(最后替换你的桶名):

wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip
unzip instantclient-basic-linuxx64.zip
cd instantclient_21_5/
find . -type l -name "libclntsh.so*" -delete
mv libclntsh.so.21.1 libclntsh.so
sudo apt-get update
sudo apt-get install patchelf -y
patchelf --set-rpath /tmp/libs/instant-client-basic-linux.x64-21.5.0.0.0/instantclient_21_5 instantclient_21_5/libclntsh.so
cd ..
wget https://src.fedoraproject.org/lookaside/pkgs/libaio/libaio-0.3.110.tar.gz/2a35602e43778383e2f4907a4ca39ab8/libaio-0.3.110.tar.gz
tar xzvf libaio-0.3.110.tar.gz
cd libaio-0.3.110
make prefix=`pwd`/usr install 
find ./usr/lib/ -type l -name "libclntsh.so*" -delete
mv ./usr/lib/libaio.so.1.0.1 ../instantclient_21_5/libaio.so.1
cd ..
zip -T -r instantclient-basic-linuxx64_patched.zip instantclient_21_5/
wget https://files.pythonhosted.org/packages/a9/b7/c2d0223fb4f1013b090cf82f3ce56f36f33b79a48f9c33b36717c2977b04/cx_Oracle-8.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
aws s3 cp instantclient-basic-linuxx64_patched.zip s3://<mybucket>/glue_libs/
aws s3 cp cx_Oracle-8.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl s3://<mybucket>/glue_libs/

按照上面的第 9 步和第 10 步配置您的作业。

希望任何读过这篇文章的人都能在第一次尝试时就做对,因为我确实没有。