Содержание

Ключевые слова: Х-терминал, linux, LTSP, Linux Terminal Server Project, терминальный linux-сервер, бездисковая станция, ПК без жесткого диска, использование старых компьютеров, diskless workstation, thin client, asplinux, использование Linux в офисе, X-terminal

Распределение процессорного времени

Вы даже представить себе не можете, как "криво" сделанная программа может свести на нет всю мощь аппаратного обеспечения вашего компьютера. Хотите пример? Откройте в текстовом редакторе из проекта KDE (kedit) любую гипертекстовую страничку, в которой много табличных данных и выполните замену двух символов "TD" на что угодно без учета регистра. Например, я на подобную "замену" в файле размером 47 Кбайт потратил более 5 минут, и это на компьютере с центральным процессором Pentium-4 и тактовой частотой в 2,6 ГГц! Причем, что характерно, все 5 минут загрузка центрального процессора была почти 100%.

На подобные случаи можно не обращать внимание, работая за традиционным персональным компьютером, когда пользователь единолично распоряжается ресурсами своего процессора, но в распределенной Х-терминальной среде дела обстоят значительно сложнее. Даже не смотря на то, что аппаратные возможности Х-терминал сервера, как правило, на высоте, неэффективное программное обеспечение может значительно ухудшить производительность труда пользователей. Особенно печально, что это коснется всех пользователей без исключения. Если более пристально рассмотреть систему управления диспетчеризации процессов в операционной системе Linux, то окажется, что она сделана довольно грамотно. И по умолчанию, она сама прекрасно справится с подавляющим большинством ситуаций повышения нагрузки на сервер, но в случае "повисшей" (зациклившейся) пользовательской задачи она нам мало чем поможет.

Какие меры можно принять для минимизации негативного влияния "прожорливых" к процессорному времени программ? В ручном режиме наблюдения за системой сделать это очень просто, достаточно запустить программу мониторинга системных процессов типа top, и корректировать приоритеты выполнения того или иного процесса. Для достижения подобных целей у системного администратора есть утилита renice.

Например, от команды top вы получили такую информацию по процессам, которые запустил пользователь с именем mikola:

 13:11:40  up 18 days, 33 min,  5 users,  load average: 0,00, 0,13, 0,18
190 processes: 172 sleeping, 18 running, 0 zombie, 0 stopped
CPU states:   0,2% user   0,8% system   0,0% nice   0,0% iowait  98,8% idle
Mem:  1030108k av,  982128k used,   47980k free,       0k shrd,  168508k buff
                    742092k actv,    6552k in_d,   21204k in_c
Swap: 2048248k av,   92916k used, 1955332k free                  401504k cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
 6370 mikola    15   0 63256  54M 20480 R     0,0  5,4   0:19   0 soffice.bin
 5519 mikola    15   0 24308  23M 13540 S     0,0  2,3   0:17   0 galeon-bin
 6843 mikola    15   0 15056  14M 11212 S     0,0  1,4   0:00   0 sim
 5543 mikola    15   0 14960  11M  5332 S     0,0  1,1   0:01   0 evolution-mail
 6858 mikola    15   0  8364 8364  6000 S     0,0  0,8   0:00   0 kdeinit
 5529 mikola    15   0  7804 7804  3224 S     0,0  0,7   0:00   0 evolution
 6853 mikola    15   0  5936 5936  4168 S     0,0  0,5   0:00   0 kdeinit
 8238 mikola    15   0  4588 4588  2320 R     0,0  0,4   0:00   0 xterm

Как видно из примера, все задания пользователя выполняются с приоритетом 15 (nice=0). Для того, чтобы лучше понять методику распределения приоритетов выполнения в операционной системе Linux, следует быть знакомым с параметром nice, который специфичен для каждого процесса в памяти. Значение nice может изменятся от -20 (наивысший приоритет) до 19 (самый низкий приоритет). Отрицательные значения nice доступны только суперпользователю, поэтому с ними следует быть особенно осторожными, впрочем как и со значением 19. Граничные значения приоритетов выполнения с одной стороны приведут к тому, что процесс будет потреблять практически все процессорное время системы (мешая даже демонам), а с другой стороны, процесс у которого nice=19 будет "просыпаться" только в моменты полного бездействия системы, что в Х-терминальной среде бывает очень редко.

Выполнять изменение приоритетов очень просто. Для того, чтобы понизить приоритет процесса с именем soffice.bin вам достаточно использовать такую команду:

# renice +1 6370
6370: old priority 0, new priority 1

Теперь данный процесс будет выполняться с приоритетом меньшим на единицу, чем другие процессы пользователя.

Кроме этого, команда renice позволяет изменять приоритеты выполнения не только отдельных процессов по их идентификационному номеру (PID), но также влиять на все процессы, запущенные определенным пользователем (параметр -u) или принадлежащих пользовательской группе (параметр -g).

