Avatar of DrDamnit
DrDamnit
Flag for United States of America asked on

Why aren't my MySQL connections closing?

When I run a script (especially a billing script we use to bill billable phone calls, which uses the phone system database and the CRM to determine who called, if it was billable, if they have an account, etc...), which takes a few minutes I have time to run:

show status like '%onn%';

Open in new window


In the MySQL CLI.

I get something like this:
show connections
You can see the connection count is 74. For now, let's say that's OK even though it seems high to me. There are other things going on in this server other than what I am just looking at (the phone system accesses it among other things).

Immediately after restarting the server my connection count is 72.

I run the script, and it jumps to 74.

When the script completes, I expect it to drop back down to 72.

It doesn't. Am I misreading this? Is this the historical connection count instead of the current / active connection count?

I'm definitely closing the database connections in PHP when I am done with them:

At the top of a page, I instantiate one instance of MySQLi for everything in that page to use. All functions, classes, etc... use dependency injection to utilize the same database connection, which originates at the very top of the script:

<?php
$db = gimmieDB(); //Returns a MySQLi object connected to the database
include('includes/application_top.php');
//do other stuff.

Open in new window


at the bottom of this page I do this:

$db->close();
unset($db);

Open in new window


Why is this connection count not going down?
PHPMySQL Server

Avatar of undefined
Last Comment
DrDamnit

8/22/2022 - Mon
arnold

Unsettling the variable does not close the connection.

You need to see what your gimmieDB returns.
The same way you have gimmieDB you need one that you release the connection.

You might be looking at the wrong part I.e. You may have a different code that opens he connection and never closes it.
DrDamnit

ASKER
All it does is instantiate a MySQLi object with the connection, if there is an error, log it with fLog, and otherwise returns the object.

I should be able to (later) use the close() method of that returned object to close it, right?

/**
 * Creates a MySQLi object for the database
 * @return mysqli A MySQLi object with a connection to the system's database.
 **/

function gimmieDB()
{
    $dbDatabase = '[REDACTED]';
    $dbUser = '[REDACTED]';
    $dbPass = '[REDACTED]';
    $dbServer = 'localhost';

    $m = new mysqli($dbServer,$dbUser,$dbPass,$dbDatabase);
    if($m->connect_error) {
        fLog('gimmieDB',$m->connect_error);
    }

    return $m;
}

Open in new window

DrDamnit

ASKER
... and if you notice the bottom, the first line is close(), the SECOND line is unset().
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Ray Paseur

FWIW, I never bother to call the Close() methods -- the PHP script terminator will close the connections for you.  And I've never had an "excess" of open connections.
http://php.net/manual/en/mysqli.close.php

If your connections are persistent, you may need to close them yourself.  Also, if you run the gimmeDB() method repeatedly, it will create a new connection each time.  So, 15 calls to the function gives 15 connections.  Usually only one connection is needed.  This is another argument for getting a connection object and using dependency injection to pass the connection object into any other methods that need to use the connection.
DrDamnit

ASKER
@ray:

You probably recognize this function from a previous (and valuable) conversation we have had.

I only call it once at the top of a given script, and everything in the script uses that single connection object - it is passed as a dependency injection to all classes, functions, and methods.

Then, it dies when we get to the bottom of the calling script (page).

Until I saw these "excess" connections, I wasn't doing the close() either because (as it states in the docs) unless you specify a persistent connection, it will close it for you.

This is why I am confused. "The Google" says those are concurrent connections. But, the server got REALLY busy earlier today (an unusual onslaught of people signed in all at once) and it started throwing the too many connections error. So, I went looking for stray uses of the gimmieDB() function to see if I was accidentally instantiating some extra connections. I found some, and one in particular (in our billing script) was racking up hundreds of connections because I accidentally had it in a loop (instead of just above the loop).

While trying to track this down, I looked at the MySQL stats for connections. The first time I looked (before restarting MySQL) it has 132,000,000 connections. That's outrageous.

