Laden...

Speicherauslastung / Datenzugriffe einer gewachsenen Anwendung optimieren

Erstellt von UndercoverDeveloper vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.654 Views
U
UndercoverDeveloper Themenstarter:in
16 Beiträge seit 2015
vor 6 Jahren
Speicherauslastung / Datenzugriffe einer gewachsenen Anwendung optimieren

Hallo,

ich habe ein Problem was ich gerne mal in die Runde werfen würde.

Ausgangssituation:

Es gibt eine große Software die über Jahre gewachsen ist. Aufgrund fehlender Zeit für Wartungsarbeiten / Optimierungen sind diverse Probleme entstanden. Jetzt soll die Anwendung aber modernisiert werden. Hauptproblem ist aktuell die Datenschicht der Anwendung. Die Anwendung setzt auf einen selbst entwickelten OR - Mapper.

  1. Je nachdem wie viele Berechtigungen man in der Anwendung hat, kann es gut sein das die Anwendung bereits nach Programmstart 500-600MB Arbeitsspeicher verbraucht. Vereinzelt bekommen wir schon OutOfMemory Exceptions da die Datenmenge während der Programmlaufzeit weiter anwächst.

Bei Programmstart werden also eine Menge Daten aus der Datenbank geholt die eventuell zu diesem Zeitpunkt nicht benötigt werden und dann auch nicht mehr gelöscht werden.

  1. Jeder Programmierer der mal an dieser Anwendung gearbeitet hat, musste selber zusehen das er die Daten aus der Datenbank bekommt die er gerade benötigt. Zu Sicherheit wird dann lieber nochmal eine extra Datenbankabfrage gemacht. Das führt jetzt dazu das z.B 5 mal die Datenbank angefragt wird obwohl die Daten vielleicht schon im Arbeitsspeicher liegen.

  2. Die Datenbankabfragen sind über die gesamte Anwendung verstreut. Es gibt zwar eine Klasse, die nennt sich DataAccess. In dieser sind die SQL Statements gebündelt und werden durch Funktionen wie "LocationListGetByOwningPerson", "LocationListGetByNumber", "LocationListGetByblablabla..." nach außen gegeben. Diese Funktionen ruft jeder Entwickler aber an jeder Stelle auf wo er gerade lust dazu hat. In der BusinessLogic, im CodeBehind von Winforms usw.

Lösungansätze:

Für ein besseres Caching lohnt sich sicherlich ein Blick auf System.Runtime.Caching (MemoryCache). Somit kann man Daten die z.B länger als 10 Minuten nicht verwendet wurden aus dem Speicher löschen und verhindert somit ein weiteres ansteigen der Speicherauslastung.

Dann müsste ich im zweiten Schritt verhindern das bei Programmstart nicht so viele Daten ausgelesen werden und die ganzen unnötigen Aufrufe aus der Klasse "DataAccess" irgendwie konsolidieren. Aber ich glaube genau das ist ein Fass ohne Boden. Viele Funktionen verlassen sich darauf das bei Programmstart viele Daten ausgelesen werden. Zu evaluieren welche wirklich benötigt werden ist schwierig. Man ist damals nach dem Motto vorgegangen "Lieber mehr als zu wenig."

Daten die dann bei Programmstart nicht mehr ausgelesen werden, müssen an geeigneter Stelle wieder geholt werden. Außerdem...selbst wann ich mir einmal die Mühe mache und die Datenbankzugriffe konsolidiere und nicht mehr so viele Daten bei Programmstart einlese und erst bei Bedarf hole, ist das alles nicht Nachhaltig. In 2 Jahren sieht die Anwendung wieder so aus.

Ich hätte gerne eine Lösung die an der Basis ansetzt und nachfolgende Programmierer dazu zwingt es richtig zu machen oder im Idealfall das soweit abstrahiert das sie sich nicht darum kümmern müssen.

Frage:

Sicherlich schwierig zu beantworten ohne das ihr den Code und die Awendung genauer kennt. Das würde aber jetzt den Rahmen sprengen. Gibt es irgendwelche allgemeine Best Practices oder Vorgehensmodelle wie man so alte Anwendungen modernisiert? Besonders im Bezug auf die Datenschicht?

