在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率
Posted
技术标签:
【中文标题】在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率【英文标题】:Using async sockets on Windows Server 2008 R2 causes 100% CPU usage 【发布时间】:2011-07-01 02:15:18 【问题描述】:我有一个相当通用的 C# 套接字服务器,它使用套接字类的异步方法 - BeginAccept()、BeginReceive() 等。过去 4 年,该服务器在许多运行 Win Server 2003 的客户站点上运行良好. 最近我在一台Windows Server 2008 R2 服务器上安装了它,64 位。在第一个客户端连接并在接受处理程序中发出 BeginReceive() 和 BeginAccept() 调用之前,一切看起来都很好。发生这种情况时,CPU 使用率会飙升至 100% 并保持这种状态,直到我关闭侦听套接字。
不确定是否重要,但服务器正在虚拟机中运行。
已经做了很多测试,但似乎没有任何帮助。使用 Process Explorer,我可以看到在 BeginReceive()/BeginAccept() 调用后不久启动了两个线程,它们是消耗处理器的线程。不幸的是,我无法在我的 Win7 64 位工作站上重现此问题。
我做了很多研究,到目前为止,我发现的只是以下两篇知识库文章,它们暗示 Server 2008 R2 可能存在 TCP/IP 组件问题,但它们仅作为热修复程序提供:KB2465772 和 KB2477730。在我更确定他们会解决问题之前,我不愿意让我的客户安装它们。
还有其他人遇到过这个问题吗?如果是这样,您必须采取什么措施来解决此问题?
这是我认为导致这种情况的方法:
private void AcceptCallback(IAsyncResult result)
ConnectionInfo connection = new ConnectionInfo();
try
// Finish accept.
Socket listener = (Socket)result.AsyncState;
connection.Socket = listener.EndAccept(result);
connection.Request = new StringBuilder(256);
// Start receive and a new accept.
connection.Socket.BeginReceive(connection.Buffer, 0,
connection.Buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), connection);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// CPU usage spikes at 100% shortly after this...
catch (ObjectDisposedException /*ode*/)
_log.Debug("[AcceptCallback] ObjectDisposedException");
catch (SocketException se)
connection.Socket.Close();
_log.ErrorFormat("[AcceptCallback] Socket Exception (0: 1 2", connection.ClientAddress, se.ErrorCode, se.Message);
catch (Exception ex)
connection.Socket.Close();
_log.ErrorFormat("[AcceptCallback] Exception 0: 1", connection.ClientAddress, ex.Message);
【问题讨论】:
我似乎有一个类似的问题,但是使用服务器 2012 R2。除了我的应用程序运行良好几个星期,然后突然我得到高 CPU 使用率。分析表明使用 cpu 的是System.net.Socket.beginReceive()
【参考方案1】:
该问题是由于在设置侦听器套接字时对 BeginAccept() 进行了多次调用。不知道为什么这个问题只出现在 64 位服务器上,但是按照如下所示更改代码解决了这个问题。
原码:
public SetupServerSocket()
IPEndPoint myEndPoint = new IPEndPoint(IPAddress.Any, _port);
// Create the socket, bind it, and start listening.
_serverSocket = new Socket(myEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(myEndPoint);
_serverSocket.Listen((int)SocketOptionName.MaxConnections);
for (int i = 0; i < 10; i++)
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
致以下:
public SetupServerSocket()
IPEndPoint myEndPoint = new IPEndPoint(IPAddress.Any, _port);
// Create the socket, bind it, and start listening.
_serverSocket = new Socket(myEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(myEndPoint);
_serverSocket.Listen((int)SocketOptionName.MaxConnections);
//for (int i = 0; i < 10; i++)
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
//
【讨论】:
【参考方案2】:我知道您在其中找到了 SetupServerSocket() 的“Wire Performance”文章 - 如果您有快速的新客户端连接,那么原始的 10x for 循环将支持 10 个侦听线程。您已将其更改为一个侦听器。如果 Win2k8r2 有这样的错误,也许这是唯一可能的解决方案。您可能希望确保在您的客户端中有可靠的连接重试代码。
使用 .NET 中的高性能套接字更接近线路 http://msdn.microsoft.com/en-us/magazine/cc300760.aspx
【讨论】:
以上是关于在 Windows Server 2008 R2 上使用异步套接字会导致 100% 的 CPU 使用率的主要内容,如果未能解决你的问题,请参考以下文章
如何在windows server2008 r2上打开internet信息服务 iis 管理器
如何在windows server 2008 r2创建web服务器
windows server2012 r2能安装sqlserver2008 R2吗