Laden...

Windows Dienst auf 64 bit legt Server lahm

Erstellt von Loewchen0507 vor 14 Jahren Letzter Beitrag vor 14 Jahren 2.521 Views
Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren
Windows Dienst auf 64 bit legt Server lahm

Hi,

ich habe eine kleine Schnittstelle, einen Windows Dienst geschrieben, welcher Daten aus verschiedenen Datenquellen in andere transferiert. Funktioniert auch wunderbar. Bis vor ein paar Tagen. Da habe ich den Dienst auf einem 64 Bit System installiert. Einen Small Business Server mit 8 GB Speicherkapazität. Doch auf diesem System läuft mein Dienst extrem langsam. Statt zuvor drei Minuten, legt der Dienst den Server nach ein paar Minuten vollkommen lahm. Grund dafür ist, dass die Speicherauslastung auf dem Server auf 7,5 GB (nur für den Dienst) steigt. Ich habe danach erstmal geprüft was ich in den Einstellungen des Projektes bei CPU eingetragen habe. Dort habe ich Any CPU gewählt. Daher gehe ich davon aus, dass hier kein Problem besteht. Habt Ihr eine Ahnung woran das liegen könnte und wie man das Problem umgehen könnte?

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Hallo Loewchen0507,

wenn es am 64bit OS liegen würde, würdest du direkt eine BadImageFormatException bekommen.

Ich vermute eher das der Server sich vom anderen unterscheidet und entweder Software Komponenten fehlen, oder z.B. der Server keinen Kontakt zu einer Datenquelle hat.

Das kannst du aber auch nur durch Logging herausfinden.

Gruß,
Tom

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Wie sieht das denn mit .NET Framework aus?
Ich benutzte Komponenten aus .NET Framework 2.0. Das wird beim Setup auch direkt mit installiert. Allerdings ist das ja nur 32 bit. oder? Muss man dort eventuell etwas nach installieren?

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Am Framework wird es nicht liegen, da der Dienst ansonst nicht starten würde.

Ich denke eher das ein Fehler in deinem Code dafür verantwortlich ist.

Dabei ist z.B. Verbindung zu den Datenquellen gerne ein Problem welche bei einem Server Umzug auftreten kann.
Datenquelle kann nicht erreicht werden, Fehler werden nicht behandelt und die Applikation versucht es daraufhin immer wieder bis sie mal den Geist aufgibt.

Wenn du wirklich kein Anhaltspunkt hast, kannst auch mal versuchen mit einem Profiler das Problem einzugrenzen.

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

An der Datenbankverbindung kann es nicht liegen. Die stimmt. Es werden auch Daten übertragen. Allerdings extrem langsam. Fehlerbehandlung habe ich überall eingebaut. Den Profiler habe ich mitlaufen lassen. Aber ich kann daraus auch nur erkennen, dass es ewig dauert, bis der SQL Server antwortet.

Was ich im code mache ist schnell erklärt.
Ich hole mir die Daten aus der Quelle und schreibe Sie in ein Dataset.
Mit dem Wert aus der ersten Spalte mache ich dann eine Abfrage auf das Ziel. Daran erkenne ich ob dieser Datensatz schon vorhanden ist oder nicht. Ist er vorhanden so aktualisiere ich die Daten. Ist er noch nicht vorhanden, so erzeuge ich einen neuen Datensatz. Hat bisher mit allen Varianten von Betriebssystem und SQL Servern funktioniert. In dem Netzwerk indem ich momentan die Schnittstelle installiert habe existiert auch ein XP Rechner mit 32 bit. Installiere ich die Schnittstelle auf diesem Rechner, so dass von dort aus auf den SQL Server zugegriffen wird, so funktioniert alles einwandfrei. Das Problem ist dort nur die Netzwerkverbindung.

Bilde ich das gleiche System auf meinem Laptop nach. XP Prof und SQL Server 2005, so läuft die gleiche Datenmenge in 5 Minuten durch. Die Speicherkapazität übersteigt dabei nicht mal 50.000 MB und baut sich nach erfolgreichem Durchlauf auch wieder ab.