Ich bin für jeden Input dankbar.

Danke & LG

16.827 Beiträge seit 2008
vor 6 Jahren

Zu 1): seid ihr euch sicher, dass die OutOfMemory Exception wirklich vom Speicher kommt? Entgegen des Namens gibt es auch andere Auslöser wie zB. zu viel offene Handles.

Gibt es irgendwelche allgemeine Best Practices ohne Vorgehensmodelle wie man so alte Anwendungen modernisiert?

Ich glaube die pauschalste Antwort ist: auf der grünen Wiese migrieren => Harte Refaktorierung.
Das heisst: neues Projekt anlegen und Code im Refaktorierungsstil übernehmen. Mehr oder minder von Grund auf neu entwickeln und Gemeinsamkeiten nutzen.

Das kostet aber Zeit und Geld - und Zeit(!); nutzt man daher i.d.R. eher für insgesamt gegen die Wand gefahrene Anwendungen.
Ein Best Practise kann es hier in meinen Augen für eine Soft Refaktorierung nicht geben. Das muss individuell in den Rahmen der Software passen.
Die Frage ist für mich: kann bei so einer Beschreibung überhaupt eine Soft Refaktorierung infrage kommen....?

H
523 Beiträge seit 2008
vor 6 Jahren

Habt Ihr das Projekt mal mit einem Memoryprofiler unter die Lupe genommen um zu sehen welche Objekte wirklich viel Speicher verbrauchen?

In 2 Jahren sieht die Anwendung wieder so aus.

Gibt's keine Richtlinien und Vorgesetzte die das Einhalten der Richtlinien durchsetzen können?

4.938 Beiträge seit 2008
vor 6 Jahren

Das Hauptproblem eurer Anwendung scheint ja zu sein, daß ihr keine vernünftige, einheitliche Architektur habt, wie in [Artikel] Drei-Schichten-Architektur beschrieben.

Du solltest also ersteinmal dafür sorgen, daß der DataAccess nur noch von den BusinessLogic aus aufgerufen wird (und wenn es ersteinmal nur Wrapper-Methoden sind).
Gerade wenn euer Projekt noch Jahre weiterlaufen soll (und nicht einfach nur noch ein Legacy-Projekt ist). Habt ihr denn keinen Software-Architekten für das Projekt?

So wie Abt schreibt, sehe ich es auch. Je nachdem wie der Rest der Software geschrieben ist, ist es überhaupt ausreichend nur ein Soft-Refaktorierung hier zu machen?

U
UndercoverDeveloper Themenstarter:in
16 Beiträge seit 2015
vor 6 Jahren

Danke für die Antworten. Ich dachte mir schon fast das es nicht einfach ist, es keine allgemeine Lösung / Vorgehensweise gibt und es einfach zu stark von der jeweiligen Software abhängt.

Eine hartes Refactoring könnte durchaus die einzig richtige Lösung sein. Dazu habe ich mich zwar noch nicht überwunden und versuche noch andere Wege zu evaluieren. Im Moment sind das aber alles eher Zwischenlösungen die zwar den Kunden (Geschäftsleitung) erstmal zufrieden stellen aber das Problem nur verschleppen und es kracht sowieso irgendwann.

Zu 1): seid ihr euch sicher, dass die OutOfMemory Exception wirklich vom Speicher kommt? Entgegen des Namens gibt es auch andere Auslöser wie zB. zu viel offene Handles.

Ja da sind wir sicher. Fehler wegen zu vieler Handles kriegen wir übrigens auch aber das ist ein anderes Thema.

Habt Ihr das Projekt mal mit einem Memoryprofiler unter die Lupe genommen um zu sehen welche Objekte wirklich viel Speicher verbrauchen?

In 2 Jahren sieht die Anwendung wieder so aus.

Gibt's keine Richtlinien und Vorgesetzte die das Einhalten der Richtlinien durchsetzen können?

