Schrift
[thread]4589[/thread]

Linux Monitor: Client-Server Rollen



<< |< 1 2 >| >> 16 Einträge, 2 Seiten
bloonix
 2006-05-25 16:52
#38794 #38794
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Hallo Leute,

ich bastel gerade an einem neuen Linux-Monitor und habe ein paar
grundsätzliche Fragen zu Client-Server Rollen, also wer spielt den Client
und wer den Server. Auch, wieviele Prozesse laufen sollen bzw. wo sie
laufen... auf dem "Server" oder auf dem "Clienten".

Also, folgedes Szenario:

Ich habe ungefähr 1000 Linux-Server, deren Systemlast alle paar Sekunden
abgefragt wird. Auf jedem dieser Server läuft ein Agent, der entweder
als Client oder als Server läuft, also entweder auf Requests wartet oder
selbst Requests startet.

Dann gibt es einen Datenserver, der die ganzen Daten in eine Datenbank
schreibt, welche die Agenten sammeln.

Meine Problem ist nun, wie ich dieses Szenario verwirklichen soll. Wenn die
Agenten, die auf den Linux-Servern laufen, auf Requests warten, dann heißt
das, dass auf dem Datenserver 1000 Prozesse laufen, die sich gegen die
Agenten verbinden und ihre Daten abholen. Wenn die Agenten selbst ihre
Requests gegen den Datenserver starten, dann laufen auf dem Daten-
Server 1-x Prozesse, die alle Requests verarbeiten und die Daten in eine
Datenbank schreiben. Ich scheiter also genau an diesem Punkt. Wie rum?

Bei beiden Wegen gibt es Vor- und Nachteile.

Was würdet ihr mir raten?

Viele Grüße,
opi\n\n

<!--EDIT|opi|1148561686-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
ptk
 2006-05-27 23:23
#38795 #38795
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Du solltest einen Server schreiben, der mit select() statt mit fork() und vielen Prozessen arbeitet.
bloonix
 2006-05-29 18:54
#38796 #38796
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,27.05.2006, 21:23]Du solltest einen Server schreiben, der mit select() statt mit fork() und vielen Prozessen arbeitet.[/quote]
Wie meinst du das genau? Hast du ein Beispiel für mich?

fork() halte ich auch für sehr schlecht, weil pro Sekunde dann sehr viele
Prozesse erzeugt werden können.

Also ich habe mir folgendes überlegt... ich habe einen Listenerprozess,
der auf Port 43600 lauscht. Dieser Listener nennt dem Client einen anderen
Port, auf dem ein Serverprozess läuft und an den er seine Statistiken
abliefern kann. Der Listenerprozess durchläuft dabei ein Array mit aktiven
Ports und reicht dabei immer den nächsten Port weiter, auf diese Weise
habe ich eine Lastenverteilung. Es laufen dann 1-x Serverprozesse, nur
mein Problem hierbei ist... wie registriere ich am besten die aktiven
Serverprozesse? Wie stelle ich am besten fest, dass sie aktiv sind?\n\n

<!--EDIT|opi|1148914491-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
Thorium
 2006-05-29 19:05
#38797 #38797
User since
2003-08-04
232 Artikel
BenutzerIn
[Homepage] [default_avatar]
[quote=opi,29.05.2006, 16:54]Wie meinst du das genau? Hast du ein Beispiel für mich?[/quote]
Google: perl select socket

Erster Hit...
War ja ned so schwer, oder?\n\n

<!--EDIT|Thorium|1148915195-->
Per|li|nist der; -en, -en <zu ↑...ist>: a) Anhänger, Vertreter der radikalen Perlinisten die Perl als die einzig wahre Sprache ansehen; b) Mitglied einer perlinistischen Community.
bloonix
 2006-05-29 22:01
#38798 #38798
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=Thorium,29.05.2006, 17:05]<a href="http://www.google.de/search?hs=kpi&q=perl+select+s..." target="_blank">Google: perl select socket</a>[/quote]
Meine Frage zielte nicht darauf ab, wie die Verwendung von "select" und
"socket" ausschaut, sondern wie ptk meint, dass ich damit 1000 Requests
zeitnah verarbeiten kann.

Dennoch danke für deinen Tipp.\n\n

<!--EDIT|opi|1148928207-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
ptk
 2006-05-29 23:03
