Frage

Frage

Hallo alle,

Ein wenig Hintergrund auf meiner Frage ... Ich habe derzeit eine Website für den ISP gebaut ich dafür arbeite Nachrichten an Benutzer zeigt auf der Grundlage ihres Abrechnungsstatus. Wenn sie in Nicht-Pay sind angezeigt ich eine Nachricht Non-Pay und wenn sie in Abuse sind, zeige ich einen Missbrauch Nachricht usw. Der Verkehr von einem Cisco SCE generiert wird, die die Endbenutzers HTTP-Verkehr auf meiner Website umleitet.

Das Problem, das ich sehe, ist übermäßiger Verkehr. Ich glaube, der Verkehr könnte P2P-Verkehr, automatisches Updates sein, oder irgendetwas anderes in der Art. Im Grunde alles, was 80-Port verwendet wird von der SCE auf meine Seite umgeleitet.

Die Lösung, die ich auf meinem Server zu erzwingen bin versucht, ein Modul an seinem Platz zu setzen, dass die Blöcke Benutzer auf ihrer Trefferanzahl basieren. Also, wenn sie eine Schwelle während einer bestimmten Zeitdauer überschreiten, werden sie auf eine andere Seite umgeleitet werden, die hoffentlich die Last vom Prozessor bringen, da es müssen alle SQL-Abfragen und Intelligenz nicht tun, die in die Takes ASP.NET-Seite.

Allerdings, wenn ich ein Modul versuchen durchzusetzen, das ich gebaut, es hat tatsächlich das Gegenteil (erhöht die CPU-Last). Das Modul verwendet eine Tabelle, die im Speicher in Anwendungsstatus gespeichert wird, die sich um die Anforderungen von IP zu verfolgen, verwendet. Hier ist der Code für das Modul:

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();
        }
    }
}

Also, was ich frage mich, ist die folgende: Gibt es etwas, das Sie sehen, dass ich in dem Modul falsch tue, was die hohe CPU-Auslastung verursacht werden könnte? Gibt es eine Alternative Art und Weise, dass ich diesen Verkehr blockieren sollte?

Jede Hilfe Sie würde zur Verfügung stellen können sehr geschätzt.

Danke, C


Lösung

Ich habe den Code in das Modul nur führen Sie den Löschabschnitt alle 1 Minute geändert:


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

Ich habe auch einen Code, dass ich Indizes die IP-Säule meines Datensatzes glauben. Es scheint nicht richtig, obwohl, so bin ich nicht sicher, dass es das tut, was ich bin es die Absicht zu tun:


    DataColumn[] key = new DataColumn[1];
    key[0] = col1;

    table.PrimaryKey = key;

    ds.Tables.Add(table);

die beiden oben genannten Änderungen Nachdem scheint die CPU-Last deutlich verringert zu haben. Ich stelle mir vor, dass unser SQL-Server auch Gott zu danken, dass es jetzt endlich kann Atem an.

Vielen Dank für jede Hilfe !!

War es hilfreich?

Lösung

Es gibt ein paar Dinge, die ich würde versuchen:

  • Das erste, was ich sehe, ist, dass Sie die „DeleteOldEntries“ sind rufen jedes Mal dieser Code-Unter ausgeführt wird, die es bei jedem Durchgang einen Scan durch das gesamte Datatable tun verursacht. Gibt es eine andere Möglichkeit, dies nur zu bestimmten Zeiten zu laufen begrenzen könnte? Wenn kein Timer, der es alle 15 Sekunden läuft, dann vielleicht eine zweite Variable im Zustand (wie „ExecCount“), die jedes Mal, „CheckHitCount“ erhöht ausgeführt wird, so dass Sie nur jeden 10. oder 20. Mal durch spülen? Auf diese Weise können Sie diesen potenziell teueren Abschnitt des Codes auf jeder Fahrt vermeiden.
  • Eine weitere Option ist das Hinzufügen eines Index zu Ihrem Datatable. Ich bin nicht sicher, wie .NET-Lookups in Datentabellen behandelt, aber vielleicht wäre dies für Sie von Interesse sein: MSDN Artikel

Können Sie so etwas wie ANTS Profiler zu sehen, wo die meiste Zeit während der Ausführung ausgegeben wird? Da stelle ich mir diese Seite viele genannt wird, viele Male / Sekunde, wie du die Auswirkungen senken kann sogar ein wenig einen großen Unterschied machen würde.

Wenn Sie einige Ergebnisse zu erhalten, sind aber immer noch nicht zufrieden, stellen Sie sicher, dass Sie Ihre Frage modifizieren, um die neuen Informationen hinzuzufügen, so können wir halten an einer Lösung arbeiten, die Sie mit zufrieden sind.

Andere Tipps

Nun, müssen Sie daran denken, dass der Datensatz im Speicher sein wird, und über den Datensatz zu suchen, ist es viel CPU-Zyklen dauern wird, um die Datensätze zu finden, die Sie suchen.

Hinzu kommt die Tatsache, dass da dies eine Web-Anwendung ist, können Sie eine Menge Hits bekommen gehen, so dass Sie diese Routine aufrufen wollen, um am Ende sehr, sehr oft.

Meine Empfehlung wäre die Trefferzahl in einem Datenbank-Server zu speichern und dann aktualisieren und den Server abfragen, um zu sehen, ob die Trefferanzahl überschritten wird. Es werden in der Lage, die Last, sowie handhaben die Größe des Datensatzes zu behandeln, die Sie abfragen wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top