PHP PDO SQLSRVR 在数据库上的 cpu 使用率高
PHP PDO SQLSRVR high cpu usage on Database
重新安装 Ubuntu 服务器 18.04 后我遇到了一个奇怪的问题。
我的 “服务器 1” 有这些软件包和驱动程序来连接 PHP-FPM + Apache 与 远程 Sql 服务器数据库 2016,连接使用 IPv4。
$ odbcinst --version
unixODBC 2.3.7
$ apt list msodbcsql17
msodbcsql17/bionic,now 17.7.2.1-1 amd64 [installed]
$ php --re pdo_sqlsrv | head -1
Extension [ <persistent> extension #33 pdo_sqlsrv version 5.9.0 ]
$ php --re sqlsrv | head -1
Extension [ <persistent> extension #41 sqlsrv version 5.9.0 ]
下面是我的/etc/odbcinst.ini内容:
$ cat /etc/odbcinst.ini
[ODBC Driver 17 for SQL Server]
Description=Microsoft ODBC Driver 17 for SQL Server
Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.7.so.2.1
UsageCount=1
$ openssl version
OpenSSL 1.1.1 11 Sep 2018
我的两台服务器都是Ubuntu18.04,所有包都升级了
澄清一下,我们在 Ubuntu 方面没有问题,问题在 SQL 服务器上。
使用我的 “服务器 1”、Linux 和 SQL 服务器都可以而且速度很快。
但是使用我的 “服务器 2”,安装新的 Ubuntu 18.04,我的 SQL 服务器使用率超过 90% CPU,并且Linux仍然很快。
这两个 Linux 使用上面列出的相同包和驱动程序,具有完全相同的版本。
执行的PHP代码在两台服务器上完全相同。
我忘记在我的 "Server 2"?
上查看另一个包或配置
我不知道是否有关系,但在我的 SQL 服务器上,ODBC 驱动程序版本是 13。可能不是,因为 "Server 1"不会引起问题。
谢谢!
终于找到问题了!
快速回答
在 SQL 服务器上读取 trace log,在“应用程序名称”字段中,我们可以观察到一些来源调用数据库(Apache、PHP-FPM 和 PHP Freetds)
使用 PHP SQLSRV (pdo) 时出现问题,仅使用 FreeTDS (php ext DBLIB) 没有问题。
那么在 unix 系统上只使用 PHP DBLIB with FreeTDS 是个好主意。
完整回答
TL;DR;
当然,问题不仅仅在于 PHP SQLSRV 扩展。在我们的调查中,我们查看驱动程序版本,客户端 Linux 使用最新版本的驱动程序 MSODBCSQL17。
但是在我们的服务器上,运行 SQL SERVER 2016,驱动版本是13。
但是 Microsoft 有一个 upgrade to version 17(与 Linux 客户端上使用的相同)
正在阅读更改日志,issue about high cpu usage is fixed。
“你能证明吗?”
是的!
我们做了一个简单的测试,在我们的 linux“服务器 1”上,我们删除了对 freetds 的支持(禁用 DBLIB),我们立即可以在仪表板上观察到性能下降,几分钟后,当再次启用 freetds (DBLIB) 时,性能 returns 恢复正常,见上文。
我们的新 linux 没有安装 freetds,我们只从 Microsoft 获取驱动程序到 PHP 7+ 和 PECL 扩展。
问题是因为我们的 SQL 服务器使用 ODBC 驱动程序 13 而我们的客户使用 ODBC 驱动程序 17。
我们无法在 SQL SERVER 上升级驱动程序,因为我们需要此版本,并且仅在 SQL SERVER 2019 上支持 ODBC 17。
那么,目前我们的解决方案是使用 freetds 而不是 PHP SQLSRV 扩展。
要注意的另一点是,来自 PHP SQLSRV 的所有查询都是 parametrized,如下所示:
Declare @Out int;
EXEC sp_prepexec @Out output,
N'@P1 nvarchar(128), @P2 nvarchar(100)',
N'SELECT database_id, name
FROM sys.databases
WHERE name=@P1 AND state_desc = @P2',
@P1 = 'tempdb', @P2 = 'ONLINE';
EXEC sp_unprepare @Out;
与 freetds 相同的查询出现在跟踪日志中,如下所示:
SELECT database_id, name
FROM sys.databases
WHERE name='tempdb' AND state_desc='ONLINE';
我认为这种差异使得 SQL 服务器强制使用更多 CPU 比具有更简单查询的 FreeTDS。
但是你两个都安装了,怎么决定用哪个?
是的,在我的“服务器 1”上,我们同时安装了驱动程序和扩展程序,但我的应用程序决定首先使用 DBLIB 可用,我们使用 Laravel, and this code is inside connector:
/**
* Create a DSN string from a configuration.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
// First we will create the basic DSN setup as well as the port if it is in
// in the configuration options. This will give us the basic DSN we will
// need to establish the PDO connections and return them back for use.
if (in_array('dblib', $this->getAvailableDrivers())) {
return $this->getDblibDsn($config);
} elseif ($this->prefersOdbc($config)) {
return $this->getOdbcDsn($config);
} else {
return $this->getSqlSrvDsn($config);
}
}
结论
我不知道我的应用程序在安装 PHP SQLSRV 后仍然使用 FreeDTS,这个问题以前没有出现过,因为 laravel 偏好 dblib。
这个问题太难找了,希望大家的分析能帮到看到这行的你
谢谢!
;)
重新安装 Ubuntu 服务器 18.04 后我遇到了一个奇怪的问题。
我的 “服务器 1” 有这些软件包和驱动程序来连接 PHP-FPM + Apache 与 远程 Sql 服务器数据库 2016,连接使用 IPv4。
$ odbcinst --version
unixODBC 2.3.7
$ apt list msodbcsql17
msodbcsql17/bionic,now 17.7.2.1-1 amd64 [installed]
$ php --re pdo_sqlsrv | head -1
Extension [ <persistent> extension #33 pdo_sqlsrv version 5.9.0 ]
$ php --re sqlsrv | head -1
Extension [ <persistent> extension #41 sqlsrv version 5.9.0 ]
下面是我的/etc/odbcinst.ini内容:
$ cat /etc/odbcinst.ini
[ODBC Driver 17 for SQL Server]
Description=Microsoft ODBC Driver 17 for SQL Server
Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.7.so.2.1
UsageCount=1
$ openssl version
OpenSSL 1.1.1 11 Sep 2018
我的两台服务器都是Ubuntu18.04,所有包都升级了
澄清一下,我们在 Ubuntu 方面没有问题,问题在 SQL 服务器上。
使用我的 “服务器 1”、Linux 和 SQL 服务器都可以而且速度很快。
但是使用我的 “服务器 2”,安装新的 Ubuntu 18.04,我的 SQL 服务器使用率超过 90% CPU,并且Linux仍然很快。
这两个 Linux 使用上面列出的相同包和驱动程序,具有完全相同的版本。
执行的PHP代码在两台服务器上完全相同。
我忘记在我的 "Server 2"?
上查看另一个包或配置我不知道是否有关系,但在我的 SQL 服务器上,ODBC 驱动程序版本是 13。可能不是,因为 "Server 1"不会引起问题。
谢谢!
终于找到问题了!
快速回答
在 SQL 服务器上读取 trace log,在“应用程序名称”字段中,我们可以观察到一些来源调用数据库(Apache、PHP-FPM 和 PHP Freetds)
使用 PHP SQLSRV (pdo) 时出现问题,仅使用 FreeTDS (php ext DBLIB) 没有问题。
那么在 unix 系统上只使用 PHP DBLIB with FreeTDS 是个好主意。
完整回答
TL;DR;
当然,问题不仅仅在于 PHP SQLSRV 扩展。在我们的调查中,我们查看驱动程序版本,客户端 Linux 使用最新版本的驱动程序 MSODBCSQL17。
但是在我们的服务器上,运行 SQL SERVER 2016,驱动版本是13。
但是 Microsoft 有一个 upgrade to version 17(与 Linux 客户端上使用的相同)
正在阅读更改日志,issue about high cpu usage is fixed。
“你能证明吗?”
是的!
我们做了一个简单的测试,在我们的 linux“服务器 1”上,我们删除了对 freetds 的支持(禁用 DBLIB),我们立即可以在仪表板上观察到性能下降,几分钟后,当再次启用 freetds (DBLIB) 时,性能 returns 恢复正常,见上文。
我们的新 linux 没有安装 freetds,我们只从 Microsoft 获取驱动程序到 PHP 7+ 和 PECL 扩展。
问题是因为我们的 SQL 服务器使用 ODBC 驱动程序 13 而我们的客户使用 ODBC 驱动程序 17。
我们无法在 SQL SERVER 上升级驱动程序,因为我们需要此版本,并且仅在 SQL SERVER 2019 上支持 ODBC 17。
那么,目前我们的解决方案是使用 freetds 而不是 PHP SQLSRV 扩展。
要注意的另一点是,来自 PHP SQLSRV 的所有查询都是 parametrized,如下所示:
Declare @Out int;
EXEC sp_prepexec @Out output,
N'@P1 nvarchar(128), @P2 nvarchar(100)',
N'SELECT database_id, name
FROM sys.databases
WHERE name=@P1 AND state_desc = @P2',
@P1 = 'tempdb', @P2 = 'ONLINE';
EXEC sp_unprepare @Out;
与 freetds 相同的查询出现在跟踪日志中,如下所示:
SELECT database_id, name
FROM sys.databases
WHERE name='tempdb' AND state_desc='ONLINE';
我认为这种差异使得 SQL 服务器强制使用更多 CPU 比具有更简单查询的 FreeTDS。
但是你两个都安装了,怎么决定用哪个?
是的,在我的“服务器 1”上,我们同时安装了驱动程序和扩展程序,但我的应用程序决定首先使用 DBLIB 可用,我们使用 Laravel, and this code is inside connector:
/**
* Create a DSN string from a configuration.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
// First we will create the basic DSN setup as well as the port if it is in
// in the configuration options. This will give us the basic DSN we will
// need to establish the PDO connections and return them back for use.
if (in_array('dblib', $this->getAvailableDrivers())) {
return $this->getDblibDsn($config);
} elseif ($this->prefersOdbc($config)) {
return $this->getOdbcDsn($config);
} else {
return $this->getSqlSrvDsn($config);
}
}
结论
我不知道我的应用程序在安装 PHP SQLSRV 后仍然使用 FreeDTS,这个问题以前没有出现过,因为 laravel 偏好 dblib。
这个问题太难找了,希望大家的分析能帮到看到这行的你
谢谢!
;)