WCF не обрабатывает 1000 вызовов в секунду

Я работаю над службой WCF, размещенной в службе Windows, используя nettcpbinding.

когда я попытался выполнить нагрузочный тест для службы, я создал простой клиент, который вызывает службу около 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. изменил функцию моих служб, чтобы использовать асинхронность и ждать

    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 thread, предложенное по этой ссылке https://support.microsoft.com/en-us/kb/2538826 хотя я использую .net 4.5.1 и установил для MinThreads значение 1000 worker и 1000 IOCP

после всего этого служба начинает обрабатывать больше запросов, но задержка все еще существует, и простому клиенту требуется около 4 часов, чтобы дать тайм-аут

Странно, что я обнаружил, что служба обрабатывает от 8 до 16 вызовов в течение 100 мс, что касается количества потоков, которые в настоящее время находятся в службе.

я нашел много статей, в которых говорится о конфигурации, которую необходимо поместить в machine.config и Aspnet.config, я думаю, что это не связано с моим случаем, поскольку я использую nettcp для службы Windows, а не для IIS, но я реализовал эти изменения и нашел никаких изменений в результатах.

может ли кто-нибудь указать мне, что мне не хватает, или я хочу от службы чего-то, что она не может поддерживать?


person mkalashy    schedule 11.06.2015    source источник
comment
Если метод не может работать за 1/1000 секунды, вы никогда не сможете предотвратить тайм-аут. вы продолжаете передавать данные службы, и она не может обрабатывать их быстрее, чем вы их передаете. в конце концов воронка будет заполнена, а остатки пропадут.   -  person Franck    schedule 11.06.2015
comment
Если вам нужно обслуживать 1000 запросов в секунду, вы можете начать изучать системы балансировки/распределения нагрузки.   -  person Ron Beyer    schedule 11.06.2015
comment
Да ему нужно что-то вроде лазури с кучей нод. Ему нужна установка, которая может подключаться к базе данных, выполнять вставки, запрашивать данные, создавать объекты и возвращать пользователю все это за 1/1000 секунды или быстрее, чтобы не прерывать соединения со временем. У меня есть убийственная балансировка SQL-сервера, и я не могу получить лучше, чем 4 мс, ему нужно в 4 раза быстрее.   -  person Franck    schedule 11.06.2015
comment
@Franck, я ценю ваш ответ, но могу направить меня по ссылке в MSDN, где так написано, чтобы убедиться, что я на неправильном пути или нет.   -  person mkalashy    schedule 15.06.2015
comment
@RonBeyer, не могли бы вы дать мне ссылку на MSDN, которая доказывает, что мне нужна балансировка нагрузки для обработки 1000 вызовов в секунду?   -  person mkalashy    schedule 15.06.2015
comment
нет ссылки, это просто базовая математика. Если я отправлю вам сообщение для чтения каждую секунду, и вы потратите 1 секунду, чтобы прочитать его, вы будете как раз вовремя. но если вы потратите 2 секунды, чтобы прочитать его, то, когда вы читаете один, у вас есть еще 2 на стороне, поскольку я посылаю вам быстрее, чем вы можете прочитать. в следующую секунду вы читаете еще один, но у вас есть еще 2 сбоку. в конце концов, как только вы прочитали 1000 сообщений за 2000 секунд, я отправил вам 2000 сообщений, которые лежали у вас на столе. В конце концов, стол не сможет вместить всю стопку непрочитанных сообщений. сообщение, падающее на пол, является сброшенным соединением.   -  person Franck    schedule 15.06.2015
comment
если вашему процессору требуется 100 мс для запуска вашего метода, он сможет выполнять МАКСИМУМ 10 раз метод в секунду. Теперь, как говорится, вам нужно запустить 1000 раз ваш метод за 1 секунду, поэтому вам нужно запустить метод 1000 раз за 1 секунду = 1000 мс / 1000 раз = 1 мс на метод. Таким образом, весь ваш метод должен обрабатываться быстрее или равной 1 миллисекунде, что я не думаю, что это возможно на одном сервере. забудьте о многопоточности 1 сек, так как один вызов может выполняться только на 1 процессоре. прямо сейчас ваш метод занимает около 12,5 мс, вам нужно в 12,5 раз больше скорости на одном ядре, чтобы снизить ее до нашей 1 мс.   -  person Franck    schedule 15.06.2015
comment
пожалуйста, обновите свой вопрос с реализацией клиента - возможно, создание экземпляров клиента занимает много времени или это может быть какая-то другая проблема. Выполняет ли ваша реализация метода WS какие-либо длительные вычисления или какие-либо задачи ввода-вывода? Возможно, проблема не в WCF, а в ожидании завершения работы базы данных.   -  person pg0xC    schedule 17.06.2015


Ответы (2)


Это может быть то, как написан ваш тестовый клиент. С NetTcp, когда вы создаете канал, он пытается получить его из пула незанятых соединений. Если он пуст, то он открывает новое соединение сокета. Когда вы закрываете клиентский канал, он возвращается обратно в пул незанятых соединений. Размер пула незанятых соединений по умолчанию равен 10, что означает, что как только в пуле бездействия будет 10 подключений, любое последующее закрытие фактически закроет сокет TCP. Если ваш тестовый код быстро создает и удаляет каналы, вы можете отбрасывать соединения в пуле. В этом случае вы можете столкнуться с проблемой слишком большого количества сокетов в состоянии TIME_WAIT.
Вот запись в блоге, описывающая, как изменить поведение объединения.

person MattC    schedule 11.06.2015

Скорее всего, это связано с тем, что для режима параллелизма установлено значение Single (это значение по умолчанию). Попробуйте установить для ConcurrencyMode значение Multiple, добавив ServiceBehaviourAttribute в реализацию службы.

Обязательно ознакомьтесь с документацией: 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

Вас также могут заинтересовать Сеансы, создание экземпляров и параллелизм. статья, описывающая проблемы параллелизма.

person pg0xC    schedule 11.06.2015
comment
у меня уже установлено несколько, это моя текущая конфигурация [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] - person mkalashy; 15.06.2015