线程池友好的睡眠方法?
Thread-pool friendly approach to Sleep?
我想在 ASP.net 应用程序中插入一个睡眠(又名节流、延迟、缓缓、停留)(想象一下类似失败的登录尝试升级延迟)。
protected void Page_Load(object sender, EventArgs e)
{
Int32 sleepyTime = GetSleepyTime(Request);
if (sleepyTime > 0)
System.Threading.Thread.Sleep(sleepyTime);
//...Continue normal processing
}
我希望所有剩余的处理继续正常进行;我只是想让用户代理受苦。
问题是 ASP.net 使用线程池来处理请求。如果我要 Sleep
5、10、30 秒,我就会吃掉宝贵的有限资源。
我想它应该是这样的:
protected void Page_Load(object sender, EventArgs e)
{
Int32 sleepyTime = GetSleepyTime(Request);
if (sleepyTime > 0)
ABetterKindOfSleep(sleepyTime);
//...Continue normal processing
}
private void ABetterKindOfSleep(int milliseconds)
{
await SleepAsync(milliseconds);
}
private async void SleepAsync(int milliseconds)
{
System.Threading.Thread.Sleep(milliseconds);
}
但从未编写过任何 async/await 代码,也不了解 async
和 await
去向、原因或原因背后的逻辑,即使它可以用于 运行异步代码:不知道能不能用来[=44=]异步代码
红利阅读
- Does Thread.Sleep affect the ThreadPool?
- Sleeping in a pooled C# thread
- How to delay / throttle login attempts in ASP.NET?
- Asynchronous Thread.Sleep()
async
等价于 Thread.Sleep
是 await Task.Delay
:
if (sleepyTime > 0)
await Task.Delay(sleepyTime);
请注意,这必须在 async
方法的上下文中使用,并且在可以使用 async
的地方存在限制(特别是在 WebForms 上)。有关详细信息,请参阅我的 article on async
ASP.NET and the official tutorial on async
WebForms.
很简单。
首先你创建一个 IHttpModule
class:
class TarpitHttpModule : IHttpModule
{
}
然后通过在 web.config
:
中注册让 IIS 知道这个模块
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="Tarpit" type="TarpitHttpModule"/>
如果你是卡西尼,加到:
<configuration>
<system.web>
<httpModules>
<add name="Tarpit" type="TarpitHttpModule"/>
只要有 http 请求进来,IIS 就会调用您的 .Init
方法。这是您将使用以下方式注册异步事件处理程序的地方:
- Application.AddOnBeginRequestAsync: Adds the specified
BeginRequest
event to the collection of asynchronous BeginRequest
当前请求的事件处理程序。
代码:
public void Init(HttpApplication application)
{
//This is the synchronous event handler; which we don't want
//application.BeginRequest += new EventHandler(this.Application_BeginRequest);
//EventHandlerTaskAsyncHelper requires .NET 4.5
//https://brockallen.com/2013/07/27/implementing-async-http-modules-in-asp-net-using-tpls-task-api/
// Archive: http://archive.is/Cdvle
//
//Normally you'd have to write a pair of methods:
// application.AddOnBeginRequestAsync(OnBegin, OnEnd);
//
//and then we'd have to write an OnBegin which returns IAsyncResult, and then OnEnd which takes the IAsyncResult.
//The modern way is to use Tasks, and use the IAsyncResult that a Task **is**.
//Fortunately the .NET team wrote a handy class that wraps up the boilerplate catching faults, etc,
//and created the EventHandlerTaskAsyncHelper class
var beginTaskHelper = new EventHandlerTaskAsyncHelper(BeginRequestAsync);
application.AddOnBeginRequestAsync(beginTaskHelper.BeginEventHandler, beginTaskHelper.EndEventHandler);
}
所以现在我们必须提供 BeginRequestAsync 异步处理程序:
async Task BeginRequestAsync(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var context = application.Context;
// In reality i would use the context.Request to come up with a unique key
// for this user agent e.g.
String key = SHA256(UserHostAddress+UserAgent+AcceptTypes+UserLanguages).ToBase64();
// And use that as a cache key store information about this user agent
Object tarpitInfo = context.Cache.Get(agentIdentity);
if (ti == null)
return;
// But in this SO demo, i'm just going to unconditionally sleep
Boolean waitPerformed = await PerformDelay(context, tarpitInfo);
if (waitPerformed)
{
context.Response.StatusCode = 429;
context.Response.StatusDescription = "Too Many Requests";
context.Response.End();
return;
}
}
然后是睡觉的工作:
async Task<Boolean> PerformDelay(HttpContext context, TarInfo ti)
{
int delayMs = 3000;
Task delay = Task.Delay(delayMs);
await delay;
return true;
}
我还想阻止机器人流量攻击登录端点,我担心如果我只是等待,我会达到最大并发请求或 运行 内存不足。我还没有找到使用 Windows 和 Asp.Net.
执行此操作的低开销方法
我喜欢它 done here 的方式,它改变了 TCP/IP 堆栈的行为以缩小 window 大小而不是 ACK 后续数据包,这使得远程以指数方式返回关闭,只发送少量数据。
我可能会在前面添加一些 Linux 虚拟机 运行ning HAProxy 以利用其 DDOS capabilities
我想在 ASP.net 应用程序中插入一个睡眠(又名节流、延迟、缓缓、停留)(想象一下类似失败的登录尝试升级延迟)。
protected void Page_Load(object sender, EventArgs e)
{
Int32 sleepyTime = GetSleepyTime(Request);
if (sleepyTime > 0)
System.Threading.Thread.Sleep(sleepyTime);
//...Continue normal processing
}
我希望所有剩余的处理继续正常进行;我只是想让用户代理受苦。
问题是 ASP.net 使用线程池来处理请求。如果我要 Sleep
5、10、30 秒,我就会吃掉宝贵的有限资源。
我想它应该是这样的:
protected void Page_Load(object sender, EventArgs e)
{
Int32 sleepyTime = GetSleepyTime(Request);
if (sleepyTime > 0)
ABetterKindOfSleep(sleepyTime);
//...Continue normal processing
}
private void ABetterKindOfSleep(int milliseconds)
{
await SleepAsync(milliseconds);
}
private async void SleepAsync(int milliseconds)
{
System.Threading.Thread.Sleep(milliseconds);
}
但从未编写过任何 async/await 代码,也不了解 async
和 await
去向、原因或原因背后的逻辑,即使它可以用于 运行异步代码:不知道能不能用来[=44=]异步代码
红利阅读
- Does Thread.Sleep affect the ThreadPool?
- Sleeping in a pooled C# thread
- How to delay / throttle login attempts in ASP.NET?
- Asynchronous Thread.Sleep()
async
等价于 Thread.Sleep
是 await Task.Delay
:
if (sleepyTime > 0)
await Task.Delay(sleepyTime);
请注意,这必须在 async
方法的上下文中使用,并且在可以使用 async
的地方存在限制(特别是在 WebForms 上)。有关详细信息,请参阅我的 article on async
ASP.NET and the official tutorial on async
WebForms.
很简单。
首先你创建一个 IHttpModule
class:
class TarpitHttpModule : IHttpModule
{
}
然后通过在 web.config
:
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="Tarpit" type="TarpitHttpModule"/>
如果你是卡西尼,加到:
<configuration>
<system.web>
<httpModules>
<add name="Tarpit" type="TarpitHttpModule"/>
只要有 http 请求进来,IIS 就会调用您的 .Init
方法。这是您将使用以下方式注册异步事件处理程序的地方:
- Application.AddOnBeginRequestAsync: Adds the specified
BeginRequest
event to the collection of asynchronousBeginRequest
当前请求的事件处理程序。
代码:
public void Init(HttpApplication application)
{
//This is the synchronous event handler; which we don't want
//application.BeginRequest += new EventHandler(this.Application_BeginRequest);
//EventHandlerTaskAsyncHelper requires .NET 4.5
//https://brockallen.com/2013/07/27/implementing-async-http-modules-in-asp-net-using-tpls-task-api/
// Archive: http://archive.is/Cdvle
//
//Normally you'd have to write a pair of methods:
// application.AddOnBeginRequestAsync(OnBegin, OnEnd);
//
//and then we'd have to write an OnBegin which returns IAsyncResult, and then OnEnd which takes the IAsyncResult.
//The modern way is to use Tasks, and use the IAsyncResult that a Task **is**.
//Fortunately the .NET team wrote a handy class that wraps up the boilerplate catching faults, etc,
//and created the EventHandlerTaskAsyncHelper class
var beginTaskHelper = new EventHandlerTaskAsyncHelper(BeginRequestAsync);
application.AddOnBeginRequestAsync(beginTaskHelper.BeginEventHandler, beginTaskHelper.EndEventHandler);
}
所以现在我们必须提供 BeginRequestAsync 异步处理程序:
async Task BeginRequestAsync(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var context = application.Context;
// In reality i would use the context.Request to come up with a unique key
// for this user agent e.g.
String key = SHA256(UserHostAddress+UserAgent+AcceptTypes+UserLanguages).ToBase64();
// And use that as a cache key store information about this user agent
Object tarpitInfo = context.Cache.Get(agentIdentity);
if (ti == null)
return;
// But in this SO demo, i'm just going to unconditionally sleep
Boolean waitPerformed = await PerformDelay(context, tarpitInfo);
if (waitPerformed)
{
context.Response.StatusCode = 429;
context.Response.StatusDescription = "Too Many Requests";
context.Response.End();
return;
}
}
然后是睡觉的工作:
async Task<Boolean> PerformDelay(HttpContext context, TarInfo ti)
{
int delayMs = 3000;
Task delay = Task.Delay(delayMs);
await delay;
return true;
}
我还想阻止机器人流量攻击登录端点,我担心如果我只是等待,我会达到最大并发请求或 运行 内存不足。我还没有找到使用 Windows 和 Asp.Net.
执行此操作的低开销方法我喜欢它 done here 的方式,它改变了 TCP/IP 堆栈的行为以缩小 window 大小而不是 ACK 后续数据包,这使得远程以指数方式返回关闭,只发送少量数据。
我可能会在前面添加一些 Linux 虚拟机 运行ning HAProxy 以利用其 DDOS capabilities