一个诡异的bug的查找
以前写的一个异步防垃圾系统,有访问mysql 数据源.
而且运行都快大半年了,非常稳定。
然后前阵子机房掉电,损坏了服务器。
移到一台新的server上来了,却一直不稳定。
如果改成连接池,异常消除。
禁用连接池问题依旧。
报的异常信息是:
MySql.Data.MySqlClient.MySqlException: Unable to connect to any of the specified MySQL hosts. ---> System.Net.Sockets.SocketException: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 192.168.XXX.XXX:3306
在 System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
在 MySql.Data.Common.StreamCreator.CreateSocketStream(IPAddress ip, Boolean unix)
在 MySql.Data.Common.StreamCreator.GetStream(UInt32 timeout)
在 MySql.Data.MySqlClient.NativeDriver.Open()
--- 内部异常堆栈跟踪的结尾 ---
在 MySql.Data.MySqlClient.NativeDriver.Open()
在 MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings)
在 MySql.Data.MySqlClient.MySqlConnection.Open()
在 Microsoft.Practices.EnterpriseLibrary.Data.Database.GetNewOpenConnection()
在 Microsoft.Practices.EnterpriseLibrary.Data.Database.GetOpenConnection(Boolean disposeInnerConnection)
在 Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteScalar(DbCommand command)
在 Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteScalar(CommandType commandType, String commandText)
报"通常每个套接字地址(协议/网络地址/端口)只允许使用一次"异常以前也见过,
比如重复listing 一个端口会报此信息,但后面不会跟remote host的IP 和port.
而这异常消息是:
中文版:
通常每个套接字地址(协议/网络地址/端口)只允许使用一次
英文版:
"Only one usage of each socket address (protocol/network address/port) is normally
permitted <IP ADDRESS/PORT HERE>."
1.第一个就是想办法复现这个问题
同样一套代码在本地就是不出问题
2.第二对比了环境。
mysql connector版本不一样
通过分析connector的源码发现,这块基本没有多少改动,而且后面我也统一了版本。
3.猜测是异步代码访问到同步代码,引起的资源冲突
写了一个多线程并发程序测试,也很正常。
这么一个小小问题,分析和查询了半天,就是没有复现和查询出来。后面发现用连接池没有问题,就这样一直放着,但感觉一直是个炸弹在那里,哪天DBA要求我改成短连接,问题又出来了。
今天突然想起前阵子写的tcp server,在做并发测试时,不同平台的连接数情况不同,测试结果不同。
在xp win server2003当socket连接数大于4000时,初使化socket时就会出现异常。
然后在win7 winserver 2008下,连接数大于20000,初使化socket依然稳定。
联想一下,会不会是由于这个稳定引起的?
后面写了一个代码在不同的机器上进行测试:
class Program
{
static void Main(string[] args)
{
DbTest();
}
private static void DbTest()
{
// The connection string should have Pooling=false;
string connectionString = "<INSERT CONNECTION STRING HERE>";
MySqlClientFactory mysql = MySqlClientFactory.Instance;
DbConnection connection = mysql.CreateConnection();
connection.ConnectionString = connectionString;
DbCommand command = mysql.CreateCommand();
command.Connection = connection;
command.CommandText = "<INSERT FAVORITE QUERY HERE>";
int i = 0;
while (true)
{
i++;
try
{
Console.WriteLine(i);
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Trace.Write(ex);
Console.WriteLine(ex);
throw;
}
finally
{
connection.Close();
}
}
}
}
在winserver2003里
i==2341时,问题就复现现来了
MySql.Data.MySqlClient.MySqlException: Unable to connect to any of the specified
MySQL hosts. ---> System.Net.Sockets.SocketException: 通常每个套接字地址(协议/
网络地址/端口)只允许使用一次。 192.168.XXX.XXX:3306
在 System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
在 MySql.Data.Common.StreamCreator.CreateSocketStream(IPAddress ip, Boolean u
nix)
在 MySql.Data.Common.StreamCreator.GetStream(UInt32 timeout)
在 MySql.Data.MySqlClient.NativeDriver.Open()
这时查
本地连接服务器端占用的socket句柄资源为:3853个约等于4000
现在基本是可以确定问题了
windows服务器连接数测试发现能达到50000个。但服务器自己内部发起连接通信数量只能达到4000。
原因是服务器发送端口范围从1024-5000之间。软件编程需要考虑此问题。
以前此系统是运行在win server 2008上,而现在运行在win server 2003上,由于并发量比较大,采用短连接,占用的
socket句柄资源来不及释放。
socket 如果系统自己释放默认是4分钟。
降低等待时间和增加最大端口数量可以提高系统的数据吞吐率.
可选的解决方案:
1.采用连接池
2.采用win server 2008 系统
3.把系统的socket清理时间设置得更短(30S,不要太短)
4.优化系统配置,修改系统端口范围
优化的详情可以参考:http://bbs.itwgw.com/redirect.php?tid=94&goto=lastpost X系列服务器上Windows Server 2003性能优化