Du bist nicht angemeldet.

Werbeanzeige

birdfreeyahoo

Alter Hase

  • »birdfreeyahoo« ist der Autor dieses Themas

Beiträge: 764

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

1

22.01.2019, 22:32

Thread-Modell Server

Hey,

ich habe hier im Moment einen Server vorliegen, auf den erwartet mehrere hundert Clients sich verbinden sollen.
Im Moment ist er so implementiert, dass ein Thread auf neue Verbindungen wartet und für jeden Client ein neuer Thread hinzukommt.
Zusätzlich ist es so, dass für jede Message eine neue Verbindung aufgebaut wird (und dann direkt wieder geschlossen wird). Das möchte ich abschaffen und auf eine konstante Verbindung setzen, da sowieso jede 10 Sekunden eine Nachricht geschickt wird und der Server auch auf seine Initiative Nachrichten schicken können soll.

Ich habe da nicht so viel Erfahrung drin, aber ich denke nicht dass es gesund sein wird später 600 Threads zu haben. Im Moment sind es nur ugf. 200, die aber nicht parallel laufen sondern immer erzeugt und zerstört werden (z.B. auf Programm-Ebene) wenn einer der 200 User was machen will. Sollte ich es vermeiden so viele Threads zu haben? Ich hatte neulich einen Bug dass ein TimerTask der jede 3 Minuten ausgeführt werden sollte (scheduleAtFixedRate) einfach nicht mehr gelaufen ist und der Server neugestartet werden musste. Ich weiß nicht ob das was damit zu tun haben könnte. Bisher läuft das noch relativ gut, d.h. es werden keine Verbindungen oder laufende Threads einfach gedroppt.

Mein alternativer Ansatz wäre, in einem Thread einen Selector laufen zu lassen, der bei einem Event (Accept/Read) einen Thread aus einem ThreadPool disponiert, der den Request verarbeitet und im selben Thread falls nötig eine Response sendet. Ich weiß nicht welche Modelle da gängig sind für solche Client-reichen Server. Die Gefahr die ich da sehe ist, dass ein Bottleneck dadurch entsteht, dass der Pool keine Threads mehr hat. Welche Werte sind da empfohlen als Maximum? Die Operationen in den Threads sind hauptsächlich Datenbankoperationen und Network-Stream-Writes, die dann am besten asynchron erfolgen.

Ich wäre für ein paar Meinungen dazu dankbar.

Tobiking

1x Rätselkönig

  • Private Nachricht senden

2

23.01.2019, 01:28


Ich habe da nicht so viel Erfahrung drin, aber ich denke nicht dass es gesund sein wird später 600 Threads zu haben. Im Moment sind es nur ugf. 200, die aber nicht parallel laufen sondern immer erzeugt und zerstört werden (z.B. auf Programm-Ebene) wenn einer der 200 User was machen will. Sollte ich es vermeiden so viele Threads zu haben?

Mit 600 Threads, die die meiste Zeit schlafen, sollte ein normaler PC kein Problem haben. Ressourcenverschwendung (reservierter Stack und Scheduling) ist es dennoch. Wenn du weiter skalieren möchtest, solltest du von den Thread pro Verbindung weggehen.


Mein alternativer Ansatz wäre, in einem Thread einen Selector laufen zu lassen, der bei einem Event (Accept/Read) einen Thread aus einem ThreadPool disponiert, der den Request verarbeitet und im selben Thread falls nötig eine Response sendet. Ich weiß nicht welche Modelle da gängig sind für solche Client-reichen Server. Die Gefahr die ich da sehe ist, dass ein Bottleneck dadurch entsteht, dass der Pool keine Threads mehr hat. Welche Werte sind da empfohlen als Maximum?