#38799 #38799
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
[quote=opi,29.05.2006, 16:54][quote=ptk,27.05.2006, 21:23]Du solltest einen Server schreiben, der mit select() statt mit fork() und vielen Prozessen arbeitet.[/quote]
Wie meinst du das genau? Hast du ein Beispiel für mich?[/quote]
Leider habe ich kein Perl-Beispiel. Schau mal in den Manpages zu perlipc und IO::Socket nach. Oder vielleicht auch im Sourcecode von squid. Das ist ein Klassiker, was massive Verarbeitung mithilfe von select() angeht.
bloonix
 2006-05-30 01:40
#38800 #38800
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,29.05.2006, 21:03]Das ist ein Klassiker, was massive Verarbeitung mithilfe von select() angeht.[/quote]
Hi ptk,

ich werde die select() Methode für den Listener verwenden, aber ich denke
das das nicht reichen wird. Wie oben schon angesprochen suche ich
nach einer Möglichkeit, die eingehenden Requests weiterleiten zu können,
damit ich eine Lastenverteilung habe.

Als Lösung habe ich mir folgendes gedacht...
(alles kurze Beispiele, aber sie funktionieren)

Ich habe einen Listener, der auf eingehende Requests wartet. Der Listener
hat eine Liste von offenen Ports, die er aus einer Pipe liest.

[b]listener.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use strict;
use warnings;
use IO::Socket::INET;
use Fcntl;

my $pipe_name = './myFIFO';
my $host      = '127.0.0.1';
my $port      = 43600;
my @open_ports;

my $listener = IO::Socket::INET->new( LocalHost  => $host
                                   , LocalPort  => $port
                                   , Type       => SOCK_STREAM
                                   , Proto      => 'tcp'
                                   , Listen     => 10
                                   , Reuse      => 1
                                   ) or die "can't open socket over port $port";

while (my $client = $listener->accept()) {
  chomp (my $request = <$client>);

  # wenn @open_ports leer ist, werden die naechsten Ports
  # aus der Pipe gelesen...
  unless (@open_ports) {
     die "pipe $pipe_name is not open" unless -e $pipe_name;
     sysopen my $PIPE,$pipe_name,O_RDONLY or die $!;
     @open_ports = <$PIPE>;
     close $PIPE;
  }

  # an den Client wird der naechste freie Port gesendet und das
  # Array gleichermassen verkuertzt
  print $client shift @open_ports;
  close $client;
}

close($listener);


Nun habe ich die Serverprozesse, die ihren Port, auf den sie laufen, in die
Pipe schreiben, sobald sie zur Verfügung stehen.

[b]server.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use strict;
use warnings;
use IO::Socket::INET;
use Fcntl;

sub i_am_free {
  my $pipe = shift;
  my $port = shift;
  unless (-p $pipe) {
     require POSIX;
     POSIX::mkfifo($pipe,0600) or die $!;
  }
  sysopen my $PIPE,$pipe,O_WRONLY or die $!;
  print $PIPE "$port\n";
  close $PIPE;
}

my $pipe_name = './myFIFO';
my $host      = '127.0.0.1';
my $port      = shift @ARGV;
die "Usage: $0 <port>\n" unless $port =~ /^\d+$/ && $port > 0 && $port < 65657;

my $server = IO::Socket::INET->new( LocalHost  => $host
                                 , LocalPort  => $port
                                 , Type       => SOCK_STREAM
                                 , Proto      => 'tcp'
                                 , Listen     => 10
                                 , Reuse      => 1
                                 ) or die "can't open socket over port $host:$port";

i_am_free($pipe_name,$port);

while (my $client = $server->accept()) {
  my $request = <$client>;
  if ($request) {
     # processing the request
  }
  close $client;
  i_am_free($pipe_name,$port);
}

close($server);


Zu guter Letzt habe ich dann noch den Client, der zunächst einen
Request an den Listener schickt und einen Port von diesem erhält. Mit
dem neuen Port verbindet sich dann der Client zu einem Server.

[b]client.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
use strict;
use warnings;
use IO::Socket::INET;

my $addr = '127.0.0.1';
my $port = 43600;
my $data = {};