Ich bekomme auch keinerlei Fehlermeldungen, was mich sehr stutzig macht. Sonst bekomme ich Timeouts vom SQL Server oder Fehlermeldungen, dass die Verbindung zum SQL Server nicht aufgebaut werden kann, oder das ein Statement nicht funktioniert usw. Doch meine Errorlogdatei ist leer. Daten werden übertragen, aber es sind halt maximal 30 Datensätze die Sekunde. Statt 300. Vielleicht muss ich auch noch was nachkonfigurieren oder was anders schreiben... mag alles sein...

Hier mal der Codeschnipsel von der zentralen Routine:


for (int i = 0; i < Source.Tables[0].Rows.Count; i++)
{
DrSource = Source.Tables[0].Rows[i];

//Desabfrage mit KundennummerWINLine
SqlStr = SqlStr + " AND " + Properties.CoWi.Default.KDNR + " = '" + DrSource[0].ToString() + "'";
cmd = new SqlCommand(SqlStr, SqlConn);
//SqlConn.Open();
//SqlDataReader reader = cmd.ExecuteReader();

SqlDataAdapter dab = new SqlDataAdapter(SqlStr, SqlConn);
Des.Tables[0].Clear();
dab.AcceptChangesDuringFill = true;
dab.Fill(Des.Tables[0]);
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dab);

if (Des.Tables[0].Rows.Count >0)// reader.HasRows)
{
    DrDes = Des.Tables[0].Rows[0];

    for (int j = 1; j < Source.Tables[0].Columns.Count; j++)
    {
        DrDes[j] = DrSource[j];
    }

    //reader.Close();
}
else
{
    if (SqlStr.Contains("addresses"))
    {
        DrDes = Des.Tables[0].Rows.Add();
        for (int j = 0; j < Source.Tables[0].Columns.Count; j++)
        {
            DrDes[j] = DrSource[j];
        }
    }
    //reader.Close();
}
//SqlConn.Close();
SqlStr = help;

dab.AcceptChangesDuringUpdate = true;
dab.ContinueUpdateOnError = true;
dab.FillLoadOption = LoadOption.OverwriteChanges;
dab.Update(Des.Tables[0]);

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Hmpf, ja das kann immer alles mögliche sein.

Du schreibst das der SQL Server länger braucht? Kann es sein das du auf unterschiedliche Daten zugreifst? Evtl braucht der Server länger weil er andere Tabellen abfrägt die z.B. nicht indiziert sind?

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Also beim debugen habe ich festgestellt das er an sich super schnell durchläuft richtig lange braucht er bei dieser zeile:

dab.Update(Des.Tables[0]);

Da ich an dieser Stelle immer nur eine Zeile habe finde ich das ziemlich merkwürdig.

Vorher hatte ich es so gemacht, das ich erst das gesamte Dataset erstelle und dann rüber gebe. Da ging garnichts mehr. Zumindest bei großen Datenmengen. Wenn ich da um die 20.000 Datensätze drin habe, dann kackt das ding ab.

Echt blöd, wenn man so gut wie garkeinen Ansantz hat.

Kann das auch an Timeouts oder Einstellungen auf dem SQL server liegen?

T
433 Beiträge seit 2006
vor 14 Jahren

Das hört sich eher an das der SQL Server das Problem ist.

Also wenn du 20k Datensätze einfügen willst solltest du ein BulkInsert einsetzen, anstatt die einzeln per Inserts reinzuzimmern.

Wenn das aber schon bei einem Datensatz auftritt hast du aber definitiv Probleme mit der DB.
Wie groß ist denn die Tabelle, gibt es Zugriff mit Transaktionen auf die Tabelle? Arbeiten da noch mehr Leute drauf? Wieviele Spalten hast du in der Tabelle? Gibt es Trigger in der Tabelle?

Das alles kann merklich die Performance beeinflussen.

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Naja...

Es sind halt Datenbanken von Programmen, welche von USern (später mal) parallel genutzt werden sollen. Momentan läuft in diesem System der Dienst alleine auf der DB. Die einzigen Transaktionen die auf der Datenbank laufen, kommen von der Db. Die TAbelle hat soviele Spalten wie man konfiguriert. Momentan sind es glaube ich 21 Spalten, welche ich im Dataset benutzte. Die Tabelle auf der Datenbank hat allerdings ca. 70 Spalten und ja, ich fülle alle Pflichtfelder aus 😉. Trigger gibt es auf der Tabelle nicht.