Das mit dem Memoryprofiler habe ich gemacht. Das sind größtenteils einfach die Datenbank - Rows die in das Programm geladen werden. Teilweise werden plump ganze Tabellen heruntergeladen. Dann hat man gleich nach nach Programmstart mehrere hunderttausende Objekte im Arbeitsspeicher die dann eben auch mal 500MB Platz benötigen. Sicherlich gibt es Tabellen die mehr und welche die weniger Platz benötigen. Wenn ich anfange aufzuräumen würde ich das entsprechend priorisieren.

Schlimmer wirds noch wenn während der Laufzeit Bilder aus der Datenbank runtergeladen werden (eine wichtige Aufgabe der Software ist das Arbeiten mit Bildern). Durch die hohe Grundauslastung an Arbeitsspeicher und fehlendes richtiges Caching (Speicher sollte auch wieder freigegeben werden) kommen wir irgendwann in einen kritischen Bereich.

Richtlinien in diesem Sinne gibt es nicht. Es gibt allgemeine Coding - Guildlines die sich aber mehr auf Naming und Formatierung beziehen. Es gibt aber keine Richtlinien bezogen auf die Software -
Architektur die dazu zwingen das sowas nicht passiert. Geschweigen von Code Reviews um die Einhaltung der Richtlinien zu prüfen.

Das Hauptproblem eurer Anwendung scheint ja zu sein, daß ihr keine vernünftige, einheitliche Architektur habt, wie in
>
beschrieben.

Du solltest also ersteinmal dafür sorgen, daß der DataAccess nur noch von den BusinessLogic aus aufgerufen wird (und wenn es ersteinmal nur Wrapper-Methoden sind).
Gerade wenn euer Projekt noch Jahre weiterlaufen soll (und nicht einfach nur noch ein Legacy-Projekt ist). Habt ihr denn keinen Software-Architekten für das Projekt?

So wie Abt schreibt, sehe ich es auch. Je nachdem wie der Rest der Software geschrieben ist, ist es überhaupt ausreichend nur ein Soft-Refaktorierung hier zu machen?

Nein, wir haben keinen Software-Architekten. Wir sind alles "normale" C# Entwickler die sich eben um alles kümmern. Das ist halt in vielen Backoffice Abteilungen so...

Eine gewisse Art von Architektur gibt es schon. Also wir öffnen im CodeBehind einer Form keine Datenbank - Connection und sowas. Es gibt die Forms, darunter gibt es die BusinessLogic.cs (ja sehr riesige Datei) und darunter die Klassen DataStore (Abbild der Tabellen) und DataAccess (Zugriff auf die Tabellen). Nur ganz grob erklärt...

Trotzdem befindet sich im CodeBehind viel Logik - Code der da nicht hingehört und unsere 3 -Schichten Architektur (vom Grundgedanken ist es ja eine) lässt sich sehr leicht aufweichen und ist sehr aufgeweicht. Teilweise werden die DataAccess - Funktionen (z.B AppointmentGetById) durch die BusinessLogic.cs einfach 1:1 durchgeschleift und dann im CodeBehind aufgerufen. Sicherlich sollte genau das nicht passieren und nur die BusinessLogic.cs Zugriff auf die direkte Datenbankkommunikation haben. Konzepte wie MVC, MVP, MVVM wären bestimmt besser aber das käme einer Neuentwicklung gleich.

Ich denke weiter darüber nach.... . Wenn ihr Input habt dann immer her damit.

Danke & LG

16.827 Beiträge seit 2008
vor 6 Jahren

Ohne einen Verantwortlichen, in der Regel ein Architekt, der auch mal ein "Nein, so nicht!" durchzieht, wird auch eine Neuentwicklung in diesem Bereich sicherlich wieder versumpfen.

T
2.222 Beiträge seit 2008
vor 6 Jahren

