WCF每秒不能处理1000个呼叫

时间:2015-06-11 14:32:44

标签: c# wcf async-await threadpool nettcpbinding

我正在使用nettcpbinding处理在Windows服务中托管的WCF服务。

当我尝试对服务执行负载测试时,我构建了一个简单的客户端,该服务器在第二次调用服务大约1000次,从服务返回大约需要2到8秒,并且在离开简单客户端后运行大约半小时返回结果的时间增加了,有些客户端为发送时间提供了一些超时时间,配置为2分钟。

我修改了服务提升配置,就像这样

这些是我尝试执行的步骤:

  1. 修改了服务限制配置

    <serviceThrottling maxConcurrentCalls="2147483647" maxConcurrentInstances="2147483647" maxConcurrentSessions="2147483647"/>

  2. 正在使用Windows 7计算机,因此我转移到了服务器2008但结果相同。
  3. 更新tcp绑定的配置如下所示 NetTcpBinding baseBinding = new NetTcpBinding(SecurityMode.None,true);             baseBinding.MaxBufferSize = int.MaxValue;

            baseBinding.MaxConnections = int.MaxValue;
            baseBinding.ListenBacklog = int.MaxValue;
            baseBinding.MaxBufferPoolSize = long.MaxValue;
    
            baseBinding.TransferMode = TransferMode.Buffered;
            baseBinding.MaxReceivedMessageSize = int.MaxValue;
            baseBinding.PortSharingEnabled = true;
            baseBinding.ReaderQuotas.MaxDepth = int.MaxValue;
            baseBinding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
            baseBinding.ReaderQuotas.MaxArrayLength = int.MaxValue;
            baseBinding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
            baseBinding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
            baseBinding.ReliableSession.Enabled = true;
            baseBinding.ReliableSession.Ordered = true;
            baseBinding.ReliableSession.InactivityTimeout = new TimeSpan(23, 23, 59, 59);
    
    
            BindingElementCollection elements = baseBinding.CreateBindingElements();
            ReliableSessionBindingElement reliableSessionElement = elements.Find<ReliableSessionBindingElement>(); 
            if (reliableSessionElement != null)
            {
                reliableSessionElement.MaxPendingChannels = 128;
    
    
    
                TcpTransportBindingElement transport = elements.Find<TcpTransportBindingElement>();
    
                transport.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint = 1000;
    
                CustomBinding newBinding = new CustomBinding(elements);                    
                newBinding.CloseTimeout = new TimeSpan(0,20,9);
                newBinding.OpenTimeout = new TimeSpan(0,25,0);
                newBinding.ReceiveTimeout = new TimeSpan(23,23,59,59);
                newBinding.SendTimeout = new TimeSpan(0,20,0);
                newBinding.Name = "netTcpServiceBinding";
    
                return newBinding;
            }
            else
            {
                throw new Exception("the base binding does not " +
                    "have ReliableSessionBindingElement");
            }
    
  4. 将我的服务功能更改为使用async并等待

    public async Task<ReturnObj> Connect(ClientInfo clientInfo)
    {
        var task = Task.Factory.StartNew(() =>
        {
            // do the needed work
            // insert into database
            // query some table to return information to client
        });
    
    
        var res = await task;
        return res;
    }
    

    并更新客户端以使用异步并等待它对服务的调用。

  5. 应用了此链接中提出的Worker线程解决方案 https://support.microsoft.com/en-us/kb/2538826 虽然我使用的是.net 4.5.1,并将MinThreads设置为1000 worker和1000 IOCP
  6. 毕竟这项服务开始处理更多的请求,但延迟仍然存在,而简单的客户需要大约4个小时才能给出时间

    奇怪的是,我发现该服务在100毫秒内处理大约8到16个呼叫,关于当前服务中存在的线程数。

    我发现很多文章谈论需要放在machine.config和Aspnet.config中的配置,我认为这与我的情况无关,因为我在Windows服务上使用nettcp而不是IIS,但我实现了这些变化,发现结果没有变化。

    有人可以指出我所缺少的东西,或者我想从服务中得到它无法支持的东西吗?

2 个答案:

答案 0 :(得分:1)

可能是您的测试客户端的编写方式。使用NetTcp,当您创建通道时,它会尝试从空闲连接池中获取一个通道。如果它为空,则会打开一个新的套接字连接。当您关闭客户端通道时,它将返回到空闲连接池。空闲连接池的默认大小为10,这意味着一旦空闲池中有10个连接,任何后续关闭将实际关闭TCP套接字。如果您的测试代码正在快速创建和处理通道,则可能会丢弃池中的连接。然后,您可能会在TIME_WAIT状态下遇到太多套接字的问题 Here是一篇描述如何修改池行为的博客文章。

答案 1 :(得分:0)

这很可能是由于并发模式设置为Single(这是默认值)。尝试通过将ServiceBehaviourAttribute添加到服务实现来将ConcurrencyMode设置为Multiple。

请务必查看文件:https://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode(v=vs.110).aspx

示例:

// With ConcurrencyMode.Multiple, threads can call an operation at any time.   
// It is your responsibility to guard your state with locks. If 
// you always guarantee you leave state consistent when you leave 
// the lock, you can assume it is valid when you enter the lock.

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
class MultipleCachingHttpFetcher : IContract

您可能也对描述并发问题的Sessions, Instancing, and Concurrency文章感兴趣。