Подтвердить что ты не робот

Управление очередью на уровне приложений/управление трафиком веб-сайта

У нас есть приложение для веб-сайта, которое мы ожидаем получить невероятно высокий трафик в нескольких точках в течение года. В настоящее время у нас есть стороннее программное обеспечение для балансировки нагрузки, которое перенаправляет пользователей на страницу "удержание" во время периодов занятости, чтобы наши серверы веб-приложений не задыхались от количества входящих запросов.

В будущем мы хотели бы получить больше контроля над этим процессом и реализовать виртуальную очередь. Текущий балансировщик нагрузки не имеет функций очередей, а просто позволяет трафик на основе ограничения скорости. Это случайный случай и приносит удачу, когда вы обновляете страницу (или получаете автоматическое обновление).

Я немного читал об этом в Интернете, но нашел небольшую информацию о реализации самой простой виртуальной очереди HTTP-запросов. Конечно, компании предлагают это как полноценное обслуживание, такое как queue-it и Netprecept но они кажутся излишними для наших текущих потребностей (и стоят очень дорого).

Входящее веб-приложение написано в ASP.Net MVC. Принимая во внимание, что в настоящий момент нам не нужны расширенные функции, такие как "приоритет очереди" и т.д., Я создал очень базовое доказательство концепции, используя статический класс менеджера очереди, используя ConcurrentQueue<T> и т.д., Но мне интересно, это допустимый, масштабируемый подход? Это что-то, что может быть частью основного уровня приложения? Или он должен храниться отдельно? Есть ли у кого-нибудь технические ноу-хау о том, как реализовать эту функцию в приложении ASP.Net MVC?


EDIT: спасибо за ответы до сих пор. Большинство ответов, похоже, содержат много подробностей о кешировании. Это уже (очень) сильно используется на нашем веб-сайте, используя веб-кэширование ASP.Net, кэширование полных запросов страниц на уровне балансировки нагрузки и кэширование объектов с помощью AppFabric.

Причина возможности управления очередью заключается в том, что процесс очень тяжелый для записи в базу данных. Мы эффективно создаем заказы на определенный продукт через веб-сайт. Это означает, что эти транзакции БД учитывают такие вещи, как проверка акций на прошлой неделе и т.д. Именно здесь возникают проблемы с производительностью, и это является причиной желания реализовать какую-либо систему очередей.