Diese Schnittstelle existiert schon seit 2007 und lief bisher einwandfrei, auch wenn in beiden Programmen von mehreren Benutzern normal gearbeitet wird. In der Regel habe ich dann einen Intervall von 10 Minuten, in denen der Dienst läuft. Bisher auch ohne Probleme. Hier wurde nun aber in neue Hardware und Software investiert. Was ich eigentlich auch super finde. Aber dafür läuft meine Schnitte jetzt nicht. Der IT Fredi fragte mich auch schon, ob er noch was machen kann. Kann ja eigentlich an allem liegen. Ist ja so ziemlich alles neu.

Ach ja. Die Ports müssten noch überprüft werden. Nicht dass die durch die Firewall gesperrt werden.

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Ports an sich werden nicht das Problem sein, da ansonsten ja gar nichts geht.
Anders kann es sein wenn die Verbindung unterbrochen oder beschränkt wird.
Da solltest aber im Profiler sehen können.

Werf mal den Profiler an und nimm das Statement was so lange benötigt und führe es direkt im Query Analyzer aus. Das kannst du auch auf verschiedene Rechner testen, wie z.B. Desktop, Server, lokal am SQL Server.

Wenn es im Query Analyzer auch so lange dauert kannst du dir den Ausführungsplan mal anschauen, dort sieht man auch recht schnell was die grossen Zeitfresser sind.

Zeitgleich kannst du dir auch mal den Eventlog am SQL Server anschauen ob da vielleicht Fehler stehen.

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Ich verzweifel hier grade...

Das mit dem ausführen der Statements auf verschiedenen Maschinen habe ich schon gemacht. Ich bekomme Ausführungszeiten von 1 Sekunde bis 7 Sekunden... Jenachdem ob es ein Server oder Client ist.

Aber ich habe eben einen Anruf bekommen von jemand anderen, der auch solch eine Schnittstelle im Einsatz hat. Die arbeiten nicht mit 64 bit Systemen aber haben grade umgestellt auf den SQL Server 2008. Dort ist es genau ersichtlich wo es hängen bleibt. Nämlich beim löschen der Tabellen.


for (int y = 0; y < Additional.Length; y++)
                        {
                            Delete = SQLClass.RunSqlStatement(DesConStr, "TRUNCATE TABLE " + Additional[y].ToString() + "");
                        }

Die Funktion der Klasse sieht so aus


        static public Boolean RunSqlStatement(String ConStr, String SqlStr)
        {
            Boolean ReturnValue = false;

            SqlConnection Conn = new SqlConnection(ConStr);
            SqlCommand Cmd = new SqlCommand(SqlStr, Conn);
            
            try 
            {
                Conn.Open();
                Cmd.ExecuteNonQuery();
                ReturnValue = true;
            }
            catch
            {
                ReturnValue = false;
            }
            finally 
            {
                Conn.Close();
            }

            return ReturnValue;
        }

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Hm....
Ich hab leider keine Erfahrung mit dem 2008er aber hast du die erforderlichen Berechtigung mit dem User? TRUNCATE TABLE

Meiner Erfahrung nach sind das aber oft locks die auf der Tabelle liegen. Hast du mal im Eventlog auf dem Server geschaut, ob da was drin steht?

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Ja da steht was drin.
Kryptisch aber auf die Schnittstelle bezogen und dann bricht sie auch ab.

Den Link schau ich mir mal an.
Bisher war das so, das TRUNCATE TABLE auch funktionierte wenn andere in den Daten drin waren. Da das Programm sich die Daten nur holt, aber nichts drin ändert.

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Hi,

also ich habe den Dienst nun auf einem 32 bit System installiert. Auf einer VMWare sozusagen. Dort läuft der Dienst ohne Fehler durch. Also ich bekomme keinerlei Exception.
ABER:
Die Daten werden auch nicht übertragen. Ich habe keine Idee warum. Die Felder in die ich etwas hineinschreibe werden einfach nicht aktualisiert und neue Daten werden auch nicht angelegt. Aber wie gesagt, ich bekomme keinerlei Exceptions. Im Profiler stehen keine Fehlermeldung drin. Ich verstehe nicht, warum hier nichts transferiert wird. Kann mir irgendjemand Tipps geben?

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Da simma wieder.

Siehst du eine Verbindung im Profiler wenn du die Applikation im VMWare benutzt?
Läuft den sonst alles? Also Daten holen und so?