Klingt für mich sehr nach mangelhaften Kentnissen im Bereich Architektur bei euch "normalen" C# Entwicklern.
Schon bei der BusinessLogics.cs würden sich mir die Nägel aufrollen.
Ich vermute mal ganz stark, dass eure Architektur keine saubere Trennung hat.
Drei Schichten kann man nur haben, wenn ihr auch drei DLLs habt, die dann ihre jeweilige Schicht wiedergeben.
Nur per Code/Ordner diese Klassen zu trennen, ist keine saubere Trennung, da alle Schichten immer noch vermischt werden können.

Entsprechend würde ich auch zum Refactoring greifen.
Warum ihr die Daten einladet, ist dann auch noch eine offene Frage.
Wenn ihr mit der Datenbank richtig umgehen könnt, ist sowas nicht nötig.
Lasst hier die DB für euch arbeiten, dazu ist diese auch da.

Ohne den Code gesehen zu haben, würde ich aktuell kein gutes Blatt daran lassen.
Ich würde hier erst einmal eine saubere Grund Architektur planen und dann per Refactoring schauen, was man mitnehmen kann.
Den Rest solltest ihr später, wenn die neue Version fertig ist, verwerfen.

Hier müsst ihr aber umbedingt lernen diszipiliert zu arbeiten.
Wenn in 2 Jahren der Code wieder vermurkst ist, macht ihr es falsch.
Hier solltet ihr also vorangig auch an eurer Disziplin arbeiten um euren Code sauber zu halten und die Architektur auch beibehalten.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

2.079 Beiträge seit 2012
vor 6 Jahren

Kleiner Tipp, was da auch helfen kann, sowas in Zukunft zu vermeiden: Code-Reviews
Irgendwer baut was und irgendjemand anderes (oder Mehrere) schaut sich das Änderungen dann an.
Beim Review sollte dann Wert darauf gelegt werden, die Guidelines einzuhalten, mögliche Fehlerquellen zu entlarven oder eben Design-Fehler früh anzukreiden.

Das setzt natürlich voraus, dass die Arbeit in kleinere überschaubare Aufgaben aufgeteilt sind.
Wenn einer allein die halbe Anwendung baut, dann macht das keinen Sinn.

So habt ihr zumindest den Vorteil, dass min. Einer die Arbeit durch winken muss.
Der Kollege betrachtet die Änderungen im Idealfall auch nicht aus Problem-Sicht, sondern stellt sich die Frage, ob das so "gut" ist, oder z.B. "Komme ich damit auch in zwei Jahren noch klar"?
Irgendwelche Schmutz-Lösungen dürften da recht schnell auffallen und werden hoffentlich abgeblockt.

Ein weiterer Vorteil:
Die Kollegen kommen untereinander in die Diskussion, speziell über die Frage nach "sauberem" Code.
Da gibt's vermutlich unterschiedliche Ansichten und das führt vielleicht früher oder später dazu, dass jemand für entsprechende Lektüre sorgt oder sich erfahrenen Rat einholt - oder selber liefert.

Wie man das managed, bleibt jedem selbst überlassen.
Ich kenne das z.B. so, dass auf einem Development-Branch und nach (einem angepassten) SCRUM gearbeitet wird.
Erst wenn alle Tasks einer UserStory abgearbeitet wurden und das Review überlebt haben oder entsprechend der Kritik angepasst wurden, erst dann, werden alle Änderungen vom Development-Branch in den versionsspezifischen Branch gemerged.
Aus diesem versionsspezifisch Branch wird dann z.B. das Setup gebaut.

Eine sehr viel einfachere Variante wäre beim TFS, wenn die eigentlichen Arbeiten als Shelveset gespeichert und so dem Kollegen gegeben werden, der das Review macht.

U
UndercoverDeveloper Themenstarter:in
16 Beiträge seit 2015
vor 6 Jahren

Klingt für mich sehr nach mangelhaften Kentnissen im Bereich Architektur bei euch "normalen" C# Entwicklern.

Ja, alles richtig was du sagst. Bis auf die Unterteilung der Schichten in mehrere DLLs. Auch das haben wir gemacht, aber das ändert nichts daran das alle 3 Schichten immer noch vermischt werden können. Vollkommen richtig das es hier ein besseres Konzept nötig ist,dass dem Entwickler die Trennung der Schichten deutlicher macht und eine Vermischung nicht mehr so leicht oder sogar "aus Versehen" geschieht.

