从依赖地狱到自包含部署:Libevent实盘交易系统的工程化实践
一.问题场景
在完成交易系统的程序里面,使用了libevent库封装网络部分的代码,开发环境是自己的虚拟机,是有互联网的,可以下载libevent。
但是生产环境托管在机房内的机器上,这个机房只有局域网用于交易,没有互联网。所以就无法使用yum install、wget、git clone等需要外网的操作。
并且还有一个问题,就是环境是否一致,如果手动在实盘机上编译安装libevent,可能导致版本与开发环境不一样,例如开发用libevent 2.1.12,实盘机装了2.0.21。依赖链就会断裂。
二.自包含部署的技术方案
上面的问题所以打算用动态库本地打包的方法,做到库与程序绑定,无需修改系统环境,减少对托管机环境的依赖。
2.1把动态库复制到本地lib目录下
首先需要查看程序运行时需要依赖的库,通过命令“ldd /usr/lib64/libevent.so”

这四个按照顺序分别是:内核虚拟库(无需处理);系统线程库;系统C库;动态链接库
所以只需要复制libevent.so和libevent_pthreads.so
复制库文件到项目目录:
cp /usr/lib64/libevent.so /home/tcy/PlaneGM/lib/
cp /usr/lib64/libevent_pthreads.so /home/tcy/PlaneGM/lib/
2.2把需要的库添加到build里面
存在一个新的问题:lib下有libevent.so和libevent_pthreads.so这两个程序运行时会用到的动态库, 然后生成build可执行文件之后放在一个新的虚拟机上就可以直接运行,所以就需要更改配置文件 需要在编译生成时把这两个文件复制到build下的lib里面
在配置文件中复制动态库
# 自动复制所需的动态库到build/lib
add_custom_command(TARGET plane POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lib/libevent.so
${CMAKE_BINARY_DIR}/lib/
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lib/libevent_pthreads.so
${CMAKE_BINARY_DIR}/lib/
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lib/libEESTraderApi_ef.so
${CMAKE_BINARY_DIR}/lib/
COMMENT "Copying required shared libraries to build directory"
)
2.3文件权限问题
把build文件夹复制到新的虚拟机上之后 ./plane会报错 :[tcy2@localhost build]$ ./plane bash: ./plane: Permission denied
报错原因是可执行文件plane没有执行权限。
为什么会出现这个问题
①Linux中新建的文件默认权限是 -rw-r--r--(644),没有执行权限(x)
②CMake生成的可执行文件有时不会自动设置+x权限,特别是当文件系统或构建环境有特殊配置时。
解决方案是:
①可以在编译完成后,在编译机器上赋予执行权限,然后再将整个build目录复制到新的虚拟机上
②在新的虚拟机上赋予执行权限
chmod +x plane
本来想直接在编译器上赋予权限之后 这样直接复制粘贴到新的虚拟机上就可以运行了,但是出现了一个问题:在原来的编译器上赋予执行权限之后,将build复制到新的虚拟机上运行不了,但是在新的虚拟机上用命令chmod +x plane加上之后就能运行了。
所以还是推荐使用第二个方案。
三.运行时关于动态库的问题
程序在用到动态库时 虽然编译会通过 但是运行的时候可能会报错 原因是他在运行时才会加载
3.1动态库的加载时机
(1)编译时(静态检查)
仅检查符号是否存在
编译器(如 gcc)和链接器(ld)会验证程序调用的函数/符号是否在动态库中声明过(通过头文件和链接选项 -lxxx),但不会验证动态库文件本身是否存在或路径是否正确。
不加载库的代码
编译阶段只记录依赖关系(如 libevent.so 是必需的),但不会将库的代码嵌入可执行文件。
(2)运行时(动态加载)
动态链接器(ld-linux)负责加载
程序启动时,动态链接器会根据以下顺序查找并加载动态库:
编译时指定的库路径(如 -Wl,-rpath=/custom/lib)。
环境变量 LD_LIBRARY_PATH 指定的路径。
系统默认库路径(如 /lib64、/usr/lib64)。
此时才会验证库文件是否存在
如果库文件丢失、权限不足或软链接(Symbolic Link)损坏,运行时才会报错(如 error while loading shared libraries: xxx.so: cannot open shared object file)。
3.2复制正确的动态库和软链接
查看程序运行时依赖的动态库

这种箭头指向的是软链接的动态库文件,箭头左侧是链接文件,右侧是目标文件。并且需要注意的是在复制软链接的时候要加上”-P“保留链接结构,否则就会失效。
首先查看这个库的详细信息
[admin@localhost PlaneYD]$ ls -l /usr/lib64/libevent*
lrwxrwxrwx. 1 root root 21 Apr 3 08:57 /usr/lib64/libevent-2.0.so.5 -> libevent-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 297792 Jun 14 2014 /usr/lib64/libevent-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 26 Apr 3 08:57 /usr/lib64/libevent_core-2.0.so.5 -> libevent_core-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 179800 Jun 14 2014 /usr/lib64/libevent_core-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 26 Apr 23 14:16 /usr/lib64/libevent_core.so -> libevent_core-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 27 Apr 3 08:57 /usr/lib64/libevent_extra-2.0.so.5 -> libevent_extra-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 133864 Jun 14 2014 /usr/lib64/libevent_extra-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 27 Apr 23 14:16 /usr/lib64/libevent_extra.so -> libevent_extra-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 29 Apr 3 08:57 /usr/lib64/libevent_openssl-2.0.so.5 -> libevent_openssl-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 24456 Jun 14 2014 /usr/lib64/libevent_openssl-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 29 Apr 23 14:16 /usr/lib64/libevent_openssl.so -> libevent_openssl-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 30 Apr 3 08:57 /usr/lib64/libevent_pthreads-2.0.so.5 -> libevent_pthreads-2.0.so.5.1.9
-rwxr-xr-x. 1 root root 11200 Jun 14 2014 /usr/lib64/libevent_pthreads-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 30 Apr 23 14:16 /usr/lib64/libevent_pthreads.so -> libevent_pthreads-2.0.so.5.1.9
lrwxrwxrwx. 1 root root 21 Apr 23 14:16 /usr/lib64/libevent.so -> libevent-2.0.so.5.1.9
根据上面查看到的程序运行时所需要的动态库在在终端进行复制,注意箭头两边的文件都需要复制,并且格式也要正确

复制完成后查看就是最后的样子。
3.3C++编译指定新版libstdc++库
程序运行时报错:
[root@localhost my_quote_server]# /usr/local/gcc-11.2.0/bin/g++ -o main main.cpp -std=c++17 -lpthread
[root@localhost my_quote_server]# ./main
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.11' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `CXXABI_1.3.13' not found (required by ./main)
./main: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./main)
说明出现了标准库不兼容的问题,系统仍然在使用旧版的libstdc++.so.6
解决方法是A[确认新库路径]->B[设置运行环境]
首先确认新库路径,找到GCC 11.2.0的库位置,通常在安装目录下的lib64/或lib/:
ls -l /usr/local/gcc-11.2.0/lib64/libstdc++.so*
输出示例:确保存在新版库

正确创建软链接
删除错误的链接
sudo rm -f /usr/lib64/libstdc++.so.6
创建正确指向的软链接(使用绝对路径)
sudo ln -s /usr/local/gcc-11.2.0/lib64/libstdc++.so.6.0.29 /usr/lib64/libstdc++.so.6
验证链接状态
ls -l /usr/lib64/libstdc++.so*
输出示例:

至此整个程序在编译以及运行的时候都不会报错了。
更多推荐
所有评论(0)