Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Apache 2.2. Ограничение соединений с хостом.  (Прочитано 14152 раз)
0 Пользователей и 1 Гость смотрят эту тему.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« : 04-01-2009 18:51 » 

Никто случайно не знает, как ограничить количество соединений к серверу с одного хоста?
В Апаче 1.3 был такой модуль, но его почему-то исключили из 2.х.

Если детально, то речь о нашей библиотеке. Есть жаждущие скачать файлы, которые не уважают нас и качают большие DDK в десятки потоков. Соответственно, каждый поток - это процесс Апача, который, пока не завершится передача запрошенных данных, обработкой других запросов заняться не может. Можно увеличить число процессов, но это, прежде всего, расход оперативки, которая не резиновая (от свопа на сервере проку нет). Временно доступ к DDK закрыт, но хотелось бы найти более гуманный метод. Можно даже программный (какой-нибудь модуль-обработчик для Апача написать).
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Chuda
Гость
« Ответ #1 : 05-01-2009 02:25 » 

http://dominia.org/djao/limitipconn2.html

А это не вариант?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 05-01-2009 09:58 » 

Спасибо Улыбаюсь А то я пол ночи сидел разбирался, как это программно делается и почти закончил (не понял только как поменять код HTTP-ответа из CGI, чтобы корректно ругнуться 503 и чтобы реализовать докачку по 206).



Опробовал модуль. Странное поведение.

Директории: /archive/ddk/

В первой ставим лимит - 2, во второй - 1.

Тестируем и получаем, что соединения к файлам во второй директории включаются в лимит для первой. При этом пока не понятно, влияют ли на них соединения к файлам в двугих директориях, но то, что эти лимитированные соединения не влияют на остальные директории - проверено.

По моему тут некорректность получается: если я задам в archive лимит 1, а в ddk - 2, то любая закачка из ddk запретит качать из archive...

Пока будем обкатывать и смотреть.
« Последнее редактирование: 05-01-2009 11:10 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Chuda
Гость
« Ответ #3 : 05-01-2009 23:20 » 

у меня был опыт использования этой радости только однажды, и случай был весьма простой.
Справилась Улыбаюсь
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 05-01-2009 23:31 » 

Ну, а какое тут еще применение, если только не выкладывание крупных файлов - в остальных случаях процессы освобождаются очень быстро и лимитировать особого смысла нет. Включать подобное на основном сайте - подвергаться риску быть непросканированным поисковыми роботами.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 06-01-2009 00:50 » 

В догонку - по поводу CGI: чтобы вставить свой код ответа нужно применить заголовок Status.

Status: 404 Not found


Вот реализация программы - ограничителя (download-limit). Тестовая версия.

Код: (Perl)
#!/usr/bin/perl

use DBD::mysql;

my ($dbh, $sth, $ipn, $file, $ctime, $session);
my ($file_length, $range_length, $range_start, $range_end);
my ($fd, $length, $buffer, $pos, $chunk);

sub db_open()
{
    $dbh = DBI->connect('DBI:mysql:database=test', 'test', 'test', {RaiseError => 1});
}

sub db_close()
{
    $dbh->disconnect();
}

sub sess_open()
{
    my @ip = split(/\./, $ENV{REMOTE_ADDR});
    $ipn = $ip[0] << 24 | $ip[1] << 16 | $ip[2] << 8 | $ip[3];

    db_open();
    $sth = $dbh->prepare("SELECT ctime, file FROM limit_sessions WHERE ip = $ipn");
    $sth->execute();

    if ($sth->rows())
    {
        my $res = $sth->fetchrow_hashref();
        $session = 1;
        $ctime = $res->{ctime};
        $file = $res->{file};
    }
    else
    {
        $session = 0;
        $ctime = time();
        $file = $ENV{PATH_TRANSLATED};
        $dbh->do("INSERT INTO limit_sessions (ip, ctime, file) VALUES ($ipn, $ctime, ?)", undef, $file);
    }

    $sth = undef;
    db_close();
}

sub sess_close()
{
    db_open();
    $dbh->do("DELETE FROM limit_sessions WHERE ip = $ipn");
    db_close();
}

sub sig_hup
{
    sess_close();
    exit 0;
}

sub debug
{
    open my $fd, ">>__log__$$";
    print $fd shift;
    close $fd;
}

##############################

use sigtrap qw(handler sig_hup any);

$| = 1;

sess_open();

print "Connection: closed\n";

for my $k (sort keys %ENV)
{
    debug "$k = $ENV{$k}\n";
}

if ($session)
{
    print "Status: 503 Service Unavalable\n";
    print "Content-Type: text/plain\n";
    print "\n";
    print "Only one session permitted!\n";
    exit 0;
}

###

$file_length = (stat($file))[7];

if (exists $ENV{'HTTP_RANGE'} and $ENV{'HTTP_RANGE'} =~ m/bytes=(\d+)?-(\d+)?/)
{
    $range_start = $1;
    $range_end = $2;
}

$range_start += 0;

if (!$range_end)
{
    $range_end = $file_length - 1;
}

$range_length = $range_end - $range_start + 1;

debug "$file_length, $range_start-$range_end/$range_length\n";

print "Content-Type: application/octet-stream\n";
print "Accept-Ranges: bytes\n";
print "Content-Length: $range_length\n";

if ($range_length != $file_length)
{
    print "Content-Range: $range_start-$range_end/$file_length\n";
    print "Status: 206 Partial content";
}

print "\n";


open my $fd, "<$file";
seek $fd, $range_start, 0;
$chunk = 1024;

for ($pos = $range_start; $pos <= $range_end; )
{
    $length = ($pos + $chunk - 1 <= $range_end) ? $chunk : $range_end - $pos + 1;
    read $fd, $buffer, $length;
    print $buffer;
}

close $fd;

sess_close();

exit 0;


Настройки Апача:

Код:
<Directory /var/www/my.site.com/www/>
    Action download-limit /cgi-bin/download-limit.pl
    SetHandler download-limit
</Directory>


Таблица для хранения сессий.

Код: (SQL)
CREATE TABLE limit_sessions (
  ip INT UNSIGNED NOT NULL,
  ctime INT UNSIGNED DEFAULT NULL,
  file VARCHAR(400) NOT NULL,
  PRIMARY KEY  (ip)
);

Смысл такой: в апаче ставится обработчик (в виде CGI-программы) на директорию. Апач проверяет наличие запрашиваемого файла, запускает CGI-скрипт и пережает ему в переменных окружения все необходимые сведения (PATH_TRANSLATED - уже оттранслированный путь к файлу). Далее программа решает, что выдать: 503, 200 или 206 и пережает требуемый диапазон из файла.
В тесте мне удавалась скорость 250 кБ/с. Прямое скачивание - около 500 кБ/с (предел моего инета). Думаю, если поиграться $chunk и $|, то можно поднять производительность.
« Последнее редактирование: 06-01-2009 01:13 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines