Laden...
X
Xynratron
myCSharp.de - Member
26
Themen
1.177
Beiträge
Letzte Aktivität
vor 8 Jahren
Dabei seit
24.09.2006
Erstellt vor 10 Jahren

Hmm, schreiben hilft manchmal:

"Code ist gekürzt und anonymisiert."

Regel 1: keinen Code aus "nettigkeit" wegkürzen, nur weil man denkt, da gibt's keinen Fehler.

"load from DB"

Wenn die DB jetzt in einen Lock fährt - aus welchen Gründen auch immer - ist das Verhalten des Codes außenrum nicht mehr definiert. Wir hatten genau das gleichzeitig auf der DB. Also hat der Code zwar macken, war aber nicht schuld.

Ich hoffe das dient wenigstens als gutes Beispiel für schlechtes Fragen nach Hilfe bei einem Fehler...

😃

Alchemy

Erstellt vor 10 Jahren

Hallo zusammen,

hab mich hier lange nicht gemeldet, aber jetzt ein Problem, dass ich logisch nicht erklären kann:

Der Code ist ~4 Jahre alt und benutzt ein Dictionary für ein internes Caching.


private static Dictionary<int, Tuple<DateTime, object>> myDict = new ..

void foo(key int)
{
  if (myDict .ContainsKey(key))
  {
    var result = myDict[key];
    if ((DateTime.Now - result.Item1) > TimeSpan.FromMinutes(5)) //5 Minutes Cache
      {
        myDict.Remove(key);
      }
      else
      {
        return result.Item2;
      }
    }
  [..] load from DB

  if (myDict .ContainsKey(key))
    myDict[key] = new Tuple<DateTime,object>(DateTime.Now, data);
  else
     myDict.Add(key, new Tuple<DateTime, object>(DateTime.Now, data));
  return data;
}


Code ist gekürzt und anonymisiert.

Das ganze ist nicht durch ein lock geschützt, noch wird z.B. ein ConcurrentDictionary verwendet. Wie gesagt, alter, funktionierender Code.

Meine Frage ist also - außer dass das jetzt etwas korrigiert wird - was sorgt dafür, dass das ganze nicht nur manchmal wegen einem threading Problem (in der Routine) auf die Schnauze fällt, sondern mehrere Stunden eine IndexOutOfRangeException beim Insert (Add) in das Dictionary erzeugt?

Threading-Problem hat das ganze sicher. Ein static überlebt keinen Prozesswechsel (AppPool Recycle)

Ich steh gerade auf dem Schlauch...

😃

Xynratron

Erstellt vor 10 Jahren

Hi zusammen,

Wie wäre es mit:

* Stage und Prod haben dieselben Bindings, aber terminiert auf unterschiedliche IP'S
* Stage und Prod benutzen dieselbe Session & DB
* IP's im LB sind je nach Anwendung getrennt
* Im LB von Prod auf Stage (rein Server basierend, auf IP) umschalten lassen (und das andere zurück)
* Prod und Stage "logisch" tauschen

Das hängt ein wenig von eurem LB ab. Am einfachsten wäre es wohl, wenn man Regeln für die URL zu den physischen Servern angeben könnte oder wenn ihr mehrere öffentliche IP's habt.

stage.example.com -> 141.1.1.1 -> Real 192.168.1.1
live.example.com -> 141.1.1.2 -> Real 192.168.1.2, Real 192.168.1.3

Dann im LB die Real-Server tauschen (lassen). Die User merken nix, außer die Session wird gekillt.

Ansonsten ist ein Ausfall für die User wohl nicht unbemerkt. Sanft kann man das noch mit einem ändern des DNS auf ne andere LB-IP erledigen, dann wandert die Last je nach TTL.

Macht ihr den Umstieg programmatisch über System.Web.Administration oder so? (die 2,3 Sekunden deuten darauf hin)

Ich hab den Thread jetzt nicht ganz nachvollzogen, da ich mit Farmbetrieb weniger Erfahrungen habe, wir regeln alles über LB.

😃

Xynratron

Erstellt vor 13 Jahren

Hiho,

hast du noch ein Backup? DBCC war immer mein Freund in Notfällen. Ehrlicherweise hab ich noch nie eine DB wirklich verloren - es war alles immer irgendwo vorhanden und wiederherstellbar.

Wenn deine DB tatsächlich "eine unerwartet kleine größe" hat, dann sollte man noch nach dem Transaktionslog schauen. Auch sein anzumerken: wenn man in einer 1000Mb Datenbank die Tabellen alle löscht, so hat die DB immernoch 1000 Mb. Der SQL Server gibt nur auf expliziten Befehl (Autoshrink, dbcc) den Speicher an das Betriebssystem zurück. Die änderungen sind wenn dann auch noch im Log, außer es wurde ein komplettes Backup gemacht oder das Log war ausgeschalten (Log = simple).

😃

Xynratron

Erstellt vor 13 Jahren

Hi Ralf,

Hi!
..Windowsstart (also z.b. eine Verknüpfung im Autostartordner) ... dabei scheint der SQLServer-Dienst etwas zu spät verfügbar zu sein, so dass meine Anwendung denk es sein keine Verbindung zum Server möglich.

scheint ja beides auf dem selben Rechner zu liegen. Windows versucht seit geraumer Zeit schneller beim Start zu werden. Der Effekt ist allerdings, dass Windows "schnell" startet, aber die Dienste (mssqlserver) erst später hochfahren. Es sieht schnell aus, aber es läuft noch lange nicht alles. Wenn der Rechner nicht sooo besonders fix ist, dann kann es schon ein paar Minuten dauern. Man merkt das auch gerne daran, dass 2-3 Minuten nach dem Start plötzlich der (endlich gestartete) Virenscanner sich seine Updates holt und nochmal alles ausbremst.

Tips, was man machen kann gabs schon, wollte nur das "Problem" nochmal beleuchten.

😃

Xynratron

Erstellt vor 13 Jahren

Hallo Taladan,

nimm die ganze "schreiben" logik in einen seperaten Thread, dann behält das auch das gewünschte sequenzielle Verhalten.
Im Endeffekt wird nur dein Hauptthread und der 2. Thread vertauscht. Deine Gui im Hauptthread läuft weiter, die Sequenz im Worker bleibt.

😃

Xynratron

Erstellt vor 13 Jahren

huhu,

Je nachdem mit welcher Datenbank und mit welchem Isolationlevel ich arbeite haben die anderen User längere Wartezeiten. Wenn Dirty Reads ausgeschlossen sind müssen die anderen Benutzer warten, bis die Transaktion abgeschlossen sind, bevor sie Daten lesen können. Aus diesem Grunde sind meine Transaktionen immer so kurz wie möglich, maximal so 2 Sekunden.

Handhabe ich genauso. Wenn es wirklich viele Daten sind, dann einzelne Transaktionen a 10.000 Stück (je nach Anwendung variierend) mit einem View zum löschen (der ist tatsächlich performanter).
Zum Teil auch gerne einfach in einer StoredProc mit nem Cursor und Schleife in einzelne Transaktionen zerhackt. Dann müssen die anderen Transaktionen nicht unnötig warten.

Die Tabellen befinden sich in der selben DB, ich verschiebe sie nur zum verarbeiten in eine work-tabelle und danach in eine history, um den Datenbestand beim Verarbeiten so klein wie möglich zu halten da sich in der Work-Tabelle nur die Datensätze zum aktuellen Vorgang befinden.

In diesen Fällen bevorzuge ich Temporäre Tabellen oder - wenn es die performance zulässt - Tabellenvariablen. Das erspart die Aufräumarbeit und man kann das ganze später auch von unterschiedlichen Stellen (Threads) anwerfen, ohne dass die "Worktabelle" von allen belegt wird.

😃

Xynratron

Erstellt vor 14 Jahren

huhu,

vielen dank für den Link, der ist sehr informativ. Allerdings auch schon etwas älter, hat sich da nichts getan?

Naja, Grundlegend muss doch alles beim alten bleiben, oder?

Von ODBC würde ich generell abraten: alt, langsam, existiert nur noch aus Kompatibilitätsgründen.

Dass die Zieldatenbank nicht bekannt ist, ist extrem ärgerlich, denn man muss trotz allem die eigentlichen DB-Statements (Insert, Update etc.) Datenbankspezifisch halten. Hier kommt man also nie um eine Anpassung auf eine bestimmte DB herum.

Dafür gibt es aber OR-Mapper:

Wenn Du Datenbank-unabhängig programmieren willst dann schau Dir die O/R-Mapper an, z.B. Entity Framework.

😃

Xynratron

Erstellt vor 14 Jahren

huhu,

naja, die Libs sind erstmal nicht im CE-Framework vorhanden, also geht es erstmal nicht.

Ein Problem - warum es vermutlich nicht wirklich funktioniert - ist, dass alle diese "kleinen" Geräte Applikationen abschalten, welche "subjektiv" keine Rechenzeit brauchen. Demzufolge ergibt die Implementation eines Services, welcher immer mal wieder Rechenzeit braucht aber keine Foreground Anwendung ist, keinen Sinn. Auch wenn der Server (Service) eine Anfrage bekommt, hat er keine Rechenzeit, Interrupts etc. um darüber überhaut eine Information zu bekommen.

Vielleicht kannst du auf andere Libs ausweichen oder ein Polling des "Servers" einbauen.

😃

Xynratron

Erstellt vor 14 Jahren

huhu,

per WMI kann man die Netzverkverbindungen auslesen, hier sollte auch ein Counter für die Netzwerkgüte dabei sein.

😃

Xynratron

10 von 1.177 Beiträgen