Schrift
[thread]4589[/thread]

Linux Monitor: Client-Server Rollen (Seite 2)



<< |< 1 2 >| >> 16 Einträge, 2 Seiten
bloonix
 2006-05-30 02:57
#38804 #38804
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Mir liegt eine Lösung für das Threading sehr am Herzen, wenn also noch
nicht so ganz klar ist, was ich nun möchte, dann erkläre ich es gerne
nochmal.

Also ich habe einen Server, der pro Sekunde ca. 100 Requests verarbeiten
muss. Ein einzelner Prozess ist leider zu wenig um alle Requests
abzuarbeiten, deshalb suche ich nach einer Möglichkeit, die Arbeit auf
mehrere Prozesse aufzuteilen, so wie es zum Beispiel mit einem Webserver
funktioniert, wo mehrere httpd Prozesse laufen. Der httpd Prozess, der
am wenigsten zu tun hat, verarbeitet den nächsten Request. Ein httpd
Prozess fungiert dabei als Dispatcher, der eingehende Requests an seine
untergebenen Verteilt.

Ich hoffe ihr (und du ptk) könnt mir helfen.

Viele Grüße,
opi\n\n

<!--EDIT|opi|1148943926-->
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.
bloonix
 2006-05-30 03:01
#38805 #38805
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,30.05.2006, 00:56]Drei Sekunden mit voller CPU-Last?[/quote]
Natürlich nicht. Die Auswertung der Daten, die Generierung von eMails,
das Prüfen verschiedener anderer Dinge, das Schreiben in die Datenbank
in verschiedene Tabellen... das alles benötigt ca. 2-3 Sekunden.

Die Auslastung durch einen Prozess liegt in der ganzen Zeit bei ca. 20%.

Eine Drei-Prozessor-Maschine mit 2 GHZ Prozessoren macht das locker.\n\n

<!--EDIT|opi|1148943883-->
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.
betterworld
 2006-05-30 03:26
#38806 #38806
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
Ueber Unix-Domain-Sockets kannst Du Dateideskriptoren (also z. B. Sockets fuer angenommene Verbindungen) an andere Prozesse schicken. Siehe "SCM_RIGHTS" in unix(7). Keine Ahnung, wie das in Perl geht. Sag's mir, falls Du es rausfindest ;-)
ptk
 2006-05-30 10:31
#38807 #38807
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
[quote=opi,30.05.2006, 01:01][quote=ptk,30.05.2006, 00:56]Drei Sekunden mit voller CPU-Last?[/quote]
Natürlich nicht. Die Auswertung der Daten, die Generierung von eMails,
das Prüfen verschiedener anderer Dinge, das Schreiben in die Datenbank
in verschiedene Tabellen... das alles benötigt ca. 2-3 Sekunden.

Die Auslastung durch einen Prozess liegt in der ganzen Zeit bei ca. 20%.

Eine Drei-Prozessor-Maschine mit 2 GHZ Prozessoren macht das locker.[/quote]
Rein rechnerisch kommst du bei 2 Sekunden pro Request, 20% Last und 100 Requests/Sekunde mit drei Prozessoren (es gibt 3-Prozessor-Maschinen?) aber nicht aus. Hoffen wir also, dass die Last wesentlich geringer ist und das meiste tatsächlich nur "Wartezeit" ist.

Da du httpd ansprichst: spricht etwas dagegen, einen Apache mit mod_perl zu verwenden?
bloonix
 2006-05-30 14:40
#38808 #38808
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,30.05.2006, 08:31]Rein rechnerisch kommst du bei 2 Sekunden pro Request, 20% Last und 100 Requests/Sekunde mit drei Prozessoren (es gibt 3-Prozessor-Maschinen?) aber nicht aus. Hoffen wir also, dass die Last wesentlich geringer ist und das meiste tatsächlich nur "Wartezeit" ist.[/quote]

