Linux 环境 libpq加载异常导致psql 连接 PostgreSQL 库失败失败案例

局点现象

  1. 数据库 mdm 升级失败
  2. 检查日志, 发现是由于 psql 连接数据库报错,
psql: symbol lookup error: psql: undefined sybol : PQmblenBounded

定位结论

通常表示 psql 可执行文件所依赖的 libpq 动态库版本与编译时版本不一致或不兼容,即运行时找不到它需要的某个函数(PQmblenBounded)。

web 界面升级, 使用的 shell 非普通 sh xxx.sh 中的shell 环境, 加载的环境变量没那么全, 局点环境中 psql 在运行过程中, 会加载系统自带的库文件缓存路径, 局点默认的缓存为

[root@localhost ~]# ldconfig -p |grep libpq.so.5
	libpq.so.5 (libc6,x86-64) => /usr/local/lib/libpq.so.5
	libpq.so.5 (libc6,x86-64) => /usr/lib64/libpq.so.5

[root@localhost ~]# nm -D /usr/local/lib/libpq.so.5 | grep PQmblenBounded
[root@localhost ~]# nm -D /usr/lib64/libpq.so.5 | grep PQmblenBounded
000000000001b010 T PQmblenBounded@@RHPG_14

[root@localhost ~]# nm -D /program/lib/libpq.so.5 | grep PQmblenBounded
000000000001a8c0 T PQmblenBounded

可以看到 /usr/local/lib下 与 /usr/lib64 下的 库文件中, 没有 PQmblenBounded 函数, 而 我们产品的库文件路径/program/lib 下的 libpq.so.5中是有的

局点环境

[root@localhost lxm]# ldd /program/bin/psql |grep libpq
	libpq.so.5 => /program/lib/libpq.so.5 (0x00007f9a02984000)
[root@localhost lxm]# 
[root@localhost lxm]# echo $LD_LIBRARY_PATH 
/program/lib:/usr/local/fuse/lib:/usr/lib64:/usr/local/lib:/lib:/lib64:/driverfile/lib
[root@localhost lxm]# 
[root@localhost lxm]# ldconfig -p |grep libpq
	libpqwalreceiver.so (libc6,x86-64) => /usr/local/lib/libpqwalreceiver.so
	libpq.so.5 (libc6,x86-64) => /usr/local/lib/libpq.so.5
	libpq.so.5 (libc6,x86-64) => /usr/lib64/libpq.so.5
[root@localhost lxm]# 
[root@localhost lxm]# 
[root@localhost lxm]#  /program/bin/psql -U postgres -c "\c ras; " -c "select current_database()"
You are now connected to database "ras" as user "postgres".
 current_database 
------------------
 ras
(1 row)

补充知识点如下

库文件加载顺序

  1. LD_LIBRARY_PATH 指向的路径
  2. /etc/ld.so.conf.d/xxx.conf
    按照字母排序
  3. ldconfig 缓存的标准系统路径 /lib /lib64 /usr/lib /usr/lib64 等

关键事实:

  1. 默认标准路径

    • 在大多数 Linux 发行版中,/etc/ld.so.conf 文件默认包含以下路径:
      include /etc/ld.so.conf.d/*.conf
      /usr/local/lib    # 这是标准本地软件安装路径
      /usr/lib
      /lib
      
    • 这意味着 /usr/local/lib 总是会被 ldconfig 扫描并加入缓存
  2. 验证方法

    # 1. 检查默认配置
    cat /etc/ld.so.conf
    
    # 典型输出(RHEL/CentOS):
    include ld.so.conf.d/*.conf
    /usr/local/lib    # 明确列出的标准路径
    /usr/lib
    /lib
    
    # 2. 查看缓存中的路径
    ldconfig -v | grep -A1 "search dir"
    
  3. 优先级特性

    • 由于在 /etc/ld.so.conf 中直接定义(而非通过 .d 目录)
    • 它的加载顺序早于 /etc/ld.so.conf.d/ 中的配置文件
    • 因此有较高优先级

您系统中的证据:

[root@localhost ~]# ldconfig -p |grep libpq
    libpq.so.5 (libc6,x86-64) => /usr/local/lib/libpq.so.5   # 来自标准路径
    libpq.so.5 (libc6,x86-64) => /usr/lib64/libpq.so.5       # 来自标准路径

优先级对比表:

路径类型示例优先级来源典型优先级
主配置文件路径/usr/local/lib/etc/ld.so.conf最高
.d目录早期文件/etc/ld.so.conf.d/00-*.conf文件名排序
.d目录后期文件/etc/ld.so.conf.d/99-*.conf文件名排序
LD_LIBRARY_PATH任何自定义路径环境变量最高(但受限制)

解决方案强化:

# 创建超高级别配置文件(00前缀)
sudo tee /etc/ld.so.conf.d/00-pg.conf <<< "/program/lib"

# 重建缓存(确保新路径最先加载)
sudo ldconfig

# 验证缓存顺序(/program/lib 应该在最前面)
ldconfig -p | grep libpq.so.5

最终检查:

# 查看实际加载的库
LD_DEBUG=libs psql -c "SELECT 1" 2>&1 | grep libpq.so

# 预期输出:
#   find library=libpq.so.5 [0]; searching
#     trying file=/program/lib/libpq.so.5   # 应该先尝试这个
#     trying file=/usr/local/lib/libpq.so.5 # 后尝试这个

结论
/usr/local/lib 确实是标准路径且优先级较高,但通过创建 00-pg.conf 文件,您可以强制系统优先使用 /program/lib 中的新版库,完美解决符号缺失问题。

本局点解决方法

echo '/program/lib'  > /etc/ld.so.conf.d/00-pg.conf && ldconfig

[root@localhost ~]# cat /etc/ld.so.conf.d/00-pg.conf 
/program/lib
[root@localhost ~]# ldconfig
[root@localhost ~]# ldconfig -p |grep libpq
	libpqwalreceiver.so (libc6,x86-64) => /program/lib/libpqwalreceiver.so
	libpqwalreceiver.so (libc6,x86-64) => /usr/local/lib/libpqwalreceiver.so
	libpq.so.5 (libc6,x86-64) => /program/lib/libpq.so.5
	libpq.so.5 (libc6,x86-64) => /usr/local/lib/libpq.so.5
	libpq.so.5 (libc6,x86-64) => /usr/lib64/libpq.so.5
	libpq.so (libc6,x86-64) => /program/lib/libpq.so
[root@localhost ~]# 
[root@localhost ~]# ldd /program/bin/psql |grep libpq
	libpq.so.5 => /program/lib/libpq.so.5 (0x00007f5b60bfc000)

可以看到, 现在 /program/lib/libpq.so.5 位于最高优先级了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值