Was war eigentlich mit den Fehlermeldungen im SQL Server geworden, eventuell zeigen die was.

Hast du mal versucht mit einer Konfiguration die nicht läuft auf ein SQL Server 2005/2000 zu zugreifen?

Gruß,
Tom

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Man ist das Konfus...

ich habe das ganze auf meinem Rechner (XP Prof und SQL Server 2005 laufen lassen. Beide Datenbanken vorher gesichert und bei mir zurückgespielt. Die gleiche Konfiguration genommen (also nur Servername, Passwort angepasst). läuft. Bei denen den Dienst mal auf den SQL Server selber installiert. laufen lassen. Keine Fehler. Doch Insert funktioniert nicht.

Löschen der Tabellen mit Truncate. Das ist allerdings sehr interessant. Mit Truncate ist folgendes passiert:
Fehlermeldung:
Tabelle kann nicht abgeschnitten werden, da Sie für die Replikation veröffentlicht oder für 'Change Data Capture' aktiviert ist.
ABER: mit SQL Server 2005 funktioniert das ganze. Obwohl identisch (also auch mit Repli)

Gleiche Tabelle mit DELETE funktioniert einwandfrei.
Merkwürdig oder?

Ist das was besonderes von SQL Server 2008? Oder kann man das mit einer Konfiguration ändern? Habe vor kurzem alles auf TRUNCATE geändert, weil das schneller ging. Nun kann ich wieder alles umkehren!? Lieber wäre mir eine Konfigurationsanpassung.

Ist das vielleicht auch der Grund warum Update nicht funktioniert? Obwohl ich da ja nicht wirklich Einfluß drauf habe, da das Update Statement ja nicht von mir erzeugt wird sondern über den CommandBuilder.

*seufz* naja. zumindest kommen wir hier der Sache schon ein ganzes Stück näher.

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Wahrscheinlich hängt der Truncate noch und der locked natürlich die Tabelle.

MSDN schreibt schon beim 2005er das TRUNCATE TABLE bei Replikationen nicht funktioniert.

Restrictions

You cannot use TRUNCATE TABLE on tables that:

* Are referenced by a FOREIGN KEY constraint. (You can truncate a table that has a foreign key that references itself.)  
* Participate in an indexed view.  
* Are published by using transactional replication or merge replication.

Von daher, never intended to work 😉

Zumindest weisst du wo der Fehler ist und kannst ihn jetzt beheben.

Gruß,
Tom

1.274 Beiträge seit 2005
vor 14 Jahren

Hi Loewchen0507,

ganz unabhängig, von dem Problem mit TRUNCATE TABLE.
Solltest du Ressourcen von der Datenbank wieder mit Dispose() freigeben oder noch besser ein Using{} Statement verwenden.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Hallo,

@ Tom, ja du hast recht. Jetzt weis ich woran es liegt und kann es beheben. Aber gibt es denn keine Möglichkeit trotzdem Truncate zu verwenden? Kann ich die Daten nicht vorher irgendwie frei geben? Denn ein absetzen eines Delete Statements dauert im Verhältnis zum Truncate viel länger. Ich lösche 15 Tabellen mit zig tausenden von Datensätzen. Daher wäre es mir lieber, hierfür beim TRUNCATE zu bleiben. Vielleicht habt Ihr hier noch eine Idee.

@ LastGentleman, ja das using habe ich noch nicht überall eingebaut, da hast du recht, dispose kenn ich nicht... muss ich mich erstmal "schlaulesen" 😃 aber danke für den Tip. Als Frage dazu. Momentan arbeite ich immer mit conn.open und conn.close. Ich war immer der Meinung, dass bei einem close die Daten sowieso wieder freigegeben werden. Oder ist das nicht sauber?

Loewchen

1.274 Beiträge seit 2005
vor 14 Jahren

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

T
433 Beiträge seit 2006
vor 14 Jahren

Hallo Loewchen0507,

ich benutze Truncates grundsätzlich nicht im Live Betrieb, deshalb hatte ich damit nie Probleme, selbst in replizierten Umgebungen.
Laut google scheint es wohl nur zu gehen wenn du die Replikation vorher stoppst und danach wieder startest, wovon ich allerdings abraten würde.

Wenn es im laufenden Betrieb nicht mehr in vernünftiger Zeitspanne geht, kannst du ein Aktiv Flag in der Table verwenden und die deaktivierten Datensätze regelmässig in Wartungsskripten löschen.
So handhabe ich das immer bei grossen Datenbanken.

Gruß,
Tom

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Hi,

also die beiden Links sind sehr interessant. Mit dem neu erlangten Wissen werde ich mal ein wenig rumspielen. Allerdings erstmal in einem neuen Projekt. Mal sehen in wie weit ich das für meine Zwecke gebrauchen kann.

@Tom:
grundsätzlich gebe ich dir Recht. Allerdings hilft mir das in meinem Fall nciht wirklich weiter. die Schnittstelle, die ich gebaut habe, versucht grundlegend Datensätze zu aktualisieren. Doch bei einigen tabellen kann ich dies nicht tun, da ich keinen Punkt habe, der für mich eine eindeutige Erkennung des Datensatzes gibt. Das liegt daran, das ich zwischen zwei Produkten "repliziere" die sich überhaupt nicht kennen und auf komplett unterschiedliche Art und Weise Ihre Daten verwalten. Lange Rede kurzer Sinn. Ich habe daher bei einigen Tabellen nur die Möglichkeit die Tabelle komplett zu löschen und die Daten aus der Quelle neu aufzuarbeiten und komplett neu rüber schieben. Grundsätzlich funktioniert das auch immer wunderbar. Das einzige was stört ist, dass ich gerne alle 5 Minuten transferieren möchte. Doch die Delete Statements benötigen viel zu viel Zeit mit der Protokollierung. Daher habe ich mich für Truncate Table entschieden. Da wußte ich aber noch nicht, dass die Zieldatenbank, zu einem späteren Zeitpunkt in eine SQL Server Replikation eingebunden werden würde. Nun ja. Da musste ich wohl oder übel wieder auf Delete zurückgreifen. Ich werde das auf jedenfall im Auge haben. Ach ja und replikation stoppen und hinterher wieder starten kommt natürlich nicht in Frage. Da können ja imense Datenverluste bei entstehen. Das will ich natürlich nicht. Vielleicht finde ich ja irgendwann mal Informationen dazu, oder Microsoft bietet hierfür eine Lösung an.

Ach ja und zu dem Update Statement. Ganz blöde. Habe in dem Select Statement doch tatsächlich eine Spalte doppelt drin gehabt. Dann meckert er natürlich rum. Wenn Du in einem Update mit Set 2 gleiche Spalten verändern willst und dann auch noch mit zwei verschiedenen Werten. Das mag er halt nicht (blush)

Ansonsten funktioniert jetzt alles. Nur der Dienst braucht dreimal so lange wie zuvor (Nur wegen Delete 😭 )

Loewchen

T
433 Beiträge seit 2006
vor 14 Jahren

Hi Loewchen0507,

was mir noch eingefallen ist.
Wenn du eine sehr hohe Verfügbarkeit der Daten benötigst kannst du auch auf 'staging tables' zurückgreifen.
Der Aufwand ist zwar um einiges grösser, dafür sind die Daten 24/7 verfügbar. Was ja bei einem Einsatz von Truncate/Delete nicht der Fall wäre.

Und zwar ist die Idee dahinter so, dass du die öffentlichen Daten z.B. in der Tabelle Products hast. Daneben hast du z.B. eine Tabelle Products_stage nur für dich.
Die Products_stage nimmst du nicht in die Replikation auf. Befüllst die wie du willst / löscht vorher mit Truncate etc.
Anschliessend machst du nur noch ein Abgleich zwischen den 2 Tabellen.
Also löscht nur die Daten die in Products_stage fehlen, aktualisierst alle restlichen Daten in Products und fügst anschliessend alle fehlenden Daten in Products hinzu.

Somit gewährleistest du das die Daten der Tabelle immer verfügbar sind.

Das vorgehen kenne ich von Fault Resilient Systemen.

Gruß,
Tom

Loewchen0507 Themenstarter:in
292 Beiträge seit 2006
vor 14 Jahren

Hallo Tom,

habe mich mit dem Thema befasst. Du hast Recht der Aufwand ist um einiges höher, aber wenn man das in eine Klasse auslagert, dann macht man die Arbeit nur einmal. 😉. Wenn ich es gemacht habe und Du Dich dafür interessierst, dann kann ich es Dir ja schicken.

Loewchen