Ein Dell-Blade mit 3 Prozessoren schimpfe ich als 3-Prozessor-Maschine.
Desweiteren spreche ich von einer Gesamtlast von ca. 20% über 2-3
Sekunden, aber ich wollte jetzt nicht die Leistung des Servers behandeln,
sondern eher, wie ich die Requests auf x-beliebige weitere Prozesse
weiterleiten kann =(

[quote=ptk,30.05.2006, 08:31]Da du httpd ansprichst: spricht etwas dagegen, einen Apache mit mod_perl zu verwenden?[/quote]

Ja, weil ich Apache nicht missbrauchen möchte, um ein Threading hinzu-
bekommen und meine Prozesse auch nicht von Apache abhängig machen
möchte. Hast du keine Erfahrung, wie solch ein Threading vonstatten gehen
könnte?
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.
betterworld
 2006-05-30 17:36
#38809 #38809
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
Ich habe mal die oben von mir angesprochene Sache implementiert, um Dateideskriptoren an andere Prozesse zu schicken. Dabei wird unter Linux "sendmsg" gebraucht. In perldoc -f send steht aber leider, dass sendmsg nicht implementiert ist. Daher musste ich zu Inline::C greifen.

Unnoetig zu erwaehnen, dass das Programm wohl nicht auf Windows laeuft. Keine Ahnung, ob es allgemein auf *ix laeuft.

Das Script forkt zwei Kinder. Der Elternprozess lauscht dann auf einem TCP-Port und leitet alle angenommenen Sockets an ein Kind weiter, welches dann mit dem Client kommuniziert.

Man kann es testen, indem man es mit "./dispatcher.pl" startet und dann in mehreren xterms oder Konsolen jeweiels "nc localhost 40001" tippt. Der dritte nc sollte gleich wieder zu Ende sein, weil es eben nur zwei Server-Prozesse gibt.

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/perl
# dispatcher.pl
use strict;
use warnings;
use Inline 'C';
use IO::Socket::INET;
use IO::Socket::UNIX;
use Socket;
use IO::Select;


my $dispatcher_pid = $$;
my $debug_prefix = 'dispatcher';

sub debug ($) {
warn "[$debug_prefix] @_\n";
}

socketpair (my $child_end, my $parent_end, AF_UNIX, SOCK_DGRAM, PF_UNSPEC) or die $!;
bless $_, 'IO::Socket::UNIX' for $child_end, $parent_end;

my $listen = IO::Socket::INET->new(
Listen => 2,
Proto => 'tcp',
LocalPort => 40001,
ReuseAddr => 1,
) or die $!;

# Unschoene Methode, um nach unserem Tod sicherzustellen, dass keine Kinder ueberleben
END {
system('fuser', '-k', $listen->sockport . '/tcp') if defined $listen and $$ == $dispatcher_pid;
}

my @children;
my $available_children=0;

for my $child_id (0..1) {
my $pid = fork;
defined $pid or die $!;
unless ($pid) {
$debug_prefix = "child $child_id";
run_child($child_id);
exit;
}
$children[$child_id] = {
pid => $pid,
id => $child_id,
};
}
debug 'forked all children';

run_dispatcher();
exit;

sub run_dispatcher {
my $sel = IO::Select->new;
$sel->add($parent_end);
$sel->add($listen);
debug 'running dispatcher';
while (my @r = $sel->can_read()) {
INCOMING: for (@r) {
if ($_ == $listen) {
my $accept = $listen->accept;
debug 'incoming connection from ' . $accept->peerhost;
if ($available_children) {
debug "$available_children children are available. Dispatching connection";
my $ret = send_fd(fileno($parent_end), fileno($accept));
debug "send_fd returned $ret";
0 == $ret and --$available_children;
next INCOMING;
}
debug 'no-one available. Shutting down the connection.';
$accept->shutdown(SHUT_RDWR);
} elsif ($_ == $parent_end) {
defined $parent_end->recv(my $dgram, 20, 0) or die $!;
debug "got $dgram";
if ($dgram =~ /^\d+ available$/) {
++$available_children;
}
}
}
}
}

sub run_child {
my ($child_id) = @_;
debug "running child (pid $$)";
for (;;) {
$child_end->send("$child_id available") or die $!;
my $fd = get_fd(fileno($child_end));
die $! if -1 == $fd;
debug "get_fd returned $fd";
open my $client, "+<&$fd" or die $!;
serve_client($client);
}
}


sub serve_client {
my ($client) = @_;
local $_;
while (<$client>) {
chomp;
debug "client sent $_";
syswrite ($client, "I already know everything about $_.\n");
}
}


__END__
__C__
#include <sys/types.h>
#include <sys/socket.h>

int get_fd (int sock) {
struct cmsghdr *cmsg = alloca(CMSG_LEN(sizeof(int)));
struct msghdr hdr = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = NULL,
.msg_iovlen = 0,
.msg_control = cmsg,
.msg_controllen = CMSG_LEN(sizeof(int)),
.msg_flags = 0,
};
int ret;
int *fdptr;

ret = recvmsg (sock, &hdr, 0);
if (0 != ret)
return -1;

cmsg = CMSG_FIRSTHDR(&hdr);
if (NULL == cmsg)
return -1;

fdptr = (int*) CMSG_DATA(cmsg);

return *fdptr;
}

int send_fd (int sock, int fd) {
char buf [CMSG_SPACE(sizeof(fd))];
struct msghdr hdr = {
.msg_control = buf,
.msg_controllen = sizeof(buf),
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
int *fdptr;

cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
fdptr = (int*) CMSG_DATA(cmsg);
*fdptr = fd;

return sendmsg(sock, &hdr, 0);
}

(Edit: Habe einen Bug gefixt, der dafuer sorgen kann, dass der Dispatcher eine falsche Vorstellung davon hat, welche Kinder available sind.)\n\n

<!--EDIT|betterworld|1149006267-->
<< |< 1 2 >| >> 16 Einträge, 2 Seiten



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