Bug #67913 [Com]: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option

From: Date: Mon, 18 Jun 2018 23:02:47 +0000
Subject: Bug #67913 [Com]: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-215782@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=67913&edit=1 ID: 67913 Comment by: php at darkain dot com Reported by: ablyler at barracuda dot com Summary: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option Status: Open Type: Bug Package: MySQL related Operating System: Any PHP Version: 5.5.16 Block user comment: N Private report: N New Comment: https://bugs.php.net/bug.php?id=76497 Solved by using the (currently undocumented) MYSQLI_OPT_READ_TIMEOUT option. Previous Comments: ------------------------------------------------------------------------ [2018-04-24 17:33:10] php at darkain dot com This bug still persists in PHP 7.2.4. This is more than just a bug, it in effect DoSed a production system I manage. I run a series of MariaDB nodes in a Galera cluster. One of the nodes misbehaved. This happens from time to time. When a connection issue happens normally with a Galera node, it is pulled out of the local list of available nodes stored on each PHP instance. This process of storing and updating the list of Galera nodes is handled within a PHP script based on successful/failure to connect to each node. The problem is that even with MYSQLI_OPT_CONNECT_TIMEOUT set, no timeout happens if a successful TCP handshake is made but no data is transmitted over the wire afterwards. PHP is left in a hung state that can only be broken by restarting the entire PHP-FPM service. This leads to an eventual resource exhaustion within PHP-FPM hitting its maximum open connection limit as more users access the web site. This eventually breaks the entire web site. Simple code to reproduce: $sql = mysqli_init(); $sql->options(MYSQLI_OPT_CONNECT_TIMEOUT, 1); $sql->real_connect('google.com:80', 'user', 'my_password', 'db'); echo 'GOOD'; NOTE that using a web server such as google.com, the server side will eventually break the connection. HOWEVER, the short timeout of 1 second never happens, and instead the server side breaks the connection after the server side timeout value. In the case of MariaDB with the single node that misbehaved, it never broke the connection. Instead, no data was ever transmitted over the wire after the TCP handshake, leaving PHP in an endless waiting process. Nothing after $sql->real_connect() is ever processed, therefor any sysadmin related emails about a failed connection or automatically pulling the failed node from the server pool ever happened as a result. ------------------------------------------------------------------------ [2014-08-26 22:55:44] ablyler at barracuda dot com Description: ------------ The MYSQLI_OPT_CONNECT_TIMEOUT is ignored when using mysqlnd. To reproduce this run: netstat -l -p 9999 Then execute the included test script (wrapped with time). Thanks to Jason Dictos for coming up with the fix to this. Test script: --------------- <?php $connect_timeout = 5; $resource = mysqli_init(); if (!mysqli_options($resource, MYSQLI_OPT_CONNECT_TIMEOUT, $connect_timeout)) { die('Unable to set connect timeout on resource'); } var_dump(mysqli_real_connect($resource, '127.0.0.1', 'username', 'password', 'database', 9999)); Expected result: ---------------- It should return in ~5 seconds with errors. Actual result: -------------- The script will keep running past the timeout value. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=67913&edit=1

« previous php.bugs (#215782) next »