วิธีที่ดีที่สุดที่จะใช้การควบคุมปริมาณคำขอใน ASP.NET MVC?


212

เรากำลังทดลองด้วยวิธีต่างๆในการเร่งการทำงานของผู้ใช้ในช่วงเวลาที่กำหนด :

  • จำกัด การโพสต์คำถาม / คำตอบ
  • จำกัด การแก้ไข
  • จำกัด การดึงฟีด

ในขณะนี้เรากำลังใช้ Cache เพื่อแทรกบันทึกกิจกรรมของผู้ใช้ - หากบันทึกนั้นมีอยู่หาก / เมื่อผู้ใช้ทำกิจกรรมเดียวกันเราก็เค้น

การใช้แคชจะทำให้เราทำความสะอาดข้อมูลเก่าและหน้าต่างเลื่อนกิจกรรมของผู้ใช้โดยอัตโนมัติ แต่การปรับขนาดอาจเป็นปัญหาได้อย่างไร

มีวิธีอื่นใดอีกบ้างที่ทำให้มั่นใจได้ว่าคำขอ / การกระทำของผู้ใช้สามารถควบคุมปริมาณได้อย่างมีประสิทธิภาพ (เน้นที่ความมั่นคง)


คุณกำลังพยายาม จำกัด ต่อผู้ใช้หรือต่อคำถาม? หากต่อผู้ใช้สามารถใช้เซสชันซึ่งจะเป็นชุดที่เล็กกว่า
เกร็ก Ogle

1
มันเป็นต่อผู้ใช้ แต่เราไม่สามารถใช้เซสชันได้เนื่องจากต้องใช้คุกกี้เรากำลัง จำกัด ตามที่อยู่ IP ในปัจจุบัน
Jarrod Dixon

1
ปัจจุบันพิจารณาแพ็คเกจ nuget github.com/stefanprodan/MvcThrottleสำหรับหน้า MVC และgithub.com/stefanprodan/WebApiThrottleสำหรับคำขอเว็บ api
Andy

คำตอบ:


240

นี่เป็นรุ่นทั่วไปของสิ่งที่เราใช้กับ Stack Overflow สำหรับปีที่ผ่านมา:

/// <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 fix ที่เร็วยิ่งขึ้น :)


5
คำถามด่วน - คุณกำลังใช้ค่า c.HttpContext.Request.UserHostAddress เป็นส่วนหนึ่งของคีย์ ค่านั้นเป็นไปได้ว่าว่างเปล่าหรือว่างเปล่าหรือเป็นค่าเดียวกันทั้งหมดหรือไม่? (เช่นถ้าคุณใช้ load balancer และเป็น IP ของเครื่องนั้นไม่ใช่ไคลเอนต์จริง ๆ ) ชอบทำ proxy proxy หรือ load balancer (เช่น BIG IP F5) ใส่ข้อมูลเดียวกันในนั้นและคุณต้องตรวจสอบ สำหรับ X-Forwarded- สำหรับหรือยัง
Pure.Krome

7
@ Pure.Krome - ใช่มันอาจเป็นไปได้ เมื่อดึง IP ลูกค้าเราจะใช้ฟังก์ชั่นผู้ช่วยว่าการตรวจสอบทั้งในREMOTE_ADDRและHTTP_X_FORWARDED_FORตัวแปรของเซิร์ฟเวอร์และจะทำความสะอาดอย่างเหมาะสม
Jarrod Dixon

3
@BrettRobi ฉันค่อนข้างแน่ใจว่าพวกเขามีเซิร์ฟเวอร์ที่เกี่ยวข้องตามที่อยู่ IP ของผู้ใช้ ดังนั้นพวกเขาจะยังคงกดปุ่มเซิร์ฟเวอร์เดียวกัน
mmcdole

4
สำหรับบรรดาของคุณที่สนใจและได้อ่านสิ่งนี้ลงในสตรีมความคิดเห็น ... เราจบลงด้วยการเขียนการเปลี่ยนเส้นทางของเราเองเพื่อล้างแคชคีย์เค้นก่อนที่จะเปลี่ยนเส้นทาง วิธีนี้การเปลี่ยนเส้นทางทั้งหมดผ่านรหัสเพื่อลบคีย์และไม่มีใครเรียกใช้คุณลักษณะ Throttle
Sloret

4
หากคุณกำลังมองหาเวอร์ชั่น Web API อยู่ที่นี่: stackoverflow.com/questions/20817300/…
Papa Burgundy

68

Microsoft มีนามสกุลใหม่สำหรับ IIS 7 เรียกว่า Dynamic IP Restrictions Extension สำหรับ IIS 7.0 - Beta

"ข้อ จำกัด 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 millisecondsที่อยู่ IP จะถูกปิดกั้นการY millisecondsร้องขอจะได้รับอนุญาตอีกครั้ง


1
คุณรู้หรือไม่ว่ามันทำให้เกิดปัญหากับซอฟต์แวร์รวบรวมข้อมูลเช่น Googlebot หรือไม่?
ช่วย


1
วางจำหน่ายแล้วและติดตั้ง IIS พร้อมกับเวอร์ชัน 8 - iis.net/learn/get-started/whats-new-in-iis-8/…
Matthew Steeples

ฉันชอบที่จะใช้นี้ <location>แต่ก็ไม่ได้ช่วยให้คุณสามารถเค้นโดย มันคือทุกคำขอสำหรับแอพหรือไม่มีเลย
Kasey Speakman

ดูเหมือนจะไม่เป็นประโยชน์หากเว็บเซิร์ฟเวอร์ของคุณอยู่หลัง load balancer เนื่องจากทราฟฟิกทั้งหมดจะปรากฏจากที่อยู่ IP เดียวกัน เว้นแต่ฉันจะหายไปบางสิ่งบางอย่างชัดเจน ...
Dscoduc

11

เราใช้เทคนิคที่ยืมมาจาก URL นี้http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspxไม่ใช่เพื่อการควบคุมปริมาณ แต่สำหรับ Denial Of Service (DOS) ของคนยากจน นี่เป็นข้อมูลแคชและอาจคล้ายกับสิ่งที่คุณทำ คุณกำลังควบคุมปริมาณเพื่อป้องกันการโจมตีของ DOS หรือไม่? เราเตอร์สามารถใช้เพื่อลด DOS ได้อย่างแน่นอน คุณคิดว่าเราเตอร์สามารถจัดการปริมาณที่คุณต้องการหรือไม่?


1
นั่นเป็นสิ่งที่เรากำลังทำอยู่ - แต่มันก็ใช้งานได้ดี :)
Jarrod Dixon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.