使用 LD_LIBRARY_PATH 解决服务 So 库冲突

最近遇到一个案例,在客户提供的机器上部署业务时,所需要的 So 库和对应的软链接已经存在,但是业务报错显示符号表有缺失,导致服务启动失败。排查原因的时候发现是该机器上部署了一个名为 PubKit 的服务,提前占用了同名软链接且对应的 So 库版本低。那么本着服务互不影响的原则,该怎么处理这个问题呢?

环境情况

为了复现这个问题,记录对应的解决方案,我在家里搭建了一套类似的环境。环境如下:
OS: Kylin Linux Advanced Server release V10 SP3 2403/(Halberd)-x86_64-Build20/20240426
软件: MongoDB 3.4.10 及依赖的 libcrypto.so.1.0.2k、libssl.so.1.0.2k

只模拟 PubKit 服务引起的故障点,已知 PubKit 使用的 So 库软链接是:

  • libcrypto.so.10,对应 libcrypto.so.1.0.0 版本
  • libssl.so.10,对应 libssl.so.1.0.0 版本

想直接找到现成的对应版本 So 库还真有点费劲,毕竟 OpenSSL 1.0.0t 发布时间已经是 2015 年了,CentOS 6.6开始使用的版本基本都是 OpenSSL 1.0.1 版本,但好在可以自行编译,包地址: https://openssl-library.org/source/old/1.0.0/

这里编译 OpenSSL 1.0.0t 时是在CentOS 7.6上进行,主要是担心存在 GCC 版本兼容问题,CentOS 7.6 GCC 是 4.8.5 版本,在兼容范围内

1
2
3
4
5
6
7
cd /home/misaka
tar -xvf openssl-1.0.0t.tar.gz
cd openssl-1.0.0t

# 注意这里是要编译 So 库的,所以要加 shared 参数,因为不打算做安装动作,所以 prefix 和 openssldir 参数都不加
./config shared
make

等待编译完成,即可在当前目录下找到对应的 So 文件: libcrypto.so.1.0.0、libssl.so.1.0.0,将其拷贝出来即可用在故障复现的机器上。

故障复现

1、将上一步准备好的 libcrypto.so.1.0.0、libssl.so.1.0.0 文件上传到 麒麟V10 虚拟机(默认使用 1.1.1f 版本,因此和 1.0.0 系列不冲突)上,并创建软链接,用来模拟客户现场的 PubKit 服务提前占用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost 100]# cp libcrypto.so.1.0.0 /usr/lib64/
[root@localhost 100]# cp libssl.so.1.0.0 /usr/lib64/
[root@localhost 100]# cd /usr/lib64

[root@localhost lib64]# ln -s libcrypto.so.1.0.0 libcrypto.so.10
[root@localhost lib64]# ls -lrt libcrypto*
lrwxrwxrwx 1 root root 19 Feb 28 2024 libcrypto.so.1.1 -> libcrypto.so.1.1.1f
lrwxrwxrwx 1 root root 19 Feb 28 2024 libcrypto.so -> libcrypto.so.1.1.1f
-rwxr-xr-x 1 root root 3078240 Feb 28 2024 libcrypto.so.1.1.1f
-rw-r--r-- 1 root root 5806670 Feb 28 2024 libcrypto.a
-rw-r--r-- 1 root root 2059728 Dec 7 00:33 libcrypto.so.1.0.0
lrwxrwxrwx 1 root root 18 Dec 7 00:34 libcrypto.so.10 -> libcrypto.so.1.0.0

[root@localhost lib64]# ln -s libssl.so.1.0.0 libssl.so.10
[root@localhost lib64]# ls -lrt libssl*
lrwxrwxrwx 1 root root 16 Feb 28 2024 libssl.so.1.1 -> libssl.so.1.1.1f
lrwxrwxrwx 1 root root 16 Feb 28 2024 libssl.so -> libssl.so.1.1.1f
-rwxr-xr-x 1 root root 624664 Feb 28 2024 libssl.so.1.1.1f
-rw-r--r-- 1 root root 1073826 Feb 28 2024 libssl.a
-rwxr-xr-x 1 root root 386368 Mar 15 2024 libssl3.so
-rw-r--r-- 1 root root 441560 Dec 7 01:20 libssl.so.1.0.0
lrwxrwxrwx 1 root root 15 Dec 7 01:21 libssl.so.10 -> libssl.so.1.0.0

