本文介绍 OceanBase 数据库当前在麒麟 Kylin V10 上 libssl 依赖的相关问题和解决方法。
适用版本
OceanBase 数据库 V2.x 和 V3.x 版本
错误现象
OceanBase 数据库当前在麒麟 Kylin V10 上 libssl 依赖问题出现较多,具体表现在几个方面。
某些旧版本 ODP 以及旧 OceanBase 数据库(如 V2.2.30)版本安装时会报错显示没有对应版本的 libssl 文件,导致 ODP RPM 安装失败。此问题通过以下方式跳过,安装后观测平时可以正常工作。
rpm -ivh <obproxy.rpm> --nodepsODP 启动时由于 libssl 不适配,导致启动失败。譬如:Kylin Linux V10 Tercel + ODP 1.8.10-20210729103745.e17。
ocp_agent 的 python 脚本显示 libssl 报错,导致无法继续相关逻辑操作,python 脚本报错后退出。(OCP 相关操作也会终止)
ImportError: /usr/lib64/python2.7/lib-dynload/_ssl.so: symbol SSLv3_method version OPENSSL_1_1_0 not defined in file libssl.so.1.1 with link time reference "
错误原因
在这些问题里,主要分为两部分。
问题一:RPM 安装由于 libssl 失败
在通过 rpm/yum 安装软件包时,rpm 会检测 rpm 包的相关信息,这些信息可以通过以下命令获得。
# 找不到ODP相关信息
rpm -qR tsar-2.1.66-1.5923e46.el7.x86_64.rpm
config(tsar) = 2.1.66-1.5923e46.el7
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.7)(64bit)
libdl.so.2()(64bit)
libdl.so.2(GLIBC_2.2.5)(64bit)
libm.so.6()(64bit)
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(PayloadIsXz) <= 5.2-1
rtld(GNU_HASH)
在输出中除去 rpmlib 和 sh 的信息,可以看到此 rpm 包需要 libc.so.6、libdl.so.2、libm.so.6 的依赖,如果这些依赖未解决,则安装有类似报错。
#这里专门换了个 rpm 包
rpm -ivh tsar-2.1.66-1.5923e46.el7.aarch64.rpm
error: Failed dependencies:
libdl.so.2(GLIBC_2.17)(64bit) is needed by tsar-2.1.66-1.5923e46.el7.aarch64
问题二:程序运行时 libssl 依赖问题
这里的程序指两个方面,二进制文件和脚本(如 python 脚本)。它们的报错本质上都是一样的,都是在运行调用时发现现有的 libssl.so.* 文件不能满足程序运行的要求。这个问题分为两个细节:1. 调用何处 libssl.so 文件,2. 此文件符不符合程序要求。
如何判断使用何处 libssl.so.* 文件
在运行下有几个关键操作系统变量和文件将影响这个问题。
- LD_LIBRARY_PATH / LIBPATH / SHLIB_PATH
- PYTHONPATH
- /etc/ld.so.conf
这些信息最终主要决定 lib 库在调用时候在操作系统层面何处去寻找相关的 lib 文件。目前,OceanBase 相关产品有两个地方寻找 libssl:一个是操作系统默认路径 /usr/lib64,第二个是在 /home/admin/ocp_agent/site-packages/mysql-vendor 里。其中第二个主要 python 使用,定义在如下。
# /home/admin/ocp_agent/init.d/ocp-agent
export LD_LIBRARY_PATH=/usr/lib64:/usr/lib:/lib64:/lib:/usr/local/lib64:/usr/local/lib:$OCP_AGENT_HOME/libs && export PYTHONPATH=/home/admin/ocp_agent/site-packages && cd /home/admin/ocp_agent && ./ocp_agentd.py start
所以,综上所述,二进制文件运行时主要根据操作系统 LD_LIBRARY_PATH 决定,如果 LD_LIBRARY_PATH 为 NULL,则默认在 /etc/ld.so.conf 文件中查询相关信息,如果还没有,则以 /usr/lib* 为准 (应该和编译以及操作系统默认配置有关)。而 python 则和启动时 python 运行引入的环境变量有关。
此外,部分程序中并未指定具体版本文件,所以会先查找 libssl.so 文件,而不是去找 libssl.so.* 文件。这也是对 libssl.so 做软连接的原因。
如何判断是否符合调用要求
二进制文件里会通过以下命令显示其所需要的动态库依赖。
ldd obproxy
linux-vdso.so.1 => (0x00007fff0e3b5000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f11e9826000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f11e9622000)
libssl.so.10 => /lib64/libssl.so.10 (0x00007f11e93af000)
libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007f11e8f4c000)
librt.so.1 => /lib64/librt.so.1 (0x00007f11e8d44000)
libldap-2.4.so.2 => /lib64/libldap-2.4.so.2 (0x00007f11e8aee000)
libidn.so.11 => /lib64/libidn.so.11 (0x00007f11e88bb000)
libssl3.so => /lib64/libssl3.so (0x00007f11e8663000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f11e8453000)
而在之前讨论的这个报错里显示:
ImportError: /usr/lib64/python2.7/lib-dynload/_ssl.so: symbol SSLv3_method version OPENSSL_1_1_0 not defined in file libssl.so.1.1 with link time reference "
以上反应了依赖的两个问题点:
- Lib 的版本需求。这个信息实际上对应在
libssl.so后缀里(但是修改文件名不解决实际版本问题),所以这里 python 需要的是libssl.so.1.1文件。 - Lib 的方法调用需求。譬如 python 需要 SSLv3_method 方法。
所以如果存在 libssl.so.1.1* 文件,则需要判断是否存在 SSLv3_method 方法。
readelf -a libssl.so.1.1 | grep -i SSLv3_method
如果显示类似的信息 SSLv3_method@@OPENSSL_1_1_0,说明满足了以上两点。
- 对应版本:OPENSSL_1_1_0
- 对应方法:SSLv3_method
解决方法
问题一解决方案
这个报错是由于 rpm 将相关安装的信息存储在其相关 rpmdb 中。所以,如果在安装过程中出现依赖问题,调整、拷贝、删除、软连接任何 libssl* 文件都无助于问题解决。要么使用 rpm --nodeps 跳过依赖检查,要么就需要在 rpmdb 中创建相关的 libssl 信息(包括版本)。
问题二解决方案
所以,对应于第二类问题,有几个实际的解决场景:
调用的 libssl 文件不对,那么让程序选择正确的 lib 文件譬如当前 OCP 在升级 OceanBase 数据库时会选择一台 OBServer 运行 python 脚本做 pre-check task,这时 ocp_agent 的 python 脚本调用 MySQL 相关操作时和自身保存在
/home/admin/ocp_agent/site-packages/mysql-vendor的libssl.so、libcrypto.so不兼容,导致运行失败。此问题,应该是 ocp_agent 的一个 bug。修复方式为移除相关libssl.so.*、libcrypto.so文件,让 python 直接使用操作系统默认的 lib 文件,待任务完成后恢复即可。mv /home/admin/ocp_agent/site-packages/mysql-vendor/lib* /tmp/调用的 libssl 文件无对应版本,或者无相关 method,其实还是文件不对,但是要先找到有相关 method 的文件,再做调整。此类主要常见于 obproxy,或者也见于 python 脚本运行过程中。主要通过替换相关
libssl.so.*/libidn.so.*/libcrypto.so.*文件来实现。程序在判断 libssl 时,先在 LD_LIBRARY_PATH 找到对应路径,再查找对应名称libssl.so文件。所以通过给libssl.so等相关文件做软连接,可以调整 libssl 使用的版本。# 譬如通过拷贝ocp docker来解决部分问题 ln -s libssl.so.10 libssl.so ln -s libidn.so.11 libidn.so ln -s libcrypto.so.10 libcrypto.so
更多信息
/usr/lib* 下无论软连接修改还是添加新的 lib 库,都有一定的风险,主要在于 /usr/lib* 下的 lib 库主要使用者是全操作系统的所有程序。修改和调整这些文件有破坏整体操作系统的风险,此外 libssl(openssl) 和 ssh 等重要进程有依赖关系,安装更新卸载都要有充分的准备。调整最好在设置 LD_LIBRARY_PATH 层面。通过调整 LD_LIBRARY_PATH 可以避免影响整个操作系统的 lib 环境。
export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:<USING_PATH>
/home/admin/ocp_agent/site-packages/mysql-vendor 的 lib 库为 ocp_agent 的 python 脚本自身使用,调整风险相对来说较少。