Off-Topic:

Der Rest ist auch richtig aber das geht jetzt weit in Richtung Firmenpolitik und wieso und weshalb es dazu gekommen ist. Bei uns ist die Abteilung so strukturiert: Entwickler -> Geschäftsleitung (Kein IT - Leiter!). Jeder Entwickler arbeitet an seinen eigenen Projekten. Kontrollinstanzen gibt es nicht. Anforderung geht direkt an Entwickler -> Von Konzeption bis Roll-Out ist das dann größtenteils eine One-Man-Show.

Zielvereinbarungen sehen wie folgt aus: Ich will das in Q2 2018 haben! -> Schau zu das es dann fertig ist. Zu diesem Zeitpunkt wurden noch keine Anforderungen erhoben sodass eine Schätzung möglich ist.

Genauso mit dem aktuellen Projekt -> Das Datum steht wann es fertig sein soll aber ich weiß noch gar nicht was alles benötigt wird. Deswegen muss ich hier jetzt nach einer "intelligenten" (sicherlich die falsche Wortwahl) Lösung suchen. Dadurch entstehen dann eben auf Dauer die Dirty - Lösungen wie diese Software weil für mehr keine Zeit ist.

Wir sehen die Probleme, sind motiviert es richtig zu machen und wollen dazu lernen. Das ist ein strukturelles Problem.

T
2.222 Beiträge seit 2008
vor 6 Jahren

@UndercoverDeveloper
Wenn du deine Schichten in DLLs packst, kannst du diese bei richtiger Referenzierung nicht mischen.
Deine Definitionsschicht hat keine Referenz zu den anderen Schichten.
Deine Datenschicht hat dann nur die Referenz auf die Definitionsschicht.
Deine Anwendungsschicht hat dann die Referenz auf die Definitions- und Datenschicht.
Deine UI hat dann nur die Referenzen auf die Anwendungs- und Definitionsschicht.
Dann kann es keine Vermischung der Schichten geben, da diese Schicht und die UI nur die nötigen Schichten sieht.

Du musst deinen "Kunden" hier klar machen, dass die eine Anforderung brauchst und musst diese mit ihnen erarbeiten.
Zwar können Zeitforderungen gemacht werden und entsprechend die Prioritäten bei euch gesetzt werden, aber du musst klar sagen, dass du erst wissen musst was gemacht werden soll.
Es bringt nichts, wenn jemand eine Zeitforderung hat, aber es realistisch nicht machbar ist.

Die optimale Umsetzung ist nur möglich, wenn ihr auch wisst was gefodert ist.
Und das muss in erster Regel, der wissen der etwas von euch fordert.
Ohne grundlegende Anforderungen könnt ihr nie saubere Lösungen umsetzen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

U
UndercoverDeveloper Themenstarter:in
16 Beiträge seit 2015
vor 6 Jahren

@UndercoverDeveloper
Wenn du deine Schichten in DLLs packst, kannst du diese bei richtiger Referenzierung nicht mischen.

Ja so sollte es sein mit den DLLs. Dann hast du recht das unsere noch etwas falsch aufgeteilt sind.

Bezüglich des Projektmanagements ist das natürlich richtig aber wir treffen hier auf eine 100%ige Blockade - Haltung der Geschäftsleitung. Diese möchten wissen wann ein Projekt welches im Q3 (als Beispiel) überhaupt mal in Angriff genommen wird fertig ist. Also in Q3 würden wir überhaupt erstmal einen Gedanken daran verschwenden. Trotzdem will man eine Schätzung in Manntagen haben und anhand dieser Schätzung werden innerlich schon die nächsten Projekte geplant (weil der Entwickler hat dann ja wieder Zeit). Natürlich sagen wir das sowas nicht geht aber das findet keine Ohren. Teufelskreis...

Ich glaube wir schweifen ab. Ich denke die Lösung für das Eingangs genannte Problem hat sich herauskristallisiert. Hartes Refactoring mit Regeln damit es nicht wieder passiert oder dirty optimieren wo es geht um den "Kunden" erstmal zufrieden zu stellen.