Wenn du von asynchron wieder auf synchron wechselst gewinnst du nicht viel. Aber Datei- und Netzwerkoperationen sind inzwischen zum großen Teil asynchron vorhanden (NIO 2 & Netty). Problematisch sind meist nur die Datenbankzugriffe. Da wird ein Ansatz wie deiner mit einem Connection Pool verwendet. Da der Connection Pool sich aber nur auf die Datenbankverbindungen bezieht, ist die Größe recht beschränkt. Die Datenbank wird durch eine große Anzahl an Verbindungen nicht schneller.


Ich hatte neulich einen Bug dass ein TimerTask der jede 3 Minuten ausgeführt werden sollte (scheduleAtFixedRate) einfach nicht mehr gelaufen ist und der Server neugestartet werden musste. Ich weiß nicht ob das was damit zu tun haben könnte.

Fängst du alle Exceptions in deinem Task? Sollte nämlich eine Exception durchfliegen, wird der Task nicht wieder gescheduled.

birdfreeyahoo

Alter Hase

  • »birdfreeyahoo« ist der Autor dieses Themas

Beiträge: 764

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

3

23.01.2019, 14:08

Wenn du von asynchron wieder auf synchron wechselst gewinnst du nicht viel. Aber Datei- und Netzwerkoperationen sind inzwischen zum großen Teil asynchron vorhanden (NIO 2 & Netty). Problematisch sind meist nur die Datenbankzugriffe. Da wird ein Ansatz wie deiner mit einem Connection Pool verwendet. Da der Connection Pool sich aber nur auf die Datenbankverbindungen bezieht, ist die Größe recht beschränkt. Die Datenbank wird durch eine große Anzahl an Verbindungen nicht schneller.


Was ich mich frage ist, ob ich da am Ende nicht langsamer dran bin. Connection Pool etc. hab ich alles schon teilweise implementiert.
Mein Gedanke ist, dass wenn ich 400 Threads habe und dann plötzlich einer was von der DB will, ist das eine blockierende Operation für den Thread (?) und ein anderer kriegt dann solange mehr Zeit.
Wenn ich nur eine begrenzte Anzahl von Threads habe, und die sind plötzlich alle blockiert, profitiert keiner davon, da die anderen Requests ja noch auf einen Thread warten.


Fängst du alle Exceptions in deinem Task? Sollte nämlich eine Exception durchfliegen, wird der Task nicht wieder gescheduled.


Nur die SQLExceptions, und da sehe ich keine in dem Zeitraum. Da passiert aber auch nichts anderes als die Verbindung und zwei Querys.

Tobiking

1x Rätselkönig

  • Private Nachricht senden

4

23.01.2019, 16:29


Mein Gedanke ist, dass wenn ich 400 Threads habe und dann plötzlich einer was von der DB will, ist das eine blockierende Operation für den Thread (?) und ein anderer kriegt dann solange mehr Zeit.
Wenn ich nur eine begrenzte Anzahl von Threads habe, und die sind plötzlich alle blockiert, profitiert keiner davon, da die anderen Requests ja noch auf einen Thread warten.

Wenn du asynchron arbeitest darfst du nicht blockieren. Das ist kooperatives Multitasking. Wenn eine Operation länger dauert, wird sie nur angestoßen oder eingereiht und dann die Kontrolle abgegeben. Der Task hängt dann zwar an dieser Stelle, der Thread läuft aber weiter und kümmert sich um die anderen Tasks.

Du tauscht damit zwar echte Parallelität gegen Quasi-Parallelität, hast aber nicht den Overhead von Threads und keine Synchronisierungsprobleme. Jede deine Verbindung kann ein Task sein und wenn auf Threads/Connections für die Datenbankabfrage gewartet wird, ist das kein Problem weil andere Tasks währenddessen laufen.

Goldwing Studios

Treue Seele

Beiträge: 332

Wohnort: Heidelberg

Beruf: Softwareentwickler, Vertriebler

  • Private Nachricht senden

5

23.01.2019, 16:38

Das möchte ich abschaffen und auf eine konstante Verbindung setzen, da sowieso jede 10 Sekunden eine Nachricht geschickt wird und der Server auch auf seine Initiative Nachrichten schicken können soll


