質問
皆さんこんにちは、
私の問題の背景を少し説明します... 現在、私が働いている ISP 用に構築されたサイトがあり、請求状況に基づいてユーザーにメッセージを表示します。非有料の場合は非有料メッセージを表示し、不正使用の場合は不正使用のメッセージなどを表示します。トラフィックは、エンド ユーザの HTTP トラフィックをサイトにリダイレクトする Cisco SCE によって生成されます。
私が見ている問題は、過剰なトラフィックです。トラフィックは、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);
上記の 2 つの変更を行った後、CPU 負荷は劇的に減少したようです。私たちの SQL サーバーも、ようやく息ができるようになったことを神に感謝していると思います。
助けてくれてありがとう!!