Kleiner Tipp, was da auch helfen kann, sowas in Zukunft zu vermeiden: Code-Reviews

Danke für den Input. Das stimmt vollkommen. Code Reviews haben nicht nur den Vorteil Fehler zu finden sondern dadurch findet auch Wissenstransfer statt und man tauscht sich mehr aus. Das sorgt vor allem langfristig für noch mehr Vorteile.

2.079 Beiträge seit 2012
vor 6 Jahren

Von Konzeption bis Roll-Out ist das dann größtenteils eine One-Man-Show.

Das spricht ja eigentlich schon gegen Code-Reviews.
Klar kann man das immer noch machen, allerdings müsste der Kollege dann mehr oder weniger die Arbeit begleiten, um überhaupt eine Chance zu haben, einen Überblick zu finden.
Allerdings ist er dann nicht mehr der Betrachter "von außen", was die Vorteile mMn. stark schmälert.

Eigentlich sollte man große Projekte eher im Team angehen.
Das zwingt früher oder später zu gewissen Einigungen im Sinne der Architektur, wenn alle Beteiligten entsprechend strukturiert arbeiten.
Wenn das ganze Projekt aber als "One-Man-Show" gestartet ist und dann in späteren "One-Man-Shows" immer wieder erweitert wurde, dann ist es kein Wunder, dass sich da Langzeitfehler einschleichen.

Vielleicht könntest Du da ein Team-Projekt vorschlagen oder sogar durchsetzen?
Sowas hat viele Vorteile, besonders im Bezug auf die Zeit.
Ein ganzes Team ist - wenn man es richtig angeht - immer schneller als einer allein.

Wenn das Projekt wirklich so schlimm ist, wie Du sagst, würde ich auch die Harte Refaktorierung als einzige Option sehen.
Das kostet bloß sehr viel mehr Zeit als einfaches Aufräumen, demnach auch mehr Geld, was ja selten gut ankommt.
Dafür lässt es aber hoffen, dass es auch noch nach Jahren noch gut läuft.
Wenn Du die Vor- und Nachteile klug ausarbeitest, kannst Du eine harte Refaktorierung vielleicht verkaufen, bekommst entsprechend viel Zeit und vielleicht sogar die Sache mit dem Team bewilligt.

Und - um mal ein wenig zu träumen - vielleicht klappt das Projekt im Team dann so gut, dass die Leute, die das sagen haben, das auch bemerken und das Konzept und dass es von dir vorgeschlagen wurde, im Hinterkopf behalten 😉
Wenns nicht gut läuft, bist dann aber leider auch Du derjenige, der es ausbaden darf.

16.827 Beiträge seit 2008
vor 6 Jahren

UndercoverDeveloper bitte beachte (endlich) [Hinweis] Wie poste ich richtig? und unterlass die Full Quotes.
Wir wollen nicht dauernd Deine Beiträge editieren müssen.....

H
523 Beiträge seit 2008
vor 6 Jahren

Zielvereinbarungen sehen wie folgt aus: Ich will das in Q2 2018 haben! -> Schau zu das es dann fertig ist. Zu diesem Zeitpunkt wurden noch keine Anforderungen erhoben sodass eine Schätzung möglich ist.

Dieses Verhalten spricht meiner Meinung nach nicht gerade für die Kompetenz der Geschäftsleitung. Leider verstehen die meisten Nicht-Softwareentwickler auch nicht, dass Softwareentwicklung keine Fließbandarbeit ist.

Genauso mit dem aktuellen Projekt -> Das Datum steht wann es fertig sein soll aber ich weiß noch gar nicht was alles benötigt wird.

Wie reagiert die GL denn, wenn Ihr darauf besteht erstmal die genauen Anforderungen zu bekommen?

16.827 Beiträge seit 2008
vor 6 Jahren

Das scheinen ja vor allem organisatorische Probleme in eurer Firma zu sein, in dessen Umfeld es wohl nur schwer ist, qualitative Software zu schreiben.