my.cnf has "max_connections = 100" so I am not sure HOW it could get that high unless it was a historical count. That's very believable for this particular server.
Ray Paseur

Running on a shared server, with everything humming along smoothly, here is what a MySQLi object looks like:
object(mysqli)#2 (19) {
  ["affected_rows"]=>
  int(0)
  ["client_info"]=>
  string(75) "mysqlnd 5.0.10 - 20111026 - $Id: c85105d7c6f7d70d609bb4c000257868a40840ab $"
  ["client_version"]=>
  int(50010)
  ["connect_errno"]=>
  int(0)
  ["connect_error"]=>
  NULL
  ["errno"]=>
  int(0)
  ["error"]=>
  string(0) ""
  ["error_list"]=>
  array(0) {
  }
  ["field_count"]=>
  int(0)
  ["host_info"]=>
  string(25) "Localhost via UNIX socket"
  ["info"]=>
  NULL
  ["insert_id"]=>
  int(0)
  ["server_info"]=>
  string(14) "5.5.45-MariaDB"
  ["server_version"]=>
  int(50545)
  ["stat"]=>
  string(147) "Uptime: 6591442  Threads: 1  Questions: 94391244  Slow queries: 2  Opens: 316968  Flush tables: 2  Open tables: 400  Queries per second avg: 14.320"
  ["sqlstate"]=>
  string(5) "00000"
  ["protocol_version"]=>
  int(10)
  ["thread_id"]=>
  int(2958085)
  ["warning_count"]=>
  int(0)
}

Open in new window

Here is what SHOW STATUS LIKE %onn% returns.  The Connections value increments as I rerun the script.
stdClass Object
(
    [Variable_name] => Aborted_connects
    [Value] => 52058
)
stdClass Object
(
    [Variable_name] => Connections
    [Value] => 2958086
)
stdClass Object
(
    [Variable_name] => Max_used_connections
    [Value] => 48
)
stdClass Object
(
    [Variable_name] => Ssl_client_connects
    [Value] => 0
)
stdClass Object
(
    [Variable_name] => Ssl_connect_renegotiates
    [Value] => 0
)
stdClass Object
(
    [Variable_name] => Ssl_finished_connects
    [Value] => 0
)
stdClass Object
(
    [Variable_name] => Threads_connected
    [Value] => 1
)

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Ray Paseur

Random thought... Where is this web site hosted?
arnold

The connection counters in statistics as you supposed is based on when mysql was started. That duration is also included in the statistics. Total Connections could reach that high as you pointed out because you had a process that was looping and initiating a new connection per loop.

Unfortunately, determining the issue at hand is a going forward event, by guestimating what might have happened. Tuning the mysql setup /db/query using everytool available.


http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

Depending on your DB use/need.

Is it a continuously growing  db?
DrDamnit

ASKER
@ray

Dedicated server. Custom built by us.

@arnold

No, the database is not continuously growing other than what is to be expected. It's been in service for years, and is linux, so has not been rebooted for well over a year. The 132M connections is reasonable for it over that period of time.

So, since we have (collectively) figured out that this is not the current connection list, WHERE is the current / active / open connection list?

At this point, I just want to watch it to make sure that I don't have something else chewing up resources so this problem doesn't return. (It hasn't returned yet, and it has had heavy use over the last 24 hours... nothing in syslog and nothing in the php error logs or mysql logs).
Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER CERTIFIED SOLUTION
arnold

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
DrDamnit

ASKER
@arnold:

Then this means my problem is solved. SHOW PROCESSLIST is (has been) rather barren since I fixed the other problem. It now has only the occasional (and expected) connection and processes.
arnold

I'd recommend you use the referenced tools to see if they provide any suggestion based on the current long collected stats.
You could set the long query log just to capture an event should it occur.

The repetitive opening of the connections might be one, the time of year, end of month, end of quarter, etc. trigger some usage that is not seen through out the rest of the month/quarter, year that might manifest the same issue next time.
..
DrDamnit

ASKER
Good idea
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.