2、安装准备好的 MongoDB RPM包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost mongo3.4.10]# ls -lrt
total 93532
-rw-rw-r-- 1 misaka misaka 5988 Dec 7 00:32 mongodb-org-3.4.10-1.el7.x86_64.rpm
-rw-rw-r-- 1 misaka misaka 12193778 Dec 7 00:32 mongodb-org-mongos-3.4.10-1.el7.x86_64.rpm
-rw-rw-r-- 1 misaka misaka 20625955 Dec 7 00:32 mongodb-org-server-3.4.10-1.el7.x86_64.rpm
-rw-rw-r-- 1 misaka misaka 11777295 Dec 7 00:32 mongodb-org-shell-3.4.10-1.el7.x86_64.rpm
-rw-rw-r-- 1 misaka misaka 51164902 Dec 7 00:32 mongodb-org-tools-3.4.10-1.el7.x86_64.rpm

[root@localhost mongo3.4.10]# rpm -ivh *.rpm --force --nodeps
warning: mongodb-org-3.4.10-1.el7.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID a15703c6: NOKEY
Verifying... ################################# [100%]
Preparing... ################################# [100%]
Updating / installing...
1:mongodb-org-tools-3.4.10-1.el7 ################################# [ 20%]
2:mongodb-org-shell-3.4.10-1.el7 ################################# [ 40%]
3:mongodb-org-server-3.4.10-1.el7 ################################# [ 60%]
Created symlink /etc/systemd/system/multi-user.target.wants/mongod.service → /usr/lib/systemd/system/mongod.service.
4:mongodb-org-mongos-3.4.10-1.el7 ################################# [ 80%]
5:mongodb-org-3.4.10-1.el7 ################################# [100%]

3、启动 MongoDB 服务并查看状态,发现服务启动,提示/usr/bin/mongod: symbol FIPS_mode_set version libcrypto.so.10 not defined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost mongo3.4.10]# systemctl start mongod
[root@localhost mongo3.4.10]# systemctl status mongod
● mongod.service - High-performance, schema-free document-oriented database
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Sun 2025-12-07 01:28:24 CST; 4s ago
Docs: https://docs.mongodb.org/manual
Process: 7414 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 7416 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 7418 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 7420 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=127)
Main PID: 7420 (code=exited, status=127)

Dec 07 01:28:24 localhost.localdomain systemd[1]: Starting High-performance, schema-free document-oriented database...
Dec 07 01:28:24 localhost.localdomain systemd[1]: Started High-performance, schema-free document-oriented database.
Dec 07 01:28:24 localhost.localdomain mongod[7420]: /usr/bin/mongod: /lib64/libcrypto.so.10: no version information available (required by /usr/bin/mongod)
Dec 07 01:28:24 localhost.localdomain mongod[7420]: /usr/bin/mongod: /lib64/libcrypto.so.10: no version information available (required by /usr/bin/mongod)
Dec 07 01:28:24 localhost.localdomain mongod[7420]: /usr/bin/mongod: /lib64/libssl.so.10: no version information available (required by /usr/bin/mongod)
Dec 07 01:28:24 localhost.localdomain mongod[7420]: /usr/bin/mongod: relocation error: /usr/bin/mongod: symbol FIPS_mode_set version libcrypto.so.10 not defined in file libcrypto.so.1>
Dec 07 01:28:24 localhost.localdomain systemd[1]: mongod.service: Main process exited, code=exited, status=127/n/a
Dec 07 01:28:24 localhost.localdomain systemd[1]: mongod.service: Failed with result 'exit-code'.

4、查看动态库引用关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost mongo3.4.10]# ldd /usr/bin/mongod
/usr/bin/mongod: /lib64/libcrypto.so.10: no version information available (required by /usr/bin/mongod)
/usr/bin/mongod: /lib64/libcrypto.so.10: no version information available (required by /usr/bin/mongod)
/usr/bin/mongod: /lib64/libssl.so.10: no version information available (required by /usr/bin/mongod)
linux-vdso.so.1 (0x00007ffc0ed99000)
libssl.so.10 => /lib64/libssl.so.10 (0x00007fa28fa5b000)
libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007fa28f69d000)
librt.so.1 => /usr/lib64/librt.so.1 (0x00007fa28f694000)
libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007fa28f68f000)
libm.so.6 => /usr/lib64/libm.so.6 (0x00007fa28f50e000)
libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007fa28f4f5000)
libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007fa28f4d3000)
libc.so.6 => /usr/lib64/libc.so.6 (0x00007fa28f326000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa292a26000)

