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.