Лучший способ реализовать регулирование запросов в ASP.NET MVC?

212

Мы экспериментируем с различными способами регулирования действий пользователя в данный период времени :

  • Ограничить вопрос / ответ постов
  • Ограничение правок
  • Ограничить поиск каналов

В настоящее время мы используем Cache для простой вставки записи активности пользователя - если эта запись существует, если / когда пользователь выполняет ту же самую активность, мы ограничиваемся.

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

Каковы другие способы обеспечения эффективного регулирования запросов / действий пользователя (акцент на стабильность)?

Джаррод Диксон
источник
Вы пытаетесь ограничить количество пользователей или вопросов? Если на пользователя, можно использовать сеанс, который будет меньшим набором.
Грег Огл
1
Это для каждого пользователя, но мы не могли использовать сессию, поскольку для этого требуются файлы cookie - в настоящее время мы ограничиваемся по IP-адресу.
Джаррод Диксон
1
В настоящее время рассмотрим пакеты nuget github.com/stefanprodan/MvcThrottle для страниц MVC и github.com/stefanprodan/WebApiThrottle для запросов веб-API
Andy

Ответы:

240

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

/// <summary>
/// Decorates any MVC route that needs to have client requests limited by time.
/// </summary>
/// <remarks>
/// Uses the current System.Web.Caching.Cache to store each client request to the decorated route.
/// </remarks>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ThrottleAttribute : ActionFilterAttribute
{
    /// <summary>
    /// A unique name for this Throttle.
    /// </summary>
    /// <remarks>
    /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1"
    /// </remarks>
    public string Name { get; set; }

    /// <summary>
    /// The number of seconds clients must wait before executing this decorated route again.
    /// </summary>
    public int Seconds { get; set; }

    /// <summary>
    /// A text message that will be sent to the client upon throttling.  You can include the token {n} to
    /// show this.Seconds in the message, e.g. "Wait {n} seconds before trying again".
    /// </summary>
    public string Message { get; set; }

    public override void OnActionExecuting(ActionExecutingContext c)
    {
        var key = string.Concat(Name, "-", c.HttpContext.Request.UserHostAddress);
        var allowExecute = false;

        if (HttpRuntime.Cache[key] == null)
        {
            HttpRuntime.Cache.Add(key,
                true, // is this the smallest data we can have?
                null, // no dependencies
                DateTime.Now.AddSeconds(Seconds), // absolute expiration
                Cache.NoSlidingExpiration,
                CacheItemPriority.Low,
                null); // no callback

            allowExecute = true;
        }

        if (!allowExecute)
        {
            if (String.IsNullOrEmpty(Message))
                Message = "You may only perform this action every {n} seconds.";

            c.Result = new ContentResult { Content = Message.Replace("{n}", Seconds.ToString()) };
            // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
            c.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
        }
    }
}

Пример использования:

[Throttle(Name="TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)]
public ActionResult TestThrottle()
{
    return Content("TestThrottle executed");
}

ASP.NET Cache работает как первоклассный - с его помощью вы получаете автоматическую очистку ваших записей газа. И с нашим растущим трафиком, мы не видим, что это проблема на сервере.

Не стесняйтесь дать отзыв об этом методе; когда мы сделаем Stack Overflow лучше, вы исправите Ewok еще быстрее :)

Джаррод Диксон
источник
5
Быстрый вопрос - вы используете значение c.HttpContext.Request.UserHostAddress как часть ключа. Это значение возможно пустым или нулевым, или все одно и то же значение? (т. е. если вы используете балансировщик нагрузки, а это IP-адрес этой машины, а не реальных клиентов) Например, прокси-серверы или балансировщики нагрузки (т. е. BIG IP F5) помещают туда те же данные, и вам нужно проверить для X-Forwarded-For также или что-то?
Pure.Krome
7
@ Pure.Krome - да, это может быть. При извлечении IP клиента, мы используем вспомогательную функцию , которая проверяет , как REMOTE_ADDRи HTTP_X_FORWARDED_FORпеременные сервера и дезинфицирует соответствующим образом .
Джаррод Диксон
3
@BrettRobi, я почти уверен, что они привязаны к серверу в зависимости от IP-адреса пользователя. Таким образом, они, вероятно, все еще будут использовать тот же сервер.
mmcdole
4
Для тех из вас, кому это небезразлично и которые читали это далеко внизу в потоке комментариев ... мы закончили тем, что написали наши собственные перенаправления, которые очищают ключ кэша газа перед перенаправлением. Таким образом, все перенаправления проходят через код для удаления ключа, и ни одно из них не вызывает атрибут Throttle.
SLoret
4
Если вы ищете версию этого веб-API, проверьте здесь: stackoverflow.com/questions/20817300/…
Папа Бургундский
68

У Microsoft есть новое расширение для IIS 7, которое называется «Динамическое расширение IP-ограничений» для IIS 7.0 - бета-версия.

«Динамические ограничения IP для IIS 7.0 - это модуль, который обеспечивает защиту от атак типа« отказ в обслуживании »и атак« грубой силы »на веб-сервер и веб-сайты. Такая защита обеспечивается путем временной блокировки IP-адресов клиентов HTTP, которые выполняют необычно большое количество одновременных запросов или которые делают большое количество запросов в течение небольшого периода времени. " http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

Пример:

Если вы установите критерии для блокировки после X requests in Y millisecondsили X concurrent connections in Y millisecondsIP-адрес будет заблокирован, Y millisecondsто запросы будут снова разрешены.

notandy
источник
1
Знаете ли вы, вызвало ли это какие-либо проблемы с сканерами, такими как робот Google?
Helephant
@Helephant webmasters.stackexchange.com/questions/26553/…
Анирудха Гупта
1
Теперь он выпущен и поставляется с IIS начиная с версии 8 - iis.net/learn/get-started/whats-new-in-iis-8/…
Мэтью Стиплз
Я хотел бы использовать это, но это не позволяет вам задушить <location> . Это каждый запрос на приложение или нет.
Кейси
Не кажется полезным, если ваши веб-серверы находятся за балансировщиком нагрузки, так как весь трафик будет выглядеть с одного IP-адреса. Если я не
пропущу
11

Мы используем технику, заимствованную из этого URL http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx , не для регулирования, а для отказа в обслуживании бедного человека (DOS). Это также основано на кеше и может быть похоже на то, что вы делаете. Вы душите, чтобы предотвратить атаки DOS? Маршрутизаторы, безусловно, могут быть использованы для уменьшения DOS; Как вы думаете, маршрутизатор может справиться с регулированием, которое вам нужно?

Роб Крафт
источник
1
Это почти то, что мы уже делаем, но это прекрасно работает :)
Джаррод Диксон