这发生在我的旧Fedora系统上。今天,我安装了一个新的centos6.5,安装了最新的oracle客户端(12.1.0.1.0),cpan的最新DBD::oracle(1.68),在尝试连接数据库时遇到了同样的问题:apache segfault。当我从命令行尝试相同的perl时,或者作为CGI,它可以工作;当我关闭sqlnet.ora文件中的LDAP名称解析程序时,它也能正常工作。
从头开始:这是我的开始.pl:
$ENV{'NLS_LANG'}='AMERICAN_AMERICA.AL32UTF8';
$ENV{'ORACLE_HOME'}='/opt/oracle/OraHome1';
use DBI ();
use DBD::Oracle ();
这是我的测试程序:
#!/usr/bin/perl
require "startup.pl" unless defined $ENV{'ORACLE_HOME'};
use DBI;
use DBD::Oracle;
print "Content-type: text/plainnn";
print "connecting: n";
my $dbh=DBI->connect("dbi:Oracle:mydb", 'username', 'password');
print "connected! n";
从shell运行此操作效果良好。以CGI脚本运行效果良好。从mod_perl运行它会使apache:崩溃
[Wed Dec 04 16:38:01 2013] [notice] Apache/2.2.15 (Unix) DAV/2 PHP/5.3.3 mod_wsgi/3.2 Python/2.6.6 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations
[Wed Dec 04 16:38:28 2013] [notice] child pid 25756 exit signal Segmentation fault (11)
对httpd进程执行strace显示以下内容:
connect(21, {sa_family=AF_INET, sin_port=htons(389), sin_addr=inet_addr("10.250.52.237")}, 16) = 0
write(21, "0f211`72124 200 ", 14) = 14
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, -1) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0204 2021", 8) = 8
read(21, "1a204 7n1 4 4 ", 14) = 14
write(21, "0201226212c201220 042cn=bpas_p,cn=OracleCo"..., 153) = 153
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 10000) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0204 1{21", 8) = 8
read(21, "2d204 1r 040cn=bpas_p,cn=OracleCont"..., 377) = 377
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
因此,很明显,httpd在与10.250.52.237:389(oracle名称解析程序的ldap端口)通信时崩溃。
我的标准sqlnet.ora是:
NAMES.DIRECTORY_PATH = (LDAP, ONAMES, TNSNAMES)
NAMES.DEFAULT_DOMAIN = xxx.yyyy.zzz
NAMES.PREFERRED_SERVERS =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = oranames01.yyyy.zzz)(PORT = 1501))
(ADDRESS = (PROTOCOL = TCP)(HOST = oranames02.yyyy.zzz)(PORT = 1502))
)
这是我的ldap.ora:
DIRECTORY_SERVERS = (oranames01.yyyy.zzz:389:636, oranames02.yyyy.zzz:389:636)
DEFAULT_ADMIN_CONTEXT = "dc=xxx, dc=yyyy, dc=zzz"
DIRECTORY_SERVER_TYPE = OID
strace转储的地址(10.250.52.237)是oranames01.yyyy.zzz.的IP地址
现在,如果我从sqlnet.ora 中删除LDAP适配器
NAMES.DIRECTORY_PATH = (ONAMES, TNSNAMES)
并将数据库连接字符串放入tnsnames.ora
mydb.xxx.yyyy.zzz=(DESCRIPTION=(SOURCE_ROUTE=OFF)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ivorapo01.xxx.yyyy.zzz)(PORT=15350)))(CONNECT_DATA=(SERVICE_NAME=mydb.xxx.yyyy.zzz)(FAILOVER_MODE =(TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 1))))
一切都很好——命令行、cgi-perl和modperl。
因此,很明显,mod_perl和LDAP名称解析程序的组合似乎存在一些问题。
这种情况发生在我的Fedora 14系统上,首先是apache 2.2.17和Oracle客户端10.2.0.1.0,现在是新安装的CentOs 6.5、apache 2.2.15和Oracle客户端12.1.0.1.0。在谷歌上搜索mod_perl和oracle显示了一些关于oracle_HOME设置太迟的点击(我也有这个,把它放在startup.pl中解决了这个问题),但似乎没有什么适合我的问题。
有人能证实吗?或者,有人能确认mod_perl+DBD::Oracle+Oracle LDAP名称解析在他们的网站上工作吗?现在,我可以通过不使用LDAP名称适配器来解决这个问题,但我希望在投入生产之前解决这个问题。
我追踪到ldap库/lib64/libldap-2.4.so.2
。这个库由mod_ldap、mod_authnz_ldap和mod_php通过一个可选的依赖项使用(依赖项列表似乎是php->libcurl->libssl->libldap,但我并没有真正调查)。这个库还复制了oracle在libclntsh.so
中定义的几个函数名。显然,这些函数彼此不兼容。就我而言,崩溃发生在ldap_search_st中。
一旦我从服务器上删除了mod_php、mod_ldap和mod_authnz_ldap,崩溃就停止了。
由于php对libldap的依赖似乎是可选的,我尝试重新启用php,并将/lib64/libldap-2.4.so.2
重命名为/lib64/libldap-2.4.so.2.disabled
,这样php就不会加载它。我重新启用了php,服务器仍然没有崩溃。
我的服务器上不需要php,所以我再次禁用了php并取消了库重命名。但解决方案似乎是:
a) 您不能在一个进程中同时使用oracleLDAP名称解析程序和系统LDAP库。
b) 如果要使用LDAP解析程序,则需要禁用mod_LDAP和mod_authnz_LDAP。
c) 如果您的服务器不需要php,也可以禁用它。如果确实需要php,则可以保持启用状态,但必须确保它不会加载系统ldap库。php中的Ldap函数以及依赖于它的curl函数将不起作用。
d) 您可以重命名系统ldap库以确保它不会被拉入,但这将扼杀系统中依赖ldap的所有其他内容。(请注意,perl中的Net::LDAP模块不会NOT使用此库,因此在重命名后它仍然可以工作!)。
e) 如果您真的需要php和ldap库,我看到的唯一解决方法是将libldap-2.4.so.2复制到/etc/ld.so.cache中不存在的某个目录,并为需要该库的程序(但显然不是http服务器)将ld_library_PATH设置为该目录。