Perl + DBD::Oracle + mod_perl + Oracle LDAP 名称解析器 = 崩溃?

4
在我使用一个老的Fedora系统时发生了这件事。今天,我设置了一个新的CentOS 6.5,安装了最新的Oracle客户端(12.1.0.1.0),从cpan安装了最新的DBD::Oracle(1.68),但是却遇到了同样的问题:当我尝试连接数据库时,Apache崩溃。当我在命令行或者作为CGI运行相同的Perl脚本时,它能够正常工作;当我关闭sqlnet.ora文件中的LDAP名称解析器时,它也可以正常工作。
回到开始:这是我的startup.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/plain\n\n";
print "connecting: \n";
my $dbh=DBI->connect("dbi:Oracle:mydb", 'username', 'password');
print "connected! \n";

在命令行中运行此代码可以正常工作。在 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, "0\f\2\1\1`\7\2\1\2\4\0\200\0", 14) = 14
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, -1) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\0\20\2\1", 8)       = 8
read(21, "\1a\204\0\0\0\7\n\1\0\4\0\4\0", 14) = 14
write(21, "0\201\226\2\1\2c\201\220\0042cn=bpas_p,cn=OracleCo"..., 153) = 153
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 10000) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\1{\2\1", 8)         = 8
read(21, "\2d\204\0\0\1r\0040cn=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 dump中获取的地址(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和mod_perl。

显然,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名称适配器来解决问题,但我宁愿在投入生产之前修复它。

1个回答

0

我追踪到这个问题是由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) 不能在一个进程中同时使用oracle LDAP名称解析器和系统LDAP库。

b) 如果要使用LDAP解析器,您需要禁用mod_ldap和mod_authnz_ldap。

c) 如果您的服务器不需要php,请同时禁用它。如果需要php,则可以保留启用状态,但必须确保它不会加载系统ldap库。 PHP中的LDAP函数以及依赖它的curl将无法工作。

d) 您可以重命名系统ldap库,以确保它不会被引入,但这将使依赖LDAP的系统上的所有其他内容都失效。(请注意,perl中的Net::LDAP模块不使用此库,因此在重命名后仍将正常工作!)

e) 如果您真的需要php和需要ldap库,则我看到唯一的解决方法是将libldap-2.4.so.2复制到某个未在/ etc / ld.so.cache中的目录中,并为需要该库的程序设置LD_LIBRARY_PATH(但显然不适用于http服务器)。


刚试了一下:在 /etc/php.d/curl.ini 中禁用 curl 也可以,而且不像重命名库那样干扰系统。 - Guntram Blohm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接