pyarrow 破坏了 pyodbc MySQL?

问题描述 投票:0回答:1

我有一个 Docker 容器,其中安装了 MySQL ODBC 驱动程序、unixODBC 和一堆 Python 东西。我的 MySQL 驱动程序通过

isql
工作,并且当我使用
pyodbc
从 Python 连接时也可以工作,如果我在新的 Python 进程中这样做的话:

sh-4.4# python
Python 3.8.16 (default, May 31 2023, 12:44:21)
[GCC 8.5.0 20210514 (Red Hat 8.5.0-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyodbc
>>> pyodbc.connect("DRIVER=MySQL ODBC 8.1 ANSI Driver;SERVER=host.docker.internal;PORT=3306;UID=root;PWD=shh")
<pyodbc.Connection object at 0x7f6fd94dac70>

但是,如果我在建立连接之前导入

pyarrow
,我会得到:

sh-4.4# python
Python 3.8.16 (default, May 31 2023, 12:44:21)
[GCC 8.5.0 20210514 (Red Hat 8.5.0-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyarrow
>>> import pyodbc
>>> pyodbc.connect("DRIVER=MySQL ODBC 8.1 ANSI Driver;SERVER=host.docker.internal;PORT=3306;UID=root;PWD=shh")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pyodbc.Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib '/usr/lib64/libmyodbc8a.so' : file not found (0) (SQLDriverConnect)")

如果我直接指定驱动程序的路径,我会得到相同的结果:

sh-4.4# python
Python 3.8.16 (default, May 31 2023, 12:44:21)
[GCC 8.5.0 20210514 (Red Hat 8.5.0-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyarrow
>>> import pyodbc
>>> pyodbc.connect("DRIVER=/usr/lib64/libmyodbc8a.so;SERVER=host.docker.internal;PORT=3306;UID=root;PWD=shh")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pyodbc.Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib '/usr/lib64/libmyodbc8a.so' : file not found (0) (SQLDriverConnect)")

过去,如果缺少库的传递依赖项,就会遇到来自 unixODBC 的相同/类似错误消息,我尝试这样做,试图看看是否有什么东西弄乱了加载器搜索路径。不确定这是否是一个有效的测试,但似乎没有什么问题:

>>> import os
>>> os.system('./lddtree.sh /usr/lib64/libmyodbc8a.so')
libmyodbc8a.so => /usr/lib64/libmyodbc8a.soreadelf: /usr/lib64/libmyodbc8a.so: Warning: Section '.interp' was not dumped because it does not exist!
 (interpreter => none)
readelf: /usr/lib64/libmyodbc8a.so: Warning: Section '.interp' was not dumped because it does not exist!
    libpthread.so.0 => /lib64/libpthread.so.0
    libdl.so.2 => /lib64/libdl.so.2
    libssl.so.1.1 => /lib64/libssl.so.1.1
        libz.so.1 => /lib64/libz.so.1
    libcrypto.so.1.1 => /lib64/libcrypto.so.1.1
    libresolv.so.2 => /lib64/libresolv.so.2
    librt.so.1 => /lib64/librt.so.1
    libm.so.6 => /lib64/libm.so.6
    libodbcinst.so.2 => /lib64/libodbcinst.so.2
        libltdl.so.7 => /lib64/libltdl.so.7
    libstdc++.so.6 => /lib64/libstdc++.so.6
    libgcc_s.so.1 => /lib64/libgcc_s.so.1
    libc.so.6 => /lib64/libc.so.6
    ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
0

我尝试将 pyodbc 和 pyarrow 升级到最新版本,行为是相同的:

pyarrow             13.0.0
pyodbc              4.0.39

我不确定问题是否专门针对 pyarrow,但基于 this bug 在导入 protobuf 时报告类似的行为,我在我的库中搜索了任何引用“protobuf”的内容,并且 pyarrow 弹出了一个头文件,其中包含该头文件姓名。可能是巧合,因为这是在旧版本的 pyarrow 中,而最新版本甚至不再有该文件。

FWIW,容器还有其他不会遇到此问题的 ODBC 驱动程序。

我认为 pyarrow init 正在改变环境中的某些内容,但我还不够 Pythonista,不知道如何识别什么;有进一步调试的技巧吗?

python mysql pyodbc pyarrow unixodbc
1个回答
0
投票

最终证明,这耗尽了分配给动态加载库的 TLS(线程本地存储)的 2048 字节。与 libarrow.so

 相关的 
pyarrow
 对于这块内存来说是一头猪,并且在通过 
pyodbc
 加载 MySQL 驱动程序之前加载它导致 
libmyodbc8a.so
 将使用量推高到该限制。

通过将其添加到

libarrow.so

 环境变量来静态预加载 
LD_PRELOAD
 解决了我的问题。 (我第一次尝试预加载 libmyodbc8a.so,但这导致了一些
其他问题我没有费心去追踪 - 不妨关注pyarrow
,因为无论如何它都是内存消耗者。

libtool

对于诊断确实没有帮助。我最终在本地编译了一个带有宏
LT_DEBUG_LOADERS
设置的版本并运行它以获得打印到STDERR的根本原因错误):“无法在静态TLS块中分配内存”。) 

© www.soinside.com 2019 - 2024. All rights reserved.