Wie kann ich eine große Datenmenge vorhalten, damit ich seitens Frontend darauf zugreifen kann?

TheJeed

Mitglied
Hallo zusammen,

wie man an der Fragestellung sieht, bin ich J2EE-Newbie. Ich arbeite mich gerade fleißig ein. Allerdings hat sich dabei anhand der Entscheidung meines Chefs eine Frage ergeben. Ich weiß, wie ich auf eine Datenbank zugreifen kann. Der Chef möchte aber nun, dass sozusagen "beim Hochfahren" der Anwendung diese alle Daten in den Heap oder einen off-Heap Cache lädt und diese dann dem Frontend zur Verfügung stellt, um das Bottleneck der Datenbankverbindungen zu umgehen. Wie mache ich das? Die Daten verändern sich nie, darauf muss also bei der Antwort keine Rücksicht genommen werden.

Btw: Deployment soll auf der aktuellsten Glassfish-Open Source Version erfolgen.

Beste Grüße,

David
 
S

Spacerat

Gast
Wenn sich die Daten ohnehin nicht ändern, wieso verwendest du dann eine Datenbank im eigentlichen Sinne (z.B. MySQL)? Es sollte dann doch auch eine DB Marke Eigenbau tun, die die Daten in einem RandomAccessFile (wenn's wirklich viele sind) oder einer Map hält, so dass sich "Queries" nur auf ein "getElement()" oder ähnliches belaufen.
 

freez

Top Contributor
Der Chef möchte aber nun, dass sozusagen "beim Hochfahren" der Anwendung diese alle Daten in den Heap oder einen off-Heap Cache lädt und diese dann dem Frontend zur Verfügung stellt, um das Bottleneck der Datenbankverbindungen zu umgehen.

Wie viele Daten sind das (in Datensätze, MB, GB)?

Ich habe auch schon in einem Projekt statische Informationen aus der Datenbank geladen und dann meinen Managed Beans per DI zur Verfügung gestellt. Hier musste ich nur entscheiden, ob ich dies im Session Scope oder Application Scope vorhalte. Das hängt von deiner Datenmenge ab. Relativ viele Daten (Datensätze so im 3-4stelligen Bereich) habe ich im Application Scope geladen, da es pro Session doch sehr viel Arbeitsspeicher fressen würde. Ne handvoll Datensätze kann man pro Session auch laden. Dies hat wiederrum den Vorteil, dass du schon Änderungen an den Daten vornehmen kannst und bei der nächsten Session die neuen Daten geladen werden. Nur aufpassen, dass es keine Inkosistenzen geben kann mit Sessions mit alten Daten. Im Application Scope musst du die Serveranwendung neu starten um die Änderungen zu übernehmen.

Unabhängig davon, musst du sicherstellen, dass der Server den Arbeitsspeicher dafür hat. Im ApplicationScope [c]1 x Anzahl Datensätze[/c] und im SessionScope sind es [c]Anzahl Sessions x AnzahlDatensätze[/c]

[EDIT]Trotzdem würde ich die Sinnhaftigkeit bedenken. Hast du eine Datenbankabfrage auf statische Daten, die jedes mal sehr lange braucht, dann würde ich diese Daten explizit vorhalten. Hast du allerdings wenige ms pro Zugriff, dann fände ich es fast Quatsch. Unabhängig davon wären Caches, wie sie in einem vorherigen Post angesprochen wurden vielleicht auch eine Alternative, die auch andere Abfragen beschleunigen können.[/EDIT]
 
Zuletzt bearbeitet:

TheJeed

Mitglied
Vielen Dank schonmal für die Antworten. Bei dem Frontend handelt es sich um JSPs. Die Daten, die vorgehalten werden sollen, belaufen sich momentan auf etwa 30.000 Datensätze(Adressdaten), später sollen es bis zu 500.000 werden. Wenn ich den Begriff "Application-Scope" richtig deute, ist es das, was ich möchte. Ich weiß aber nicht, wie ich die Daten so laden und vorhalten kann, das sie direkt nach Start der Webanwendung zur Verfügung stehen. Ich kenne den Lifecycle einer J2EE-Anwendung einfach noch nicht gut genug.

Ich denke auch, dass es für unsere Zwecke völlig ausreichend wäre, eine Map zu verwenden.
 

TheJeed

Mitglied
Aha, ich glaube, ich habe gerade in meinem alten JavaEE 5 - Buch gefunden, wonach ich suche: mit dem 'application' - Objekt kann ich demnach Daten im Application-Scope speichern.
 

Bleiglanz

Gesperrter Benutzer
Möglicherweise ist dein Chef total verwirrt weil das Zusammenspiel zwischer Geliebter, Sekretärin und Ehefrau zwischen Monaco, Gstad und San Tropez seine ganze Aufmerksamkeit erfordert.

'das Bottleneck' der Verbindung zur DB - bei einer Datenbank mit schlappen 500.000 Datensätzen?

WFT??

Datenbanken sind dazu da, dass man via Netz schnell viele SELECTs usw. absetzen kann, meistens löst ein einziger HTTP - Request auch eine oder mehrere Datenbank anfragen aus, die werden rucki-zucki vom DB-Server an den Webtier zurückgeliefert und der Client bekommt seine schöne HTML-Seite zurück.

Gut, wenn es 5 Millionen Client-Zugriffe in der Sekunde sind, dann muss man sich was überlegen, aber dieser Fall liegt wohl kaum vor.

500000 Datensätze in den Application-Scope des Webtiers (Glassfish, JBoss, Tomcat,...) ist völliger Wahnsinn. Wie sollen dann

- nebenläufige INSERTs, UPDATEs
- Transaktionen
- komplexe SQL-Abfragen (JOINs über mehrere Tabellen)
- Datenintegrität

usw. gehandhabt werden? Geht natürlich, keine Frage - aber der Aufwand? Bevor überhaupt klar ist, ob überhaupt irgendwo zwischen hier und den Bermudas ein 'Bottleneck' vorhanden ist?

[EDIT]
Ja, das mit 'ändern sich nie' habe ich gelesen und ignoriert
[/EDIT]
 
Zuletzt bearbeitet:

freez

Top Contributor
Bei 500.000 Datensätze (wer weiß wie viele es in ein paar Jahren sind) und mal angenommen ein Datensatz hätte so ca. 500bytes, landest du bei 240MB RAM, den dein Server nur dafür verballert.

Dazu kommt noch, dass du sicherlich nicht alle Datensätze gleichzeitig in der JSP anzeigst, d.h. du musst dir Algorithmen / Funktionen entwickeln, die dir deine Daten im Speicher schnell genug filtern / suchen. Eine Datenbank kann das bereits sehr gut, ohne dass man was tun muss.

Übrigens: Falls es ein neues Projekt sein sollte: nehmt lieber JSF oder so, statt JSP. JSP ist doch schon sehr veraltete Technologie.

Übrigens: Ich habe damals die Daten im Speicher gehalten, da es nur wenige und fixe Daten sind und ich alle paar 100ms darauf zugreifen musste. Da hat sich der Vorteil mit den Daten im Speicher bemerkbar gemacht, weil eine Abfrage selbst schon 180ms gedauert hatte. In deinem Fall scheint es mir nicht sinnvoll zu sein (siehe auch meinen Vorredner). Ich würde zuerst die Datenbankvariante nehmen und erst wenn es sich als Problem herrausstellt über Caching reden.
 
Zuletzt bearbeitet:

homer65

Top Contributor
Sieht fast so aus, als hätte dein Chef schlechte Erfahrungen mit der Datenbank Performance gemacht.
Trotzdem ist es sinnvoll gerade größere Datenmengen in einer DB vorzuhalten. Alles andere macht meistens keinen Sinn.
Allerdings muß man auch jemanden haben, der sich hauptberuflich mit der DB beschäftigt. Das ist ein Vollzeit Job.
Größere Firmen beschäftigen ganze Abteilungen, die sich nur mit den DB's beschäftigen.
 

fastjack

Top Contributor
Adressen ändern sich also nicht? ... naja. Ich würde die Teile in der DB halten und ein vernünftiges Caching einbauen. Paging für die Anzeigen und fertig.

Beim Cachen vielleicht einen Cache, der ein gewisses HotSet verwalten kann, also Adressen cacht die oft angefragt werden und so.

Ansonsten paß auf, daß Du den Serverstart nicht verzögerst, wenn Du alle Adressen auf einmal lädst, das kann auch schonmal dauern.

Ansonsten denke ich, daß Ihr für Eure Anwendung nicht extra eine Person abstellen müßt, die nur DB macht...

Mach doch einfach mal einen Schnelltest, die DB betanken, Beans schreiben und einen Client Testclient um die Performance zu messen. Dann könnt Ihr auch verschiedene Konstellationen testen, AppServer auf PC1, DB auf PC2, Client auf PC3 (mal durchmixen), unter anderem auch die, bei der die Daten zum AppServerstart geladen werden..

Warum eigentlich DB? Ihr könnt auch Redis (arbeitet im Speicher) nutzen, da hast Du dann eigentlich als Verzögerung den Trip durch Netz zum Redisserver, da die Daten ratz fatz gelesen und geschrieben werden. Und für einen Redis-Server braucht ihr nicht wirklich einen Admin.
 

KSG9|sebastian

Top Contributor
Eventuell einen (distributed) Cache welcher Write-Through auf JPA-Resourcen ermöglicht (Oracle Coherence, evtl. Hazelcast?). Damit würdest du dir das manuelle bauen und verwalten eines Caches ersparen.

Einen funktionierenden OffHead-Cache zu bauen ist auch nicht ganz trivial, da steckt einiges an Logik drinnen, die ich dem Otto-Normal-Entwickler nicht zutrauen würde.
 

TheJeed

Mitglied
Nochmal danke für die rege Beteiligung. Die Datenmenge ändert sich nicht. Wirklich nicht. Und es wird innerhalb der ersten sechs Monate mit einer Steigerung Zugriffsrate von 0,5 bis 30-50 Hits/s gerechnet. Ein Datensatz hat etwa 25 kb Das noch so zu den Rahmendaten.

Ohne die sachlich diskutierenden hier vor den Kopf stoßen zu wollen: Ich möchte nicht wissen, dass ich die Daten in einer DB halten soll, sondern ich möchte wissen, wie ich sie im Speicher halten kann. Ich weiß jede Antwort wirklich zu schätzen, aber eine Antwort auf die eigentliche Problemstellung wäre nützlicher.
 
S

Spacerat

Gast
Ich weiss nicht, um was du dir Sorgen machst. Etwa darum, dass ein vernünftiger DB-Treiber nicht bereits genau das macht, was du erreichen willst? Ein anderes Ding wäre natürlich, wenn weder DB noch DB-Anbindung möglich wären, wenn der Chef sich weigert, eine DB installieren zu lassen. Dann herzlichen Glückwunsch - bei der Datenmenge kämst du wohl kaum um 'ne eigene Implementation mittels RandomAccessFile und FilePointer-Index nicht rum. Ganz banal und mit 2 exemplarischen Comparatoren zum Sortieren des Index (wobei aber die Sort- und Search-Algos noch fehlen):
Java:
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public final class IndexSequenziell {
	public static void main(String[] args) {
		try {
			RandomAccessFile raf = new RandomAccessFile("data.rel", "rw");

			Record r1 = new Record("vorn", "nachn", 111, 22, "red");
			System.out.println("r1 = " + r1);

			Set<Long> indices = new TreeSet<>();

			long pos = raf.getFilePointer(); // Position in Datei für Index sichern

			indices.add(pos);

			Record.write(r1, raf);
			raf.seek(pos + Record.LENGTH); // auf naechsten Eintrag zeigen (padding)

			//...

			raf.seek(pos); // Position aus dem Index
			Record r2 = Record.read(raf);
			System.out.println("r2 = " + r2);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class Record {
	// 3 Strings a 20 Zeichen + 2 + 2 ints
	public static final int LENGTH = 3 * 20 * 4 + 2 + 2 * 4;

	public static final Comparator<Record> NACHNAME_ASC = new Comparator<Record>() {
		@Override
		public int compare(Record o1, Record o2) {
			return o1.nachname.compareToIgnoreCase(o2.nachname);
		}
	};

	public static final Comparator<Record> NACHNAME_DESC = new Comparator<Record>() {
		@Override
		public int compare(Record o1, Record o2) {
			return o2.nachname.compareToIgnoreCase(o1.nachname);
		}
	};

	String vorname;
	String nachname;
	int alter;
	int anzahlFinger;
	String farbe;

	private Record() {
	}

	public Record(String vorname, String nachname, int alter, int anzahlFinger,
			String farbe) {
		if (vorname.length() > 20) {
			throw new IllegalArgumentException("vorname zu lang");
		}
		if (nachname.length() > 20) {
			throw new IllegalArgumentException("nachname zu lang");
		}
		if (farbe.length() > 20) {
			throw new IllegalArgumentException("farbe zu lang");
		}
		this.vorname = vorname;
		this.nachname = nachname;
		this.alter = alter;
		this.anzahlFinger = anzahlFinger;
		this.farbe = farbe;
	}

	static Record read(RandomAccessFile file) throws IOException {
		Record r = new Record();
		synchronized (file) {
			long pos = file.getFilePointer();
			r.vorname = file.readUTF();
			r.nachname = file.readUTF();
			r.alter = file.readInt();
			r.anzahlFinger = file.readInt();
			r.farbe = file.readUTF();
			if (file.getFilePointer() - pos > LENGTH) {
				file.seek(pos);
				throw new IOException("record ungueltig");
			}
			return r;
		}
	}

	static void write(Record r, RandomAccessFile file) throws IOException {
		synchronized (file) {
			long pos = file.getFilePointer();
			file.writeUTF(r.vorname);
			file.writeUTF(r.nachname);
			file.writeInt(r.alter);
			file.writeInt(r.anzahlFinger);
			file.writeUTF(r.farbe);
			if (file.getFilePointer() - pos > LENGTH) {
				file.seek(pos);
				throw new IOException("record zu lang");
			}
		}
	}

	@Override
	public String toString() {
		return "Record{" + "vorname=" + vorname + ", nachname=" + nachname
				+ ", alter=" + alter + ", anzahlFinger=" + anzahlFinger
				+ ", farbe=" + farbe + '}';
	}
}
 

freez

Top Contributor
Ein Datensatz hat etwa 25 kb Das noch so zu den Rahmendaten.

Dir ist schon klar, dass es bei 1/2 Mio Datensätze 12GB RAM benötigt?

Nun, wenn es unbedingt im Speicher sein soll, baust du dir selbst eine InMemory Datenbank, oder du nimmst eine, die es schon gibt (siehe Post vor mir mit Redis ... gibt bestimmt auch andere).

Ich möchte nicht wissen, dass ich die Daten in einer DB halten soll, sondern ich möchte wissen, wie ich sie im Speicher halten kann.

Wenn es unbedingt im Speicher des App Servers sein soll, dann brauchst du im einfachsten Fall nur sowas:
Java:
@ManagedBean(name="myBean")
@ApplicationScoped
public class MyBean {
    private List <Adress> addresses = null;
	
	@PostConstruct
	public void init(){
		addresses = loadAllData();
	}
}

Aber wie gesagt, zum durchsuchen dieser Datenmenge musst du dich selber kümmern. Dabei kann man auch einiges falsch machen, was dann sich darin äußert, dass es entweder falsch funktioniert, oder zu langsam ist.

Woher du die Daten dann lädst, ist dir überlassen. Ich empfehle dir eine Datenbank :D. Scherz beiseite ... ich meine in dem Fall eher eine, die lokal auf dem Server einfach in einem File liegt (Stichwort embedded Datenbank). Ich hatte mal mit db4o gearbeitet. Da schiebst du einfach Objekte in ein File rein und holst sie so auch wieder raus. Vielleicht ist das ne Variante die Daten zu halten um beim Serverstart diese zu laden. Ob die aber mit 12GB Daten umgehen kann?
 

Bleiglanz

Gesperrter Benutzer
Nochmal danke für die rege Beteiligung. Die Datenmenge ändert sich nicht. Wirklich nicht. Und es wird innerhalb der ersten sechs Monate mit einer Steigerung Zugriffsrate von 0,5 bis 30-50 Hits/s gerechnet. Ein Datensatz hat etwa 25 kb Das noch so zu den Rahmendaten.

Ohne die sachlich diskutierenden hier vor den Kopf stoßen zu wollen: Ich möchte nicht wissen, dass ich die Daten in einer DB halten soll, sondern ich möchte wissen, wie ich sie im Speicher halten kann. Ich weiß jede Antwort wirklich zu schätzen, aber eine Antwort auf die eigentliche Problemstellung wäre nützlicher.

Antwort: es ist unmöglich, 500000*25 kB im Hauptspeicher einer Glassfish-Server-Instanz abzulegen und diese Daten 50 mal pro Sekunde abzufragen.

Aber: wenn du nicht willst, dass es unmöglich ist dann verwende Prevayler oder einen anderen Java-In-Memory-Database Schrott, kopiere deine Daten beim Hochfahren da rein und verwalte das im Application-Scope.

Aber: das ist Wahnsinn. Hört sich nach einem typischen Fall von 'mir ist es egal, wenn das explodiert bin ich eh nicht mehr da'-Software-Entwicklungs-Paradigma an.
 
S

Spacerat

Gast
Wenn ich mich nicht verrechnet habe, kann das RandomAccessFile 2^63 Byte also 8PB (Petabyte) verwalten, weil Dateipointer halt longs sind. Das bedeutet, wenn's 'ne selbst gestrickte bzw. 'ne embedded DB sein soll (da wirst du bei der Datenmenge wie gesagt nicht drum rum kommen) muss diese also schon mal mit RandomAccessFile arbeiten. Collections, Streams und NIO-Buffer fallen jedenfalls aus (auf 2^31 Elemente begrenzt) bzw. kommen nur als Pointer-Verzeichnise in frage.
Aber wie Bleiglanz schon sagt: Das ist Wahnsinn... lass' die Festplatte einer solch' grossen Datei nur mal einen einzigen Lesefehler haben... hoffentlich hast'n Backup.
 
Zuletzt bearbeitet von einem Moderator:
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Java mail API - möchte nur eine gewisse Anzahl von Emails in die Liste holen Allgemeines EE 3
B eine vom Admin hochgeladene csv -Datei in der Datatable auch von jedem User sichtbar Allgemeines EE 0
OnDemand Programm starten, wenn eine Aufgabe erledigt Allgemeines EE 1
X Konsolenausgabe einer java klasse in eine jsp umleiten Allgemeines EE 7
R Wie eine stateful session bean erneut "aufgreifen" Allgemeines EE 22
D JSF h:panelgrid - eine reihe mit zusätzlicher spalte Allgemeines EE 6
S Wie am besten eine Authentifzierung einbauen? Allgemeines EE 7
B Problem beim einbinden einer CSS in eine JSP Allgemeines EE 8
slawaweis CMS Unterbau für eine Web 2.0 Anwendung Allgemeines EE 4
M Wie erhällt eine MessageDrivenBean Nachrichten aus einer Queue ? Wer Pollt da gegen die DB? Allgemeines EE 3
MQue include einer jsp in eine andere Allgemeines EE 4
D Wann genau eine Middleware Allgemeines EE 8
2 JSTL Tags für eine Bean? Allgemeines EE 4
S Session in eine andere Anwendung übergeben Allgemeines EE 2
D Frage zum Verlassen eine JSF-Eingabefeldes Allgemeines EE 6
S Struts: zwei JSP's nutzen eine Action Allgemeines EE 5
J Rechnername auf dem eine J2EE läuft Allgemeines EE 10
P Eine Frage zum Thema Applikationsaufbau Allgemeines EE 3
H Eine Datenbank - 1 Datenmodell - 2 Anwendungsumgebungen Allgemeines EE 2
E HTTP-GET// -->Eine URL aufrufen, aber nicht dahin navigie Allgemeines EE 2
H Eine kurze Verständnisfrage zum Tomcat Allgemeines EE 2
W Eine Form an einen fremden Server schicken. Allgemeines EE 3
G WebApp (mit Tomcat) Wie kann meine Klasse eine Datei laden? Allgemeines EE 7
E Eine Art Thread.sleep() in JSTL? Allgemeines EE 4
M wie sieht eine ejb-jar.xml aus ? Allgemeines EE 8
T eine web anwendung bereitstellen ? Allgemeines EE 5
N Einbindung einer Bean in eine JSP (Tomcat-Server 5.5.x) Allgemeines EE 2
G StackTrace in eine TEXTAREA bringen Allgemeines EE 4
W Woraus baut man eine Super-Business-Anwendung? Allgemeines EE 5
B Besondere Ländereinstellungen für eine TomcatApp Allgemeines EE 2
TRunKX Werteübergabe von einer *.jsp in eine *.java ohne struts Allgemeines EE 4
G Application Server! Gibt es eine grundsätzliche Architektur? Allgemeines EE 9
B EJB --- Eine Modeerscheinung? Allgemeines EE 14
X Mit JSP eine Datenbankabfrage durch führen. Allgemeines EE 13
Y Eine neue Seite mit Servlet öfnnen Allgemeines EE 9
A mit JavaMail eine html mail versenden? Allgemeines EE 4
T [EJB3] Große Text- / Binärdateien zurückgeben Allgemeines EE 4

Ähnliche Java Themen

Neue Themen


Oben