Dann solltest du mal die Websocket-Architektur ausprobieren, wenn du .NET als Framework verwendest dann schau dir mal SignalR an (Ist ein Wrapper um Websocket mit Fallbacks und einfacher Handhabung mit integriertem JS- und .NET-Client.

birdfreeyahoo

Alter Hase

  • »birdfreeyahoo« ist der Autor dieses Themas

Beiträge: 764

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

6

23.01.2019, 16:56

Handelt sich dabei um einen Java-Server. Asynchrones SQL wäre da also die Lösung, damit der Thread-Pool mit maximaler Effektivität arbeitet?
Ich hatte den Thread-Pool dann mit 8 Threads geplant (4 Kerne * 2 Hyperthreads) um die Architektur komplett ausnutzen. Hätte ich einen Profit von mehr Threads?

Wenn das so funktionieren würde wäre das toll.
Eine letzte Frage dazu habe ich aber noch: Ich hatte geplant die Requests teilweise zu synchronisieren (mit synchronized).
Soweit ich weiß sind einzelne Zeilen thread-sicher zugreifbar in SQL, das bedeutet aber nicht dass mein Datenmodell sicher ist.
Was ist wenn ein Request einen Query und ein davon abhängiges Update macht und zwischen beiden würde sich das Ergebnis des Querys ändern durch einen anderen Zugriff obwohl es das logisch nicht dürfte?
Daher habe ich Objects die für ein bestimmtes logisches Objekt im Business-Modell stehen (welches in der DB verwaltet wird), über die ich synchronisiere, wenn dieses Objekt bearbeitet wird und keiner "dazwischenfunken" darf. (Also sozusagen implementierung einer atomaren Operation aus mehreren Datenbankoperationen).
Wenn jetzt ein Thread auf den Monitor warten muss, weil jemand anders gerade Informationen über den User ändert, gibt er dann die Kontrolle ab? Und reiht er sich automatisch wieder ein, sobald er wieder den Lock bekommen würde? Funktioniert diese Synchronisierung also auch ohne die Threads zu blockieren?

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »birdfreeyahoo« (23.01.2019, 17:37)


BlueCobold

Community-Fossil

Beiträge: 10 880

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

24.01.2019, 06:57

Nein.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Goldwing Studios

Treue Seele

Beiträge: 332

Wohnort: Heidelberg

Beruf: Softwareentwickler, Vertriebler

  • Private Nachricht senden

8

24.01.2019, 09:43

Dann schau mal bei Google unter "java signalr" und du findest folgenden Link:
https://github.com/Atmosphere/atmosphere

Das sollte dir weiterhelfen und den Großteil deines Aufwandes einsparen.

Nox

Supermoderator

Beiträge: 5 265

Beruf: Student

  • Private Nachricht senden

9

26.01.2019, 16:05

Kleiner Nachtrag auf die Gefahr hin, dass ich etwas unrelevantes sage, da ich mich mit JAVA nicht auskenne: Unter C++ hat sich (damals als ich es testete) die Verwendung von select für die Verbindungsverwaltung als am effizientesten herausgestellt. KA ob das auf Java übertragbar ist. Wegen der Geschwindigkeit der DB Zugriffe würde ich mir persönlich weniger sorgen machen, weil die eig dafür optimiert sind viele Anfragen in kurzer Zeit zu bearbeiten. Natürlich ist Parallelisierung auch da möglich, aber meiner Erfahrung nach ist die Zeit da besser in das Optimieren der Abfragen investiert.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

birdfreeyahoo

Alter Hase

  • »birdfreeyahoo« ist der Autor dieses Themas

Beiträge: 764

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

10

26.01.2019, 23:34

Danke für euer Feedback. Ich denke ich weiß jetzt genug um eine Entscheidung zu treffen bzw. das dann umzusetzen. Und Goldwing danke dass du mich auf Websockets hingewiesen hast, mir ist das irgendwie entgangen, das hilft mir weiter.

Werbeanzeige