问题
大家好,
关于我的问题的一点背景...我目前有一个为我工作的 ISP 构建的站点,该站点根据用户的帐单状态向用户显示消息。当他们处于非付费状态时,我会显示一条非付费消息,如果他们处于滥用状态,我会显示一条滥用消息等。流量由思科 SCE 生成,它将最终用户的 HTTP 流量重定向到我的站点。
我看到的问题是流量过多。我相信流量可能是 P2P 流量、自动更新或其他任何类型的流量。基本上任何使用端口 80 的东西都会被 SCE 重定向到我的页面。
我试图在我的服务器上实施的解决方案是放置一个模块,根据用户的点击次数阻止用户。因此,如果它们在一定时间内超过阈值,它们将被重定向到另一个页面,这有望减轻处理器的负载,因为它不必执行所有 SQL 查找和发生在ASP.NET 页面。
但是,当我尝试强制执行我构建的模块时,它实际上会产生相反的结果(增加 CPU 负载)。该模块使用存储在应用程序状态中的内存表,用于通过 IP 跟踪请求。这是模块的代码:
public class IpHitCount : IHttpModule
{
const string tableKey = "appIpLog";
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(checkHitCount);
}
#endregion
private void checkHitCount(object sender, EventArgs e)
{
// Cast the parameter into a HttpApp object
HttpApplication app = (HttpApplication)sender;
// make sure that this is the user's first request for the app
// (all first requests are routed through main)
if (app.Request.Url.AbsolutePath.ToLower().Contains("main.aspx"))
{
// If the in memory table does not exist, then create it
if (app.Application[tableKey] == null)
{
app.Application[tableKey] = CreateTable();
}
DataSet ds = (DataSet)app.Application[tableKey];
DataTable tbl = ds.Tables["IpTable"];
DeleteOldEntries(tbl);
string filter = string.Format("ip = '{0}'", app.Request.UserHostAddress);
DataRow[] matchedRows = tbl.Select(filter);
if (matchedRows.Length > 0)
{
DataRow matchedRow = matchedRows[0];
if ((int)matchedRow["hitCount"] > 4)
{
app.Response.Redirect("HitCountExceeded.htm", true);
}
else
{
matchedRow["hitCount"] = (int)matchedRow["hitCount"] + 1;
}
}
else
{
DataRow newEntry = tbl.NewRow();
newEntry["timestamp"] = DateTime.Now;
newEntry["hitCount"] = 1;
newEntry["ip"] = app.Request.UserHostAddress;
tbl.Rows.Add(newEntry);
}
}
}
private DataSet CreateTable()
{
DataSet ds = new DataSet();
DataTable table = new DataTable("IpTable");
DataColumn col1 = new DataColumn("timestamp", typeof(DateTime));
col1.AutoIncrement = false;
col1.DefaultValue = DateTime.Now;
col1.ReadOnly = false;
col1.Unique = false;
DataColumn col2 = new DataColumn("ip", typeof(string));
col1.AutoIncrement = false;
col1.ReadOnly = false;
col1.Unique = false;
DataColumn col3 = new DataColumn("hitCount", typeof(int));
col1.AutoIncrement = false;
col1.ReadOnly = false;
col1.Unique = false;
table.Columns.Add(col1);
table.Columns.Add(col2);
table.Columns.Add(col3);
ds.Tables.Add(table);
return ds;
}
private void DeleteOldEntries(DataTable tbl)
{
// build the where clause
string filter = "timestamp < '" + DateTime.Now.AddMinutes(-5.0).ToString() + "'";
// run the query against the table
DataRow[] rowsToDelete = tbl.Select(filter);
// individually delete each row returned
foreach (DataRow row in rowsToDelete)
{
row.Delete();
}
}
}
所以我想知道的是:您是否可以看到我在模块中做错了什么,这可能导致 CPU 利用率高?是否有其他方法可以阻止此流量?
您能提供的任何帮助将不胜感激。
谢谢, C
解决方案
我已将模块中的代码更改为仅每 1 分钟运行一次删除部分:
if (app.Application[deletedKey] == null)
app.Application[deletedKey] = DateTime.Now;
DateTime deletedDate = (DateTime)app.Application[deletedKey];
if (DateTime.Now >= deletedDate.AddMinutes(1))
{
DeleteOldEntries(tbl);
app.Application[deletedKey] = DateTime.Now;
}
我还添加了一些我认为索引数据集的 IP 列的代码。但这似乎不对,所以我不确定它是否正在做我打算做的事情:
DataColumn[] key = new DataColumn[1];
key[0] = col1;
table.PrimaryKey = key;
ds.Tables.Add(table);
进行上述两项更改后,CPU 负载似乎已大幅下降。我想我们的 SQL 服务器现在也正在感谢上帝,它终于可以呼吸了。
谢谢大家的帮助!!