使用负载均衡时MySQL .NET Connector引发多类异常问题排查
问题描述
我们有一个基于.NET Framework 4.6的ASP.NET项目,使用8.0.29版本的MySQL.Data NuGet包,连接MySQL集群中的多个数据库。MySQL连接器支持通过逗号分隔多主机名实现流量负载均衡,该配置在测试环境运行正常,但在流量更大的生产环境中,Windows Server事件查看器出现大量异常。单独连接集群内任一数据库均无问题,仅多主机同时配置时触发异常。
连接字符串示例
server=example1.com,example2.com,example3.com;port=25060;uid=username;pwd=password;database=database;pooling=false;Allow User Variables=True;CharSet=utf8
注:pooling设为false是因连接池引发其他独立问题
出现的异常
异常1:MySqlException
Exception type: MySqlException Exception message: Unable to connect to any of the specified MySQL hosts. at MySql.Data.MySqlClient.NativeDriver.<>c.<Open>b__40_0(Exception ex) at System.AggregateException.Handle(Func`2 predicate) at MySql.Data.MySqlClient.NativeDriver.Open() at MySql.Data.MySqlClient.Driver.Open() at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings) at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection() at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection() at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver() at MySql.Data.MySqlClient.MySqlPool.GetConnection() at MySql.Data.MySqlClient.MySqlConnection.Open()
异常2:InvalidOperationException
Exception type: InvalidOperationException Exception message: Collection was modified; enumeration operation may not execute. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.MoveNext() at System.Data.Common.DbConnectionStringBuilder.get_ConnectionString() at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value) at MySql.Data.MySqlClient.MySqlConnection.Open()
异常3:SocketException
Exception type: SocketException Exception message: No such host is known at System.Net.Dns.HostResolutionEndHelper(IAsyncResult asyncResult) at System.Net.Dns.EndGetHostAddresses(IAsyncResult asyncResult) at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
异常4:NullReferenceException
Exception type: NullReferenceException Exception message: Object reference not set to an instance of an object. at MySql.Data.Failover.FailoverManager.AttemptConnection(MySqlConnection connection, String originalConnectionString, String& connectionString, Boolean mySqlPoolManager) at MySql.Data.MySqlClient.MySqlConnection.Open()
疑问
该问题原因是什么?是否为我们的配置操作有误?
问题分析与解决方案
核心原因
并非配置错误,而是MySQL.Data 8.0.29版本的多主机负载均衡/故障转移逻辑存在线程安全缺陷,高并发场景下会触发多种异常:
- InvalidOperationException:连接字符串构建器的字典被多线程并发修改时触发枚举冲突,属于典型的非线程安全容器并发访问问题。
- NullReferenceException:FailoverManager在高并发下内部状态未正确初始化或被并发修改,导致空引用。
- SocketException/MySqlException:并发场景下DNS解析或连接尝试逻辑被打乱,出现主机无法解析或全部连接失败的情况。
另外,pooling=false的配置会加剧问题:关闭连接池后,每次请求都要创建新连接,并发请求量直接等同于连接创建的并发量,大幅提升了触发线程安全问题的概率。测试环境流量低、并发连接少,因此未暴露该缺陷。
解决步骤
- 升级MySQL.Data包:官方在8.0.30及后续版本修复了多主机场景下的线程安全问题,优先升级到最新稳定版。
- 评估恢复连接池的可能性:如果原连接池的独立问题可通过调整参数(如
max pool size、connection timeout等)解决,建议恢复pooling=true——连接池能减少连接创建的并发量,降低异常触发概率,同时提升性能。 - 临时应急方案:若暂时无法升级包,可在代码中对
MySqlConnection.Open()添加全局锁,强制串行化连接创建逻辑,但这会牺牲部分并发性能,仅作为临时过渡方案。
内容的提问来源于stack exchange,提问作者Walance
相关产品推荐
相关产品推荐