while (1) {
  my $port_request = IO::Socket::INET->new( PeerAddr => $addr
                                          , PeerPort => $port
                                          , Proto    => 'tcp'
                                          , Type     => SOCK_STREAM
                                          ) or die "can't connect to $addr:$port";

  print $port_request "1\n";
  my $new_port = <$port_request>;
  close $port_request;
  print $new_port; # just a info for tests
  chomp $new_port;

  my $new_client = IO::Socket::INET->new( PeerAddr => $addr
                                        , PeerPort => $new_port
                                        , Proto    => "tcp"
                                        , Type     => SOCK_STREAM
                                        ) or die "can't connect to $addr:$port";

  print $new_client "1\n";
  close $new_client;
  sleep(1);
}


Zusammenfassung:

1. die Server schreiben ihren Port in eine Pipe
2. der Listener liest die Pipe aus
3. der Client startet einen Request an den Listener
4. der Listener sendet den nächsten freien Port
5. der Client startet einen Request zu einem Server

Das Ganze funktioniert bis hierhin, nur habe ich nicht die geringste
Ahnung, ob das so Gang und Gebe ist. Ich kenne mich nicht mit Client-
Server-Verbindungen aus und hoffe mir kann hier jemand noch
weiterhelfen.

Viele Grüße,
opi

Edit:
Wenn jemand Projekte oder Software kennt, wo ich solches Threading
gelebt wird oder Links kennt, wo ich mir sowas anlesen kann, dann bin ich
für alles, was ihr mir postet dankbar... ich bin absolut wissbegierig auf
dieses Thema. =)\n\n

<!--EDIT|opi|1148939690-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
ptk
 2006-05-30 02:22
#38801 #38801
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Das hört sich zu kompliziert an. Wenn du select() richtig verwendest, dann gibt es nur *einen* Server-Prozess, und der "Listener" wird überflüssig.

Übrigens: wäre es eine Alternative, wenn die Clients direkt in einen (MySQL-)Datenbank schreiben würden? MySQL ist bereits multi-threaded und kann mehrere Tausend Verbindungen gleichzeitig halten.
bloonix
 2006-05-30 02:37
#38802 #38802
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,30.05.2006, 00:22]Das hört sich zu kompliziert an. Wenn du select() richtig verwendest, dann gibt es nur *einen* Server-Prozess, und der "Listener" wird überflüssig.[/quote]
also ich habe das mit select() schon ausprobiert. der server braucht ca.
3 sekunden pro request mit der gesamten verarbeitung, wenn dann also
pro sekunde ca. 100 requests reinkommen, dann kann die verwendung von
select() so gut sein wie sie will, der eine serverprozess packt das einfach
nicht. deshalb brauche ich eine möglichkeit, die arbeit auf mehrere
serverprozesse aufzuteilen und wenn es geht, halt ohne fork.

natürlich wäre auch es auch eine möglichkeit, die clients direkt in die
datenbank schreiben zu lassen, aber dafür bräuchte ich sowas wie ein
mysql-net und das ist doch kostenpflichtig, wenn mich nicht alles täuscht.
darüber werde ich mich aber nochmal informieren...

Edit:
es ist nicht kostenpflichtig, also eine absolute erleicherung für mich,
allerdings interessiert mich die lösung trotzdem, wie man das mit listener etc.
machen könnte. es gibt doch software, die das so macht... nur wie?\n\n

<!--EDIT|opi|1148943145-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
ptk
 2006-05-30 02:56
#38803 #38803
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
[quote=opi,30.05.2006, 00:37][quote=ptk,30.05.2006, 00:22]Das hört sich zu kompliziert an. Wenn du select() richtig verwendest, dann gibt es nur *einen* Server-Prozess, und der "Listener" wird überflüssig.[/quote]
also ich habe das mit select() schon ausprobiert. der server braucht ca.
3 sekunden pro request mit der gesamten verarbeitung, wenn dann also
pro sekunde ca. 100 requests reinkommen, dann kann die verwendung von
select() so gut sein wie sie will, der eine serverprozess packt das einfach
nicht. deshalb brauche ich eine möglichkeit, die arbeit auf mehrere
serverprozesse aufzuteilen und wenn es geht, halt ohne fork.
[/quote]Drei Sekunden mit voller CPU-Last? Dann wirst du einen 300-Prozessor-Rechner kaufen müssen. Oder wird doch nur die meiste Zeit auf IO gewartet? Dann ist select() die richtige Wahl.
<< |< 1 2 >| >> 16 Einträge, 2 Seiten



View all threads created 2006-05-25 16:52.