【问题标题】:WCF not handle 1000 call per secondWCF 不处理每秒 1000 个调用
【发布时间】:2015-08-27 07:50:03
【问题描述】:

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

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

我修改了服务限制配置,是这样的

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

  1. 修改了服务节流配置

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

  2. 在 Windows 7 机器上工作,所以我搬到了服务器 2008,但结果相同。
  3. 更新 tcp binding 的配置如下 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. 将我的服务功能更改为使用异步和等待

    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;
    }
    

    并更新客户端以使用 async 并在它对服务的调用中等待。

  5. 应用了此链接中提出的 Worker 线程解决方案 https://support.microsoft.com/en-us/kb/2538826 虽然我使用的是 .net 4.5.1,并将 MinThreads 设置为 1000 worker 和 1000 IOCP

毕竟服务开始处理更多请求,但延迟仍然存在,简单的客户端需要大约 4 个小时才能超时

奇怪的是,我发现服务在 100 毫秒内处理了大约 8 到 16 次调用,这与服务中当前存在的线程数有关。

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

有人可以指出我缺少什么或我想从服务中获得它无法支持的东西吗?

【问题讨论】:

  • 如果方法不能在 1/1000 秒内运行,您将永远无法防止超时。你不断地提供服务数据,它处理它的速度不能比你提供它的速度快。最终漏斗会被填满,剩下的会失败。
  • 如果您需要每秒处理 1000 个请求,您可能需要开始研究负载平衡/负载共享系统。
  • 是的,他需要像 azure 这样有很多节点的东西。他需要一个可以连接到数据库、进行插入、查询数据、构建对象并在 1/1000 秒或更短的时间内将所有这些内容返回给用户的设置,以免超时断开连接。我在这里有杀手级 SQL 服务器平衡,我不能超过 4 毫秒,他需要快 4 倍。
  • @Franck,我很欣赏你的回答,但可以将我推荐给 MSDN 上的链接,以确保我是否走错路
  • 请用客户端实现更新您的问题 - 可能是创建客户端实例需要很长时间,也可能是其他问题。您的 WS 方法实现是否执行任何长时间运行的计算或任何 IO 任务?可能问题不在 WCF 中,而是在等待数据库完成操作。

标签: c# wcf async-await threadpool nettcpbinding


【解决方案1】:

这很可能是由于并发模式设置为 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 文章感兴趣。

【讨论】:

  • 我已经将它设置为多个,这是我当前的配置 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2015-10-09
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 2019-08-29
    • 2019-08-07
    相关资源
    最近更新 更多