Apache编译后无法正常工作

in 互联网技术 with 0 comment  访问: 4,992 次

问题分析和解决

因为某个场景的需求,要在一个国产系统Rocky4.2(国产凝思4.2操作系统)上安装Apache,虽说此系统是基于Redhat 5.8开发的,但是发现yum安装源包管理,RPM命令倒是能用,但是底层依赖完全没有,这就尴尬了,so,只能源码编译安装了。

当编译完成,启动完成Apache后发现,Apache进程立马僵尸了,状态如下:

localhost:/data/app/httpd-2.4.26/bin # ps aux |grep http
root     22676  0.0  0.0  73888  2016 ?        Ss   10:26   0:00 /data/app/httpd-2.4.26/bin/httpd -k start
daemon   22683  0.0  0.0      0     0 ?        Z    10:26   0:00 [httpd] <defunct>
daemon   22684  0.0  0.0      0     0 ?        Z    10:26   0:00 [httpd] <defunct>
daemon   22685  0.0  0.0      0     0 ?        Z    10:26   0:00 [httpd] <defunct>
daemon   22686  0.0  0.0      0     0 ?        Z    10:26   0:00 [httpd] <defunct>
root     22688  0.0  0.0   5036   936 pts/3    S+   10:26   0:00 grep http

访问默认的页面It works!都访问不出来,查看日志报错如下:

./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init
./httpd: symbol lookup error: ./httpd: undefined symbol: apr_skiplist_init

一直在报如上错误。

既然报apr的问题,应该跟Apache加载apr的动态链接库有关系,那就查看一下Apache加载APR的情况:

localhost:/data/app/httpd-2.4.26/bin # ./httpd -V
Server version: Apache/2.4.26 (Unix)
Server built:   Jan 23 2019 09:39:28
Server's Module Magic Number: 20120211:68
Server loaded:  APR 1.3.0, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/data/app/httpd-2.4.26"
 -D SUEXEC_BIN="/data/app/httpd-2.4.26/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

如上可知我编译的时候编译的apr的版本是1.5.2, 但是Apache没有loaded我编译的版本APR 1.5.2,而现在工作loaded的是APR 1.3.0

这有两个问题,1是这个版本太低了,2是这个版本是个系统自带的猜想,不可控,既然知道问题了,那就想办法让Apache工作load我编译安装的版本吧。

查看Apche所需的动态链接库:

localhost:~ # cd /data/app/httpd-2.4.26/bin
localhost:/data/app/httpd-2.4.26/bin # ldd ./httpd
    linux-vdso.so.1 =>  (0x00007fffba3ff000)
    libpcre.so.1 => /data/app/pcre-8.32/lib/libpcre.so.1 (0x00007f05eed40000)
    libaprutil-1.so.0 => /data/app/apr-util-1.5.4/lib/libaprutil-1.so.0 (0x00007f05eeb1d000)
    libexpat.so.1 => /usr/lib64/libexpat.so.1 (0x00007f05ee8fa000)
    libapr-1.so.0 => /usr/lib64/libapr-1.so.0 (0x00007f05ee6d1000)
    libuuid.so.1 => /lib64/libuuid.so.1 (0x00007f05ee4ce000)
    libcap.so.2 => /lib64/libcap.so.2 (0x00007f05ee2ca000)
    librt.so.1 => /usr/lib64/librt.so.1 (0x00007f05ee0c0000)
    libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f05ede89000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f05edc6e000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f05eda6a000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f05ed72a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f05eef5b000)
    libattr.so.1 => /lib64/libattr.so.1 (0x00007f05ed526000)

Tips: 在ldd命令打印的结果中,=>左边的表示该程序需要连接的共享库之so名称,右边表示由Linux的共享库系统找到的对应的共享库在文件系统中的具体位置。默认情况下/etc/ld.so.conf文件中包含有默认的共享库搜索路径。

如上可知Apache加载的apr的共享库文件的路径是/usr/lib64/libapr-1.so.0,下面让我们来看看这是什么鬼:

localhost:/data/app/httpd-2.4.26/bin # ls -l /usr/lib64/libapr-1.so.0
lrwxrwxrwx 1 sys sys 17  1月 22 09:21 /usr/lib64/libapr-1.so.0 -> libapr-1.so.0.3.0
localhost:/data/app/httpd-2.4.26/bin # ls -l /usr/lib64/libapr-1.so.0.3.0
-rwxr-xr-x 1 sys sys 170776  1月 22 09:21 /usr/lib64/libapr-1.so.0.3.0
localhost:/data/app/httpd-2.4.26/bin # rpm -qf /usr/lib64/libapr-1.so.0.3.0
file /usr/lib64/libapr-1.so.0.3.0 is not owned by any package

如上可知是个软链接,那就好办了,那就把这个文件软链删除,然后软链到我自己的编译的apr的动态库路径,然后在apache load,操作如下:

localhost:/data/app/httpd-2.4.26/bin # rm -rf /usr/lib64/libapr-1.so.0
localhost:/data/app/httpd-2.4.26/bin # ln -s /data/app/apr-1.5.2/lib/libapr-1.so.0.5.2 /usr/lib64/libapr-1.so.0

这样Apache加载动态链接库找到的地址相当于用的是/data/app/apr-1.5.2/lib/libapr-1.so.0.5.2路径的了,就是我编译的。

重启Apache试试,在查看一下状态:

localhost:/data/app/httpd-2.4.26/bin # ./httpd -V
Server version: Apache/2.4.26 (Unix)
Server built:   Jan 23 2019 09:39:28
Server's Module Magic Number: 20120211:68
Server loaded:  APR 1.5.2, APR-UTIL 1.5.4
Compiled using: APR 1.5.2, APR-UTIL 1.5.4
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/data/app/httpd-2.4.26"
 -D SUEXEC_BIN="/data/app/httpd-2.4.26/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

localhost:/data/app/httpd-2.4.26/bin # curl -XGET http://localhost
<html><body><h1>It works!</h1></body></html>

如上可知达到目的了,加载的版本跟我预先编译的是一致的了,默认的页面也可以访问了,问题到这里暂时告落一阶段。


知识补充

如果你使用ldd命令没有找到对应的共享库文件和其具体位置,可能是两种情况引起的:

通常情况下, 许多开放源代码的程序或函数库都会默认将自己安装到/usr/local目录下的相应位置(如:/usr/local/bin 或 /usr/local/lib 等), 以便与系统自身的程序或函数库相区别。而许多Linux系统的/etc/ld.so.conf文件中默认又不包含/usr/local/lib

因此,往往会出现已经安装了共享库,但是却无法找到共享库的情况。具体解决办法如下:

检查/etc/ld.so.conf文件,如果其中缺少/usr/local/lib目录,就添加进去。

注意: 在修改了/etc/ld.so.conf文件或者在系统中安装了新的函数库之后,需要运行一个命令:ldconfig,该命令用来刷新系统的共享库缓存,即/etc/ld.so.cache文件。为了减少共享库系统的库搜索时间,共享库系统维护了一个共享库so名称的缓存文件/etc/ld.so.cache。因此,在安装新的共享库之后,一定要运行ldconfig刷新该缓存。

WeZan