Бросить больше ресурсов на сервер базы данных не является реалистичным вариантом. Я действительно ищу подробности технических реализаций системы массового обслуживания такого рода (С# или иначе). Извините, если изначально не было ясно.

4b9b3361

Ответ 1

Рассматриваете ли вы следующие моменты при измерении производительности приложения?

  • Кэширование
  • Контроллеры без сессии
  • AsyncControllers

Кэширование вывода:

Возможно, наиболее полезной функцией MVC3 (Performance-Wise) является кэширование вывода. Самые большие Производительность на самом деле происходит, когда вашему приложению действительно нужно извлекать данные, выполнять вычисления на нем и возвращать данные. Кэширование вывода может кэшировать эти результаты, чтобы их можно было возвращать напрямую, даже не касаясь базы данных. Особенно при выполнении сложных запросов это может значительно снизить нагрузку на ваш сервер (фактически вы можете сбросить нагрузку на свой сервер на 90%, тщательно выполнив кэширование в своем веб-приложении).

namespace MvcApplication1.Controllers
{
     public class DataController : Controller
     {
          [OutputCache(Duration=10)]
          public string Index()
          {
               return DateTime.Now.ToString("T");    
          }
     }
}

Контроллеры без сессии:

Контроллеры с отключенным состоянием сеанса обеспечивают оптимизацию для контроллеров, не требующих состояния сеанса. Контроллеры без учета состояния предназначены для ситуаций, когда вам не требуется концепция сеанса.

По умолчанию конвейер ASP.NET не будет обрабатывать запросы, принадлежащие одному сеансу одновременно. Он сериализует их, то есть он ставит их в очередь в том порядке, в котором они были получены, так что они обрабатываются последовательно, а не параллельно. Это означает, что если запрос выполняется и выполняется другой запрос из того же сеанса, он будет поставлен в очередь только на выполнение, когда завершится первый запрос.

Посмотрим на пример; страница делает 3 асинхронных запроса AJAX на сервер с включенным состоянием сеанса (также обратите внимание, что сеанс фактически должен использоваться, поскольку ASP.NET достаточно умен, чтобы не сериализовать запросы, если вы никогда не используете состояние сеанса, даже если оно включено).

JQuery

$(document).ready(function () {
    //Make 3 concurrent requests to /ajaxtest/test
    for (var i = 0; i < 3; i++) {       
        $.post("/ajaxtest/test/" + i,
            function (data) {                       
                //Do something with data...
            },
            "json");
    }
});

Контроллер - метод действий

public class AjaxTestController : Controller
{       
    [HttpPost]
    public JsonResult Test(int? id)
    {
        Thread.Sleep(500);
        return Json(/*Some object*/);
    }
}

enter image description here

Вы можете увидеть эффект сериализованных запросов в сетевом профиле; каждый запрос занимает примерно 500 мс больше, чем предыдущий. Это означает, что мы не получаем никакой выгоды от асинхронного вызова этих AJAX. Давайте рассмотрим профиль снова с отключенным состоянием сеанса для нашего AjaxTestController (используя атрибут [SessionState]).

[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{       
    //...As above
}

enter image description here

Гораздо лучше! Вы можете увидеть, как три запроса обрабатываются параллельно, и выполнить в общей сложности 500 мс, а не 1500 м, которые мы видели в нашем первом примере.

Асинхронные контроллеры:

Во-первых, контроллер запускает один или несколько внешних вызовов ввода-вывода (например, вызовы базы данных SQL или вызовы веб-службы). Не дожидаясь их завершения, он возвращает поток обратно в пул рабочих потоков ASP.NET, чтобы он мог обрабатывать другие запросы.

Позже, когда все внешние вызовы ввода-вывода завершены, базовая платформа ASP.NET захватывает еще один свободный рабочий поток из пула, привязывает его к исходному контексту HTTP и позволяет ему обрабатывать исходный запрос.

enter image description here

Как измерить время отклика в режиме интенсивного трафика?

Я скопировал ниже контент из этой ссылки. Потому что когда-то ссылки ломаются, поэтому я сохранил здесь важную роль. Для получения более подробной информации см. Эту ссылку

Чтобы понять, как асинхронные контроллеры реагируют на разные уровни трафика и как это сравнивается с простым синхронным контроллером, вы можете создать образец MVC с двумя контроллерами. Чтобы имитировать длительный внешний вид, оба они выполняют SQL-запрос, который занимает 2 секунды, чтобы завершить (используя команду SQL WAITFOR DELAY 00:00:02 '), а затем они возвращают тот же фиксированный текст в браузер. Один из них делает это синхронно; другой асинхронно.

В другом примере вы можете проверить простое консольное приложение С#, которое имитирует интенсивный трафик, попадающий на заданный URL. Он просто запрашивает один и тот же URL снова и снова, вычисляя скользящее среднее за последние несколько откликов. Сначала он делает это только один поток, но затем постепенно увеличивает количество параллельных потоков до 150 в течение 30-минутного периода. Если вы хотите попробовать запустить этот инструмент на своем собственном сайте, вы можете загрузить исходный код С#.

Результаты иллюстрируют ряд вопросов о выполнении асинхронных запросов. Посмотрите на этот график среднее время отклика по сравнению с количеством одновременных запросов (более низкое время ответа лучше):

enter image description here

Чтобы понять это, сначала мне нужно сказать вам, что я установил пул рабочих потоков ASP.NET MVC на искусственно низкий максимальный предел 50 рабочих потоков. Мой сервер фактически имеет максимальный размер потока минус 200 по умолчанию - более разумный предел - но результаты становятся яснее, если я его уменьшу. Как вы можете видеть, синхронные и асинхронные запросы выполнялись точно так же, пока было достаточно рабочих потоков для перемещения. И почему они не должны? Но как только поток был исчерпан ( > 50 клиентов), синхронные запросы должны были сформировать очередь для обслуживания. Основная теория массового обслуживания говорит нам, что среднее время ожидания ожидания в очереди определяется формулой:

enter image description here

и это именно то, что мы видим на графике. Время ожидания растет линейно с длиной очереди. (Извиняюсь за мою снисходительность в использовании формулы - иногда я просто не могу подавить своего внутреннего математика. Я получаю терапию, если это станет проблемой.) Асинхронные запросы не нужно было так быстро запускать в очереди. Им не нужно блокировать рабочий поток во время ожидания, поэтому ограничение потока потока не было проблемой. Так почему они начали очереди, когда было более 100 клиентов? Это связано с тем, что пул соединений ADO.NET по умолчанию ограничен 100 параллельными соединениями.

Надеюсь, это поможет вам.

Ответ 2

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

Я бы не стал комментировать код приложения и код, который касается низкой технической оптимизации производительности. Держите его отдельно, так как он сохранит ваш код под рукой.

Ответ 3

В зависимости от вашей очереди приложения может вообще не решить вашу проблему. Если вы создадите очередь, ваш сервер будет иметь меньше работы для выполнения одновременно, потому что работает меньше параллельных потоков.

Когда очередь?

Очевидно, я должен обратить вспять вопрос: почему вы очереди? Благоприятно потому, что ваши серверы просто не могут обрабатывать количество входящего трафика. Если мы говорим о пиках, которые сохраняются всего на несколько секунд, это не имеет большого значения: создайте очередь и обработайте ее через несколько секунд.

Очередь - это просто ведро

Как ваш вопрос утверждает, что этот пик длится дольше нескольких секунд "несколько пунктов в течение года". Поэтому я предполагаю, что на ваших серверах наблюдается массовый поток новых запросов на время, которое достаточно долго, что обработка очереди просто приведет к таймаутам на клиентах. [FYI: Проверьте модель ковша в сети. У них есть те же проблемы, с которыми приходится иметь дело]

Позвольте мне привести простой пример:

Это обычный день летом, и вы предлагаете холодный лимонад на углу улицы. Вы можете обрабатывать до 5 клиентов в минуту, а пики во время обеда означают, что около 7 клиентов стоят в очереди за вашим лимонадом в минуту. Через минуту у вас ожидают 2 клиента, через две минуты у вас будет 4 клиента, ожидающих вас для обработки своих заказов [и т.д.].

По мере того как пиковый бросок просто держится, пусть, скажем, 10 минут, когда вы очередь, достигает максимальной длины 20 клиентов.

В другой день это очень жарко, и ваши броски пика не являются обычными 7 клиентами в минуту, ваши броски достигают 42 клиентов в минуту. Это означает, что уже через минуту у вас будет 37 клиентов, ожидающих вашего лимонада. Очевидно, что, кроме последнего лимонада на земле, ваши клиенты не будут стоять в очереди на чашку лимонада и просто уйдут.

И это та же проблема, связанная с вашими пиками на сервере: если вы постоянно испытываете больше входящих подключений, чем можете обрабатывать свою очередь, она будет расти до тех пор, пока она не станет полной, а затем потеряет входящих клиентов. Таким образом, все, что вы получаете с очередью, это то, что вы просто задерживаете первых отброшенных клиентов и удерживаете других клиентов (что также раздражает).

Возвращая пример реального мира. Как эта проблема может быть решена здесь? Это спокойно: ускорить обработку каждого клиента или получить некоторых клерков и открыть вторую, третью,... очередь для обработки нескольких клиентов одновременно и обработать все заказы. Как в реальном мире, так и в программировании: ускорение не так просто. получение нескольких экземпляров только на короткие промежутки времени также довольно сложно. Но ясно сказано: это единственные надежные решения для решения таких проблем.

Использование IIS и MVC: не стоит стоять в нужном месте

[Очередь в одной очереди]. Вы можете создать очередь в своем приложении и приостановить все запросы на подачу, если вы достигли максимального количества активных активных участников. Но это не означает, что нет накладных расходов для всех входящих TCP-соединений и сеансов asp, которые генерируются и загружаются по каждому запросу, поскольку IIS принимает новые соединения, если есть свободные параллельные соединения с точки зрения IIS.

Создание приложения http-прокси

[Очередь в одной или нескольких очередях] Если вы создаете собственное прокси-приложение, вы можете сами решить, хотите ли вы принимать новые входящие клиентские соединения (приостанавливать прослушивание tcp или просто не принимать новых клиентов до тех пор, пока ваш у рабочей нагрузки достаточно ресурсов для обработки новых клиентов). Конечно, ваш прокси-сервер мог распространять запросы на несколько хостов и выполнять некоторую балансировку нагрузки, но для этого требуется, чтобы у вас были дополнительные хосты, которые вы можете мгновенно запускать и обрабатывать запросы (это требует от вас любой loadbalancer: иметь бэкэнд который может обрабатывать рабочую нагрузку). Поскольку это абсолютно низкий уровень, я считаю, что не нужно вдаваться в подробности и объяснять, что при принятии этой дороги существует множество рисков.

Относительно некоторых простых аспектов просто уменьшить некоторые части рабочей нагрузки: - Выгружать статическое содержимое, например изображения на другие серверы/сайты с низкой стоимостью. Это уменьшает рабочую нагрузку на вашем основном сервере, который выполняет жесткую и динамичную работу. - Кэширование: не делайте дважды, которые имеют одинаковые результаты. Проверьте, где вы работаете, замедление работы при высокой нагрузке и попытайтесь оптимизировать их как можно быстрее. - Работать с aync/put long runners в режиме сна: если у вас есть внешние запросы (база данных), попробуйте реализовать их в асинхронном режиме, чтобы ваши потоки выполнялись как можно дольше, а затем перейдите в режим сна, чтобы дать планировщику вашего хоста возможность обработки другой ожидающей работы. Контролируйте свои темы и проверяйте, сколько времени включено в ваши критические методы, и где они проводят время.

Надеюсь, это поможет решить вашу проблему или просто дать вам представление о том, какой путь принять.

Ответ 4

Я бы рекомендовал вам использовать что-то вроде BIG-IP, если вы собираетесь использовать подход, основанный на программном обеспечении, и на каком основании вы будете Redirect ваш запрос на какие серверы? Есть много вариантов, таких как Round Robin..etc

Взгляните на эту статью, если она поможет

Ответ 5

Вы могли бы взглянуть на получение некоторых эталонных показателей, чтобы увидеть, какую нагрузку/трафик может выполнять ваша текущая настройка (инфраструктура и приложение), например. сколько одновременных пользователей и т.д.

Вы можете сделать это, возможно, используя Microsoft Team Foundation Service (размещенную в облаке, отличную от TF-сервера, которая размещается в помещении, то есть в вашей инфраструктуре). Тесты нагрузки/напряжения/производительности

Я считаю, что служба TFS бесплатна для команды разработчиков менее 5 разработчиков, я думаю. Не цитируйте меня на это: -)

Как только вы получите несколько парковых фигур, и если ваше приложение сможет справиться, тогда вам нечего делать. Если он не может принять какие-то решения? Тогда вы в сценарии 80/20. Стоит ли тратить 80% вашего ресурса (время разработки, заработная плата и т.д.) На возможное увеличение производительности на 20% или лучше инвестировать 20% стоимости оборудования (процессор, оперативная память, другой сервер и т.д.) Для мгновенного повышения производительности на 80%?

Если этот сайт является высокопрофильным для вашего бизнеса или клиента и генерирует доход или имеет законодательную цель, вы можете быстрее инвестировать в оборудование, а затем инвестировать в разработку программного обеспечения. Таким образом, вы можете использовать масштабируемое приложение с высокой доступностью (HA) без единой точки отказа (SPF).

Не отвечайте на ваши вопросы о очередности, а просто рассматривайте другую точку зрения.

FYI мы надеемся обновить до двух виртуальных машин (работающих под управлением VMWare) веб-серверов, работающих под управлением Windows Server 2012 Enterprise Edition. Это будет балансировка сетевой нагрузки с использованием microsoft NLB (поэтому нет необходимости в другом сервере балансировки нагрузки или стороннем программном обеспечении). У нас будет активный активный кластер для backedn SQL-серверов. это позволяет нам поддерживать серверы (обновления, исправления и т.д.) без простоя. Дополнительным преимуществом является то, что с IIS 8.0 вы можете запускать несколько доменов (хостов) одного и того же протокола IP для SSL (HTTPS), используя SNI, который хорош (но торпедопользователь, выполняющий Windows XP, но его поддержка в апреле 2014 года). Мы должны модернизировать приложения .net, чтобы заботиться об управлении сеансом и MACstate (пересылку через серверный сервер и т.д.), Но торговля стоит того.

Ответ 6

Наряду с ответом PKKG вам придется переделать некоторые части вашего приложения, чтобы добавить кеширование.

Кабель вывода ASP.NET MVC поддерживает зависимость кэша SQL, которая позволяет кэшировать страницу как сервером, так и клиентом на основе некоторого столбца версии в таблице.

Предположим, у вас есть страница, которая отображается очень часто, но меняется реже. Например, страница вопроса. У каждого вопроса есть, вероятно, 1:100 записи против операций чтения. Это означает, что для каждого чтения подключение к БД очень дорого.

Итак, что мы можем сделать, обработайте столбец LostUpdate в качестве столбца Version и добавьте зависимость SQL Cache на этой странице с SQL-запросом, который возвращает true. Если LastUpdate для текущего вопроса позже, то указанное время кеширования.

Для каждой отдельной страницы диспетчер кэша делает запрос кеша к SQL, но этот запрос меньше, чем целая страница, потому что страница содержит множество запросов к другой таблице, а также для построения и отображения каждой информации. Например, ответы и их авторы и их репутация и т.д. Так что в 100 раз только один запрос к LostUpdate экономит огромные накладные расходы против 100 раз всех запросов и объединений и многих других вычислений.

Делать это на каждой странице сложно, но вы можете анализировать трафик и улучшать кеширование. И в том же примере, когда Stake Overflow, кэширование на домашней странице может быть плохой идеей, поскольку она отображает последние обновленные записи, поэтому кеширование может не работать, поскольку страница изменяется слишком быстро.

Ответ 7

В некоторых вариантах используется брокер услуг sql или моментальный снимок репликации. С моментальным снимком вы можете переместить отчетный процесс на другую копию базы данных и удерживать блокировки на низком уровне.