[root@localhost mongo3.4.10]# ls -lrt /lib64/libcrypto.so.10
lrwxrwxrwx 1 root root 18 Dec 7 00:34 /lib64/libcrypto.so.10 -> libcrypto.so.1.0.0

5、确认 libcrypto.so.1.0.0 中是否包含 symbol FIPS_mode_set,这里可以用nm或者objdump等方法,如不包含则没有任何输出

1
2
[root@localhost mongo3.4.10]# nm -D /usr/lib64/libcrypto.so.10 | grep FIPS_mode_set
[root@localhost mongo3.4.10]# objdump -T /usr/lib64/libcrypto.so.10 | grep FIPS_mode_set

到这里就复现了现场发现的问题,那么该如何解决呢?

解决冲突

确认FIPS_mode_set

确认要准备好的正常 So 库中是包含了 symbol FIPS_mode_set:

1
2
3
4
5
[root@localhost mongo3.4.10]# nm -D ./102/libcrypto.so.1.0.2k | grep FIPS_mode_set
0000000000070b60 T FIPS_mode_set
[root@localhost mongo3.4.10]#
[root@localhost mongo3.4.10]# objdump -T ./102/libcrypto.so.1.0.2k | grep FIPS_mode_set
0000000000070b60 g DF .text 000000000000007a libcrypto.so.10 FIPS_mode_set

配置LD_LIBRARY_PATH

LD_LIBRARY_PATH 是 Linux/Unix 系统中动态链接器(ld-linux.so) 的核心环境变量,用于临时指定共享库(.so 文件)的搜索路径,补充系统默认的库搜索规则,解决「动态库找不到」「多版本库共存」等问题。当执行一个依赖动态库的程序时,系统的动态链接器会按优先级查找所需的 .so 文件,LD_LIBRARY_PATH 是其中优先级较高的「自定义路径来源」。

基于以上的情况,即不能动 PubKit 的服务依赖,又要保证自身业务能运行。那么基于 LD_LIBRARY_PATH 的方案就是一个比较好的办法。具体操作步骤如下:

1、将上述准备好的 libcrypto.so.1.0.2k、libssl.so.1.0.2k 拷贝到 /usr/lib64/mongodb 下,并创建软链接:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost 102]# mkdir -p /usr/lib64/mongodb
[root@localhost 102]# cp libcrypto.so.1.0.2k /usr/lib64/mongodb/
[root@localhost 102]# cp libssl.so.1.0.2k /usr/lib64/mongodb/
[root@localhost 102]# cd /usr/lib64/mongodb/
[root@localhost mongodb]# ln -s libcrypto.so.1.0.2k libcrypto.so.10
[root@localhost mongodb]# ln -s libssl.so.1.0.2k libssl.so.10
[root@localhost mongodb]# ls -lrt
total 2916
-rw-r--r-- 1 root root 2513000 Dec 7 01:45 libcrypto.so.1.0.2k
-rw-r--r-- 1 root root 470360 Dec 7 01:45 libssl.so.1.0.2k
lrwxrwxrwx 1 root root 19 Dec 7 01:45 libcrypto.so.10 -> libcrypto.so.1.0.2k
lrwxrwxrwx 1 root root 16 Dec 7 01:45 libssl.so.10 -> libssl.so.1.0.2k

2、编辑 /usr/lib/systemd/system/mongod.service 文件,在 Environment 中写入 LD_LIBRARY_PATH 配置:

1
2
3
4
5
6
7
[Service]
User=mongod
Group=mongod
# 增加该行
Environment="LD_LIBRARY_PATH=/usr/lib64/mongodb:$LD_LIBRARY_PATH"
Environment="OPTIONS=-f /etc/mongod.conf"
ExecStart=/usr/bin/mongod $OPTIONS

