C# WCF每秒无法处理1000个呼叫

C# WCF每秒无法处理1000个呼叫,c#,wcf,async-await,threadpool,nettcpbinding,C#,Wcf,Async Await,Threadpool,Nettcpbinding,我正在使用nettcpbinding处理一个托管在Windows服务中的WCF服务 当我尝试对服务执行负载测试时,我构建了一个简单的客户端,它以每秒1000次的速度调用该服务,从该服务返回大约需要2到8秒,在让简单客户端运行大约半小时后,返回结果的时间会增加,一些客户端会为配置为2分钟的发送时间提供一些超时异常 我修改了服务throlting配置,如下所示 以下是我尝试执行的步骤: 修改了服务节流配置 在Windows7机器上工作,所以我转到Server2008,但结果相同 更新tcp绑定的配

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

当我尝试对服务执行负载测试时,我构建了一个简单的客户端,它以每秒1000次的速度调用该服务,从该服务返回大约需要2到8秒,在让简单客户端运行大约半小时后,返回结果的时间会增加,一些客户端会为配置为2分钟的发送时间提供一些超时异常

我修改了服务throlting配置,如下所示

以下是我尝试执行的步骤:

  • 修改了服务节流配置

  • 在Windows7机器上工作,所以我转到Server2008,但结果相同
  • 更新tcp绑定的配置,如下所示 NetTcpBinding baseBinding=新的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");
            }
    
    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=新的时间跨度(23,23,59,59);
    BindingElementCollection-elements=baseBinding.CreateBindingElements();
    ReliableSessionBindingElement reliableSessionElement=元素。查找();
    if(reliableSessionElement!=null)
    {
    reliableSessionElement.MaxPendingChannel=128;
    tcptTransportBindingElement传输=elements.Find();
    transport.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint=1000;
    CustomBinding newBinding=新的CustomBinding(元素);
    newBinding.CloseTimeout=新的时间跨度(0,20,9);
    newBinding.OpenTimeout=新的时间跨度(0,25,0);
    newBinding.ReceiveTimeout=新的时间跨度(23,23,59,59);
    newBinding.SendTimeout=新的时间跨度(0,20,0);
    newBinding.Name=“netTcpServiceBinding”;
    返回新绑定;
    }
    其他的
    {
    抛出新异常(“基绑定没有”+
    “具有ReliableSessionBindingElement”);
    }
    
  • 将我的服务功能更改为使用异步和等待

    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;
    }
    
    公共异步任务连接(ClientInfo-ClientInfo)
    {
    var task=task.Factory.StartNew(()=>
    {
    //做必要的工作
    //插入数据库
    //查询某个表以向客户端返回信息
    });
    var res=等待任务;
    返回res;
    }
    
    并将客户端更新为使用async并在其对服务的调用中等待

  • 已应用此链接中建议的工作线程解决方案 尽管我使用的是.NET4.5.1,并将MinThreads设置为1000工作者和1000 IOCP
  • 在所有这些之后,服务开始处理更多的请求,但延迟仍然存在,简单的客户端需要大约4个小时才能超时

    奇怪的是,我发现服务在100毫秒内处理了大约8到16个调用,关于服务中当前活动的线程数

    我发现很多文章都在讨论需要在machine.config和Aspnet.config中放置的配置,我认为这与我的案例无关,因为我在windows服务(而不是IIS)上使用nettcp,但我已经实现了这些更改,并且在结果中没有发现任何更改


    有人能告诉我我缺少什么,或者我想从服务中得到它不支持的东西吗?

    这很可能是由于并发模式设置为Single(这是默认值)。通过向服务实现中添加ServiceBehavior属性,尝试将ConcurrencyMode设置为多个

    请务必检查文档:

    例如:

    // 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
    

    您可能还对描述并发问题的文章感兴趣

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

    是一篇描述如何修改池行为的博客文章。

    如果该方法无法在千分之一秒内运行,您将无法阻止超时。您不断地提供服务数据,而它的处理速度无法超过您提供的速度。最终,漏斗将被填满,剩余部分将失败。如果你需要每秒处理1000个请求,你可能需要开始研究负载平衡/负载共享系统。是的,他需要像azure这样有大量节点的系统。他需要一个可以连接到数据库、进行插入、查询数据、构建对象并在1/1000秒或更好的时间内返回给用户的设置,以避免超时中断连接。我这里有杀手级的SQL server平衡,我不能超过4毫秒,他需要4倍的速度。@Franck,我感谢你的回答,但可以让我参考MSDN上的一个链接,链接到m