Skip to content

Resetting connection hangs on Aurora 2 (MySQL 5.7.12) #1321

@srogovtsev

Description

@srogovtsev

We have a weird behavior showing on a system working with Amazon Aurora 2. The behavior exhibits only under load and only sporadically, so (a) it is hard to reproduce it systematically, thus we resort to reading memory dumps, and (b) we suspect it might be related to some concurrency issue. I have two dumps from two nodes in the cluster having this issue and they both have the same characteristics.

We using version 1.3.14 of MySqlConnector and we cannot currently upgrade to 2.x due to conflicting dependencies.

The behavior exhibits as a thread permanently (or at least long enough to produce a cascade effect throughout the system) hung in this call stack:

System.dll!System.Net.Sockets.Socket.Receive(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) Line 2096	C#
System.dll!System.Net.Sockets.NetworkStream.Read(byte[] buffer, int offset, int size) Line 432	C#
System.dll!System.Net.FixedSizeReader.ReadPacket(byte[] buffer, int offset, int count) Line 26	C#
System.dll!System.Net.Security._SslStream.StartFrameBody(int readBytes, byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) Line 648	C#
System.dll!System.Net.Security._SslStream.StartFrameHeader(byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) Line 619	C#
System.dll!System.Net.Security._SslStream.StartReading(byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) Line 597	C#
System.dll!System.Net.Security._SslStream.ProcessRead(byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) Line 557	C#
System.dll!System.Net.Security.SslStream.Read(byte[] buffer, int offset, int count) Line 739	C#
MySqlConnector.dll!MySqlConnector.Utilities.Utility.Read(System.IO.Stream stream, System.Memory<byte> buffer) Line 534	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.StreamByteHandler.ReadBytesAsync.__DoReadBytesSync|6_0(System.Memory<byte> buffer) Line 33	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.StreamByteHandler.ReadBytesAsync(System.Memory<byte> buffer, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 25	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.BufferedByteReader.ReadBytesAsync(MySqlConnector.Protocol.Serialization.IByteHandler byteHandler, System.ArraySegment<byte> buffer, int totalBytesToRead, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 36	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.BufferedByteReader.ReadBytesAsync(MySqlConnector.Protocol.Serialization.IByteHandler byteHandler, int count, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 29	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.ProtocolUtility.ReadPacketAfterHeader(System.ReadOnlySpan<byte> headerBytes, MySqlConnector.Protocol.Serialization.BufferedByteReader bufferedByteReader, MySqlConnector.Protocol.Serialization.IByteHandler byteHandler, System.Func<int> getNextSequenceNumber, MySqlConnector.Protocol.Serialization.ProtocolErrorBehavior protocolErrorBehavior, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 432	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.ProtocolUtility.ReadPacketAsync(MySqlConnector.Protocol.Serialization.BufferedByteReader bufferedByteReader, MySqlConnector.Protocol.Serialization.IByteHandler byteHandler, System.Func<int> getNextSequenceNumber, MySqlConnector.Protocol.Serialization.ProtocolErrorBehavior protocolErrorBehavior, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 409	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.ProtocolUtility.DoReadPayloadAsync(MySqlConnector.Protocol.Serialization.BufferedByteReader bufferedByteReader, MySqlConnector.Protocol.Serialization.IByteHandler byteHandler, System.Func<int> getNextSequenceNumber, MySqlConnector.Protocol.Serialization.ArraySegmentHolder<byte> previousPayloads, MySqlConnector.Protocol.Serialization.ProtocolErrorBehavior protocolErrorBehavior, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 466	C#
MySqlConnector.dll!MySqlConnector.Protocol.Serialization.StandardPayloadHandler.ReadPayloadAsync(MySqlConnector.Protocol.Serialization.ArraySegmentHolder<byte> cache, MySqlConnector.Protocol.Serialization.ProtocolErrorBehavior protocolErrorBehavior, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior) Line 42	C#
MySqlConnector.dll!MySqlConnector.Core.ServerSession.ReceiveReplyAsync(MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior, System.Threading.CancellationToken cancellationToken) Line 849	C#
MySqlConnector.dll!MySqlConnector.Core.ServerSession.TryResetConnectionAsync(MySqlConnector.Core.ConnectionSettings cs, MySqlConnector.MySqlConnection owningConnection, bool returnToPool, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior, System.Threading.CancellationToken cancellationToken) Line 552	C#
MySqlConnector.dll!MySqlConnector.Core.ConnectionPool.GetSessionAsync(MySqlConnector.MySqlConnection connection, int startTickCount, MySqlConnector.Protocol.Serialization.IOBehavior ioBehavior, System.Threading.CancellationToken cancellationToken) Line 71	C#
MySqlConnector.dll!MySqlConnector.MySqlConnection.CreateSessionAsync(MySqlConnector.Core.ConnectionPool pool, int startTickCount, MySqlConnector.Protocol.Serialization.IOBehavior? ioBehavior, System.Threading.CancellationToken cancellationToken) Line 873	C#
MySqlConnector.dll!MySqlConnector.MySqlConnection.OpenAsync(MySqlConnector.Protocol.Serialization.IOBehavior? ioBehavior, System.Threading.CancellationToken cancellationToken) Line 414	C#
MySqlConnector.dll!MySqlConnector.MySqlConnection.Open() Line 380	C#

As we unroll the stack and examine the state, we observe the following:

  • in BufferedByteReader.ReadBytesAsync totalBytesToRead is 197399 (which, I suppose, is way too much)
  • in ProtocolUtility.ReadPacketAfterHeader payloadLength is set to the same 197399, and we have also packetOutOfOrderException set to MySqlProtocolException with a message of "Packet received out-of-order. Expected 1; got 30."

Our guess is that while talking to Aurora something happens to the packet order, the connector gets the wrong byte count and tries to read a lot of data that doesn't arrive - thus, gets stuck in Socket.Receive.

The question is, why we wait in Socket.Receive? Shouldn't there be a timeout for this operation? My knowledge to the lower-level networking is very limited, and I couldn't find anywhere in the code where we'd set the timeout on the Socket/TcpClient/SslStream /NetworkStream. Am I missing something?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions