ASP.NET MVC istek azaltma uygulamak için en iyi yolu?


212

Belirli bir dönemde kullanıcı işlemlerini kısıtlamanın çeşitli yollarını deniyoruz :

  • Soru / cevap gönderilerini sınırla
  • Düzenlemeleri sınırla
  • Özet akışı alımlarını sınırlama

Şimdilik, yalnızca kullanıcı etkinliğinin bir kaydını eklemek için Önbellek kullanıyoruz - eğer kullanıcı aynı etkinliği yapıyorsa / yaptığında bu kayıt varsa, kısalırız.

Önbelleği otomatik olarak kullanmak, kullanıcıların eski veri temizleme ve kayan etkinlik pencerelerini verir, ancak nasıl ölçekleneceği bir sorun olabilir.

İsteklerin / kullanıcı işlemlerinin etkili bir şekilde kısıtlanmasını sağlamanın diğer bazı yolları nelerdir (kararlılığa vurgu)?


Kullanıcı veya soru başına sınırlamaya mı çalışıyorsunuz? Kullanıcı başına, daha küçük bir set olurdu oturumu kullanabilirsiniz.
Greg Ogle

1
Kullanıcı başına, ancak Oturum kullanamadık, çünkü bu çerez gerektiriyor - şu anda IP adresine göre sınırlandırıyoruz.
Jarrod Dixon

1
Günümüzde, MVC sayfaları için github.com/stefanprodan/MvcThrottle ve web api istekleri için github.com/stefanprodan/WebApiThrottle nuget paketlerini düşünün
Andy

Yanıtlar:


240

Geçen yıl Stack Overflow'da kullandığımızın genel bir sürümü:

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

Örnek kullanım:

[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 burada bir şampiyon gibi çalışır - onu kullanarak gaz girişlerinizi otomatik olarak temizleyebilirsiniz. Ve artan trafiğimizle, bunun sunucuda bir sorun olduğunu görmüyoruz.

Bu yöntem hakkında geri bildirimde bulunmaktan çekinmeyin; Yığın Taşmasını daha iyi hale getirdiğimizde, Ewok düzeltmenizi daha da hızlı hale getirirsiniz :)


5
hızlı soru - anahtarın bir parçası olarak c.HttpContext.Request.UserHostAddress değerini kullanıyorsunuz. Bu değer boş mu yoksa boş mu yoksa aynı değer mi? (yani, bir yük dengeleyici kullanıyorsanız ve bu makinenin IP'siyse .. gerçek istemciler değil) Gibi, proxy veya yük dengeleyicileri (yani bir BIG IP F5) aynı verileri buraya koyun ve kontrol etmeniz gerekir X-Forwarded-için de falan mı?
Pure.Krome

7
@ Pure.Krome - evet, olabilir. İstemci IP'sini alırken, hem sunucu değişkenlerini hem de sunucu değişkenlerini kontrol eden REMOTE_ADDRve HTTP_X_FORWARDED_FORuygun bir şekilde dezenfekte eden bir yardımcı işlev kullanıyoruz .
Jarrod Dixon

3
@BrettRobi, kullanıcıların IP adresine dayalı sunucu benzeşimlerine sahip olduklarından eminim. Yani muhtemelen aynı sunucuya çarpıyor olacaklar.
mmcdole

4
Yorum akışında bunu çok aşağı okuyan ve okuyanlarınız için ... yeniden yönlendirmeden önce gaz kelebeği önbellek anahtarını temizleyen kendi yönlendirmelerimizi yazdık. Bu şekilde, tüm yönlendirmeler anahtarı kaldırmak için koddan geçer ve hiçbiri Gaz Kelebeği özelliğini tetiklemez.
SLoret

4
Bunun Web API sürümünü arıyorsanız, buraya bakın: stackoverflow.com/questions/20817300/…
Papa Burgundy

68

Microsoft, IIS 7 için IIS 7.0 - Beta için Dinamik IP Kısıtlamaları Uzantısı adlı yeni bir uzantıya sahiptir.

"IIS 7.0 için Dinamik IP Kısıtlamaları, web sunucusu ve web sitelerinde hizmet reddi ve kaba kuvvet saldırılarına karşı koruma sağlayan bir modüldür. Bu tür koruma, olağandışı yüksek sayıda eşzamanlı istekte bulunan HTTP istemcilerinin IP adreslerini geçici olarak engelleyerek sağlanır. veya küçük bir süre içinde çok sayıda istekte bulunanlar. " http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

Misal:

Sonrasında engellenecek ölçütleri ayarlarsanız X requests in Y millisecondsveya X concurrent connections in Y millisecondsIP adresi engellenirse, Y millisecondsisteklere tekrar izin verilir.


1
Googlebot gibi tarayıcılarda herhangi bir soruna neden olup olmadığını biliyor musunuz?
Helephant


1
Şimdi sürüm 8'den itibaren IIS ile piyasaya sürüldü ve paketlendi - iis.net/learn/get-started/whats-new-in-iis-8/…
Matthew Steeples

Bunu kullanmak isterdim, ama tarafından kısmanıza izin vermez <location>. Bu uygulama için her istek veya hiçbiri.
Kasey Speakman

Web sunucularınız bir yük dengeleyicisinin arkasındaysa, tüm trafik aynı IP adresinden geldiği için yararlı görünmüyor. Açık bir şey eksik sürece ...
Dscoduc

11

Bu URL'den ödünç alınan tekniği http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx dosyasını kısmak için değil, fakir bir adamın Hizmet Reddi (DOS) için kullanıyoruz. Bu ayrıca önbellek tabanlıdır ve yaptıklarınıza benzer olabilir. DOS saldırılarını önlemek için kısıtlıyor musunuz? Yönlendiriciler kesinlikle DOS'u azaltmak için kullanılabilir; Bir yönlendiricinin ihtiyacınız olan kısıtlamayı kaldırabileceğini düşünüyor musunuz?


1
Zaten yaptığımız şey bu - ama harika çalışıyor :)
Jarrod Dixon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.