3、daemon-reload 后启动 mongod,可以看到目前服务已经正常启动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost mongodb]# systemctl daemon-reload 
[root@localhost mongodb]# systemctl start mongod
[root@localhost mongodb]# systemctl status mongod
● mongod.service - High-performance, schema-free document-oriented database
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2025-12-07 01:49:52 CST; 1min 11s ago
Docs: https://docs.mongodb.org/manual
Process: 8032 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 8034 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 8036 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
Main PID: 8041 (mongod)
Memory: 41.0M
CGroup: /system.slice/mongod.service
└─8041 /usr/bin/mongod -f /etc/mongod.conf

Dec 07 01:49:52 localhost.localdomain systemd[1]: Starting High-performance, schema-free document-oriented database...
Dec 07 01:49:52 localhost.localdomain systemd[1]: Started High-performance, schema-free document-oriented database.
Dec 07 01:49:52 localhost.localdomain mongod[8039]: about to fork child process, waiting until server is ready for connections.
Dec 07 01:49:52 localhost.localdomain mongod[8040]: forked process: 8041
Dec 07 01:49:53 localhost.localdomain mongod[8039]: child process started successfully, parent exiting

和上面使用 ldd 的方法不同,这里可以用 lsof 结合 pgrep 命令进行确认,确实已经引用了 LD_LIBRARY_PATH 带入的 So 库文件:

1
2
3
4
5
[root@localhost mongodb]# lsof -p $(pgrep mongod) | grep mongodb
mongod 8041 mongod mem REG 253,0 2513000 583497 /usr/lib64/mongodb/libcrypto.so.1.0.2k
mongod 8041 mongod mem REG 253,0 470360 583498 /usr/lib64/mongodb/libssl.so.1.0.2k
mongod 8041 mongod 4w REG 253,0 3702 105520618 /var/log/mongodb/mongod.log
mongod 8041 mongod 8u unix 0x00000000665de206 0t0 87499 /tmp/mongodb-27017.sock type=STREAM

4、但如果执行 mongo 命令,还是会报出如下错误:

1
mongo: relocation error: mongo: symbol FIPS_mode_set version libcrypto.so.10 not defined in file libcrypto.so.10 with link time reference

那么客户端该怎么解决呢?同样也可以在执行 mongo 命令前添加 LD_LIBRARY_PATH,类似如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost mongodb]# LD_LIBRARY_PATH=/usr/lib64/mongodb:$LD_LIBRARY_PATH mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
Server has startup warnings:
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
> exit
bye

但如果每次都这样执行,就未免太过麻烦,业务上访问也多有不便。这里我的思路是可以使用脚本替代的方式,充当一个拐棍的作用。
1)将原客户端 mongo 转移到新目录

1
2
3
cd /usr/bin
mkdir mongodb-client-tools
mv mongo mongodb-client-tools/

2)新建 mongo.sh 脚本,并写入如下内容:

1
2
#!/bin/bash
LD_LIBRARY_PATH=/usr/lib64/mongodb:$LD_LIBRARY_PATH /usr/bin/mongodb-client-tools/mongo

3)增加执行权限并创建软链接:

1
2
[root@localhost bin]# chmod +x mongo.sh 
[root@localhost bin]# ln -s mongo.sh mongo

4)验证可行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost bin]# mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
Server has startup warnings:
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2025-12-07T01:49:52.704+0800 I CONTROL [initandlisten]
>

5)根据上述步骤将 mongoimport、mongoexport 等工具做类似处理即可。

问题思考

经过以上步骤,服务冲突就已经解决完毕,可以开展后续的业务工作,但还是有些内容值得思考的:
1)如果业务上如果有 So 库特定版本依赖并需要创建软链接时,需要考虑下是否为类似 OpenSSL 相关的基础依赖,在部署时是否独占机器,如果非独占,那么还是要考虑下是否会影响其他服务。在本次案例中是采取了主动规避的方案,两边都不受影响,但如果遇到暴力操作,直接解除 PubKit 的软链接再部署服务,那么对业务来说是灾难性的,可能会遇到在排查解决问题时双方互相反复解除软链接的情况。

2)对于业务部署来讲,提前检查环境是必须进行的,除了操作系统、磁盘分区等等基础信息检查项之外,还应该加上业务依赖上的检查,比如 So 版本检查,提前发现问题并制定解决方案,节省现场处理问题的时间。