Проблема в использовании утилиты renice заключается в том, что она влияет на приоритет выполнения уже запущенных задач. Например, вы как системный администратор понизили приоритет выполнения пользовательского процесса. Если пользователь завершит соответствующую программу и запустит ее снова, то процесс будет выполняться с прежним приоритетом (по умолчанию). С другой стороны, вместо активного наблюдения за поведением системы, у системного администратора должно быть много других занятий, поэтому ручное применение команды renice – это не самый хороший выбор. Неплохо было бы настроить автоматический механизм реагирования на "жадные" к процессорному времени процессы.

Для реализации системы автоматического наблюдения и реагирования за процессорным временем сервера Х-терминалов необходимо сделать ряд предположений. Во-первых, в поле деятельности данного комплекса должны попадать только процессы конечный пользователей (с распределением нагрузки между демонами операционная системы Linux справляется хорошо и без нашей помощи). Во-вторых, объектами управления должны быть процессы, которые на протяжении определенного интервала времени потребляют больше, например, 80% ресурсов центрального процессора сервера. В-третьих, если понижение приоритета выполнения процесса не помогло, то через определенное время (например, 30 минут) выполнение такого процесса принудительно прекращается.

Все исходные данные для построения подобной системы можно получить из системы /proc, а если не хотите разбираться в форматах ее файлов, то можете воспользоваться такими системными утилитами как, например, ps. За шаблон системы управления приоритетами пользовательских задач можно взять следующий сценарий, написанный на языке Perl:

#!/usr/bin/perl -w

use strict;

my $watch_users = 'nata,mikola,ira,ula,sasha,terminator,yana,serg,disp,mitya';
my %top_ps = ();
my $max_cpu_usage = 85; # Граничное значение использование ЦПУ
my $time_sleep = 20; # Время в секундах между измерениями
my $max_to_renice = 3; # К-во минут после, которых процессу понижается приоритет
my $times_to_kill = 15; # К-во минут для завершения процесса

print "Getting user process CPU usage\n";
while(1) {
    # Получаем список уникальных процессов
    my @procs = `ps h --User=$watch_users -o "pid user comm %cpu" --sort %cpu`;
    my %curr_ps = ();
    for (reverse @procs) {
	my ($pid, $user, $command, $cpu) = split;
	if ($cpu > $max_cpu_usage) {
	    $top_ps{$pid}++;
	    $curr_ps{$pid} = $cpu;
	} else { last }
    }
    for (keys %top_ps) {
	if ( !exists($curr_ps{$_}) ) { delete $top_ps{$_} }
	else { print "$_ => $top_ps{$_} ($curr_ps{$_})\n" }
    }
    # Проверка "жадных процессов"
    for (keys %top_ps) {
	if ( $top_ps{$_} == $max_to_renice*(60/$time_sleep) ) {
	    `renice +1 -p $_`;
	    print "PID $_ was reniced\n";
	}
	if ( $top_ps{$_} == $times_to_kill*(60/$time_sleep) ) {
	    `kill $_`;
	    print "PID $_ was send TERM signal\n";
	}
    }
    sleep($time_sleep);
}

Как видно из текста сценария, он получает и анализирует данные от команды ps, которая собирает информацию только о процессах, запущенных от имени реальных пользователей (переменная $watch_users). При достижении установленной границы (переменная $max_cpu_usage) использования ресурсов центрального процессора, процесс пользователя "ставится на учет", и если нагрузка будет сохраняться в течении тех минут, которые отведены в переменной $max_to_renice, то данному процессу приоритет будет понижен на 1. Если же и после этого использование центрального процессора будет в тех же пределах, то через время указанное в переменной $times_to_kill "провинившемуся" процессу будет послан завершающий сигнал TERM.

Конечно, данный сценарий нельзя рассматривать как панацею от работы зависших или неправильно работающих программных продуктов. Если всмотреться в него внимательнее, то очевидными станут потенциальные проблемы его использования. Также вызывает сомнение правильность установки значений времени работы процесса до понижения ему приоритета, и время принудительного завершения процесса, в прочем как и эмпирическая граница максимума процессорного времени. Для адекватного определения значений этих переменных следует исследовать работу конкретной среды Х-терминалов, принимая во внимание аппаратные возможности сервера, используемое программное обеспечение и количество одновременно работающих пользователей (например, чем больше пользователей и мощнее сервер, тем ниже должно быть значение переменной $max_cpu_usage).

В любом случае я предлагаю рассматривать данный сценарий, как отправную точку в деле расширенного управления распределением процессорного времени сервера Х-терминалов. И пускай его возможности очень скромны, зато он вполне способен разрешить целый ряд проблем, особенно в той ситуации, когда системный администратор находится далеко от Х-терминальной среды.

Пока интересно, читаем дальше!

Авторское право © Сеник Николай, 2004-2006