Description:
The MySqlConnection.Open() can take 30+ seconds when using SSL to connect to a MySql server if multiple threads are trying to connect at the same time.
The root of the problem seems to be with the Ssl.StartSSL method - which creates a lock while executing sslStream.AuthenticateAsClientAsync (and thus blocks any other connections when waiting for a response).
How to repeat:
The following code reliably replicates the problem:
class Program
{
static void Main()
{
var connectionString = ConfigurationManager.ConnectionStrings["test"].ConnectionString;
var builder = new MySqlConnectionStringBuilder(connectionString);
builder.SslMode = MySqlSslMode.Required;
builder.Pooling = true;
builder.MaximumPoolSize = 1000;
builder.MinimumPoolSize = 0;
builder.ConnectionLifeTime = 1;
int connectsExecuted = 0;
int slowConnects = 0;
long slowestConnectionTime = 0;
Parallel.For(
0, 10000, (i) =>
{
var connection = new MySqlConnection(builder.ConnectionString);
var connectionId = Interlocked.Increment(ref connectsExecuted);
var sw = Stopwatch.StartNew();
connection.Open();
var elapse = sw.ElapsedMilliseconds;
if (elapse > 2000)
{
Debugger.Break();
Interlocked.Increment(ref slowConnects);
if (elapse > slowestConnectionTime)
{
slowestConnectionTime = elapse;
}
}
Thread.Sleep(10); // Simulate usage of conection
connection.Close();
});
Console.WriteLine($"{slowConnects} of {connectsExecuted} connections slow - slowest conection = {slowestConnectionTime} ms");
}
}
The slowest connection times vary but typically can be 2-30 seconds. We have reports of 40+ seconds on production systems
Suggested fix:
Alter Ssl.StartSSL so that locks are not taken during the authentication process.
Description: The MySqlConnection.Open() can take 30+ seconds when using SSL to connect to a MySql server if multiple threads are trying to connect at the same time. The root of the problem seems to be with the Ssl.StartSSL method - which creates a lock while executing sslStream.AuthenticateAsClientAsync (and thus blocks any other connections when waiting for a response). How to repeat: The following code reliably replicates the problem: class Program { static void Main() { var connectionString = ConfigurationManager.ConnectionStrings["test"].ConnectionString; var builder = new MySqlConnectionStringBuilder(connectionString); builder.SslMode = MySqlSslMode.Required; builder.Pooling = true; builder.MaximumPoolSize = 1000; builder.MinimumPoolSize = 0; builder.ConnectionLifeTime = 1; int connectsExecuted = 0; int slowConnects = 0; long slowestConnectionTime = 0; Parallel.For( 0, 10000, (i) => { var connection = new MySqlConnection(builder.ConnectionString); var connectionId = Interlocked.Increment(ref connectsExecuted); var sw = Stopwatch.StartNew(); connection.Open(); var elapse = sw.ElapsedMilliseconds; if (elapse > 2000) { Debugger.Break(); Interlocked.Increment(ref slowConnects); if (elapse > slowestConnectionTime) { slowestConnectionTime = elapse; } } Thread.Sleep(10); // Simulate usage of conection connection.Close(); }); Console.WriteLine($"{slowConnects} of {connectsExecuted} connections slow - slowest conection = {slowestConnectionTime} ms"); } } The slowest connection times vary but typically can be 2-30 seconds. We have reports of 40+ seconds on production systems Suggested fix: Alter Ssl.StartSSL so that locks are not taken during the authentication process.