Have You Tried IT ?

Information Technology from scratch

Limit procesów na serwerze współdzielonym

Dodano przez Kategoria: Linux

Na jednym z serwerów współdzielonych ustanowiony jest limit procesów dla każdego konta. Oczywiście o limicie dowiedziałem się dopiero, gdy na serwerze zaczął się pojawiać błąd 500 Internal Server Error.
Akurat na tym serwerze podpiętych było kilka domen firmowych, a na każdej było założonych kilka skrzynek pocztowych. W sumie uzbierało się kilkanaście adresów e-mail, które w jednym czasie były używane przy użyciu oprogramowania Thunderbirda poprzez protokół IMAP.
Cenię sobie IMAP za jego możliwości i np. możliwość równoległej pracy kilku użytkowników na jednej skrzynce e-mail (tak, czasem się to przydaje przy prowadzeniu chociażby niewielkiego sklepu internetowego). Natomiast pewną właściwością protokołu IMAP jest to, że program pocztowy dla każdego odczytania folderu otwiera oddzielne połączenie i by najmniej nie zamyka go! Przy kilku osobach korzystających z kilku skrzynek może się uzbierać całkiem niezła ilość oddzielnych otwartych połączeń, a każde takie połączenie to oddzielny proces na serwerze. Po wyczerpaniu dostępnego limitu procesów dochodzić może do takiej sytuacji, że nie można się dostać na stronę przez www.

Rozwiązaniem będzie zamykanie starych procesów IMAP po stronie serwera. Postaram się przedstawić ostateczne rozwiązanie wraz z całym tokiem.

Lista procesów:

user@serv63:~$ ps auxw
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user    11760  0.0  0.0   8408  1504 ?        S    07:22   0:00 sshd: user@pts/0
user    11764  0.0  0.0   6756  3732 pts/0    SNs  07:22   0:00 -bash
user    15117  0.0  0.0  15428  3796 ?        S    07:29   0:00 imap [email321@domenajeden.com.pl 83.11.11.11]
user    15118  0.0  0.0   5100  2076 ?        S    07:29   0:00 imap [email543@domenadwa.pl 83.11.11.11]
user    15119  0.0  0.0   7240  2524 ?        S    07:29   0:00 imap [email654@domenatrzy.pl 83.11.11.11]
user    21214  0.0  0.0   4212  1740 ?        S    07:42   0:00 imap [email098@domena4.com.pl 83.11.11.11]
user    25117  0.0  0.0   3888  1472 ?        S    07:52   0:00 imap [email098@domena4.com.pl 83.11.11.11]
user    29872  0.0  0.0   4036   988 pts/0    RN+  08:04   0:00 ps auxw

W tym przykładzie (po wywołaniu komendy ps auxw) akurat jest niedużo procesów, ale natomiast widać, że jest kilka procesów, które mają więcej niż 30 minut (a mogą mieć znaaaaacznie więcej). Należałoby stworzyć skrypt uruchamiany cyklicznie z crona, który zamykałby procesy o wieku dłuższym niż 30 minut. Nie będzie to miało jakiegokolwiek wpływu na pracę zwykłych użytkowników, program pocztowy po prostu nawiąże nowe połączenie przy kolejnej czynności.

Wylistowanie id, wieku i nazwy aktualnych procesów:

user@serv63:~$ ps -eo pid,etime,comm
  PID     ELAPSED COMMAND
 7983       21:18 imap
 7996       21:17 imap
 7997       21:17 imap
 8003       21:15 imap
 8353       20:20 imap
 8557       19:54 imap
 8563       19:54 imap
 8564       19:54 imap
 8565       19:54 imap
10484       14:36 imap
10485       14:36 imap
10486       14:36 imap
12700       08:36 imap
13256       06:53 imap
13257       06:53 imap
13258       06:53 imap
13259       06:53 imap
13261       06:53 imap
13262       06:53 imap
14787       02:14 imap
14800       02:12 imap
15193       01:19 imap
15194       01:19 imap
15715       00:00 ps
29997       52:12 sshd
29998       52:12 bash

Parametry:

  • e – wypisuje wszystkie procesy
  • o – format podawanych danych
    pid – identyfikator procesu,
    etime – czas od kiedy został uruchomiony, w formacie [[dd-]hh:]mm:ss,
    comm – nazwa polecenia

Następnie należałoby wybrać tylko procesy imap i tylko starsze niż 30 minut:

ps -eo pid,etime,comm | awk '((length($2) > 5) || $2~/^[3-5]/) && $3~/imap/ { print $1 }' | xargs kill -15

Po znaku | informacje dalej przekazywane są do programu awk, który dokonuje operacji wyszukiwania na ciągach znaków, a następnie proces jest zamykany programem kill.

  • zmienne $1, $2, $3 – to zmienne pobrane z poprzedniego programu (id, wiek, nazwa procesu)
  • (length($2) > 5) || $2~/^[3-5]/) – pierwszy warunek sprawdza, czy aby czas nie ma więcej znaków niż 5 co oznaczałoby, że jest to ponad godzina (hh:mm:ss), drugi warunek przy użyciu wyrażenia regularnego sprawdza, czy aby rozpoczyna się od cyfry 3,4 lub 5
  • $3~/imap/ – nazwa procesu musi nazywać się imap
  •  { print $1 } – zwraca pierwszą zmienną, czyli identyfikator procesu
  • xargs kill -15 – powoduje przekazanie zwróconego identyfikatora do programu kill zamykającego proces.
    Parametr -15 powoduje, że zostaje wywołane polecenie zamknięcia procesu i ma możliwość „posprzątania po sobie”, natomiast gdyby użyć -9 to proces od razu i bezapelacyjnie jest zamykany „na tzw. chama”

 

Ten skrypt działa prawidłowo w przypadku, gdy znajdzie jakieś stare procesy do zamknięcia. Natomiast, gdy takowych nie znajdzie, wówczas program kill wyrzuca standardową informację o braku identyfikatora procesu do zamknięcia, a w przypadku umieszczenia tego w zadaniach crona, każdy wynik tekstowy polecenia wysyłany jest na e-mail administratora. Tak więc aby uniknąć niepotrzebnego zaśmiecania skrzynki należy ostatecznie zmodyfikować skrypt:

for pid in $(ps -eo pid,etime,comm | awk '((length($2) > 5) || $2~/^[3-5]/) && $3~/imap/ { print $1 }');
do kill -15 $pid;
done

Na koniec pozostaje tylko umieszczenie go w zadaniach cron:

crontab -e

*/15 7-18 * * 1-5 for pid in $(ps -eo pid,etime,comm | awk '((length($2) > 5) || $2~/^[3-5]/) && $3~/imap/ { print $1 }'); do kill -15 $pid; done

Oznacza to, że skrypt uruchamiać się będzie co 15 minut w godzinach między 7 a 18 od poniedziałku (1) do piątku (5). Ewentualnie całość można sobie zapisać gdzieś do pliku gdzieś, a w cronie wywoływać zawartość pliku.

 

 

Dodaj komentarz

XHTML: Dozwolone znaczniki: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="">