背景
朋友安装了一个 MySQL-8.0.32 版本的 MySQL;其中服务端可以正常运行但是客户端运行不了。
1.1 ps 检查发现 mysqld 确实运行起来了。
代码语言:javascript复制ps -ef | grep mysql
mysql33 407393 1 0 16:00 ? 00:00:03 /usr/local/mysql-8.0.32-linux-glibc2.12-x86_64/bin/mysqld --defaults-file=/etc/my-3306.cnf
root 412577 407779 0 16:21 pts/13 00:00:00 grep --color=auto mysql
1.2 mysql 客户端命令无法运行。
代码语言:javascript复制mysql -uroot -pxxxxxx -h127.0.0.1 -P3306
mysql: error while loading shared libraries: libtinfo.so.5:
cannot open shared object file: No such file or directory
分析
从报错的信息来看就是在加载 libtinfo.so.5 这个共享库的时候失败了。作为一个 cpper 遇到这个问题我还是比较淡定的,因为问题通常只有两个 1. 系统上有这个库文件但是它没有找到,2. 系统上根本就没有这个库文件。
对于情况 1 我们只要想办法让 mysql 能找到对应的库就行了,对于情况 2 我们只要安装上对应的依赖就能解决。
那么剩下的就是分析一下是什么情况了。先补充一下理论,加载库文件本质上就是打开库文件,对应的是 read 这个系统调用,也就是说我们只要追踪一下系统调用就可以分析出来。
2.1 strace 分析系统调用
代码语言:javascript复制strace mysql -uroot -pxxxxxx -h127.0.0.1 -e "exit;"
2.2 通过输出可以看到进程去如下地方找了 libtinfo.so.5
代码语言:javascript复制openat(AT_FDCWD, "/usr/local/mysql-8.0.32-linux-glibc2.12-x86_64/bin/../lib/private/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/glibc-hwcaps/x86-64-v3/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/glibc-hwcaps/x86-64-v2/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/tls/x86_64/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/tls/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/tls/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/tls/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/x86_64/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/x86_64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = 3
进程去了两 “类” 地方找了 libtinfo.so.5 这个库;第一类是 MySQL 的安装目录,第二类是系统默认的库路径。
2.3 确认 libtinfo.so.5 是不是 MySQL 安装包里的库
代码语言:javascript复制tree /usr/local/mysql-8.0.32-linux-glibc2.12-x86_64/lib | grep libtinfo
在 MySQL 的 lib 目录下找不到,说明这个不是 MySQL 自带的库。
2.4 确认是不是系统库
代码语言:javascript复制tree /lib64/ | grep libtinfo
├── libtinfo.so -> libtinfo.so.6
├── libtinfo.so.6 -> libtinfo.so.6.2
├── libtinfo.so.6.2
可以看得出两个结论 1. libtinfo 是系统库;2. 系统上的 libtinfo 库的版本已经升级到了 libtinfo.so.6 。程序找 libtinfo.so.5 所以会找不到。
难道是他的操作系统太新了?我确认一下。
代码语言:javascript复制cat /etc/system-release
CentOS Stream release 9
系统都到 CentOS-9 了确实新!
解决办法
通过前面的分析可以看到由于系统比较新,libtinfo.so 的版本已经升级到 6 了,然而 mysql 还依赖于 5 。/lib64 下面的是基础库,如果采用降级的方式来处理影响面就太大了;最终选择 “骗” 一下 MySQL ,告诉它有一个 libtinfo.so.5 但是实际上是 libtinfo.so.6 。
代码语言:javascript复制# 创建 5 版本的连接文件
cd /lib64
ln -s libtinfo.so libtinfo.so.5
# 重启加载库
ldconfig
检查
代码语言:javascript复制mysql -uroot -pxxxxxx -h127.0.0.1 -P3306
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 22
Server version: 8.0.32 MySQL Community Server - GPL
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
mysql> select @@version;
-----------
| @@version |
-----------
| 8.0.32 |
-----------
1 row in set (0.00 sec)