Существует множество инструментов для ограничения скорости и QoS, но до сих пор я не смог найти ни одного, который бы отвечал моим конкретным потребностям, а именно:
У меня есть веб-приложение, работающее на Apache 2.2, и я хочу, чтобы каждый из моих клиентов ограничивался, скажем, 10000 запросами в день. Ограничение должно быть основано не на IP-адресе клиента, а на учетной записи клиента, которую можно извлечь из URL-адреса; например.: http://mywebsite.com/customer1/page1. Как только они превышают свой лимит, я бы хотел, чтобы их запросы «замедлялись» до некоторого предопределенного значения, например 15 запросов в минуту, возможно, путем введения задержки. Если это невозможно, то можно будет вернуть сообщение об ошибке типа 503 Service Unavailable.
Как я могу сделать это с помощью Apache? Если нет возможности сделать это с помощью Apache, тогда меня будут интересовать предложения по другим инструментам, обратным прокси и т. Д.
ОБНОВЛЕНИЕ: ограничение скорости должно происходить для ряда служб (mod_dav_svn, mod_passenger, mod_wsgi) и должно быть высокопроизводительным.
Я только что принял ответ @ Ladadadada: «Это невозможно сделать с Apache», но я подумал, что перечислю несколько способов, которыми я ищу, как обойти это, для справки:
Напишите свой собственный модуль Apache. Он будет использовать общую память, чтобы отслеживать все запросы и учетные записи, к которым они были. Срок действия этих счетчиков истечет через 24 часа. Учетные записи, которые превышают нижний предел, будут задерживать каждый из своих запросов на определенный период времени, а учетные записи, превышающие верхний предел, будут возвращать статус 503 для всех запросов. Имя учетной записи будет извлечено из URL-адреса с помощью SetEnvIf.
Напишите сценарий (на Ruby), который будет запускаться как демон и следить за журналом доступа Apache. Он будет извлекать имя учетной записи из каждого зарегистрированного запроса и отслеживать их так же, как # 1, без сложностей с общей памятью. Он также будет отслеживать все IP-адреса, связанные с данной учетной записью за последние 24 часа. Когда учетная запись превышает свой лимит, он будет добавлять правила NFQUEUE iptables для каждого IP-адреса, связанного с учетной записью. Пакеты с этих IP-адресов будут захвачены сценарием Ruby с использованием Netfilter :: Queue (во втором потоке), где они будут задерживаться.
Я не думаю, что вы сможете сделать это только в Apache.
Есть довольно много Модули Apache, ограничивающие пропускную способность но я не думаю, что кто-то из них будет соответствовать тому, что вы описали.
mod_bw может ограничивать пропускную способность на основе различных частей запроса. Он может ограничиваться на основе IP-адреса, расширения файла, типа MIME, размера файла и каталога (на основе моего чтения документы). Вы добиваетесь ограничения на основе каталога, помещая директивы модуля внутри <Directory >
блок, поэтому я ожидаю, что они будут работать так же хорошо внутри <Location >
блок. mod_bwshare кажется, идет внутрь <Directory >
и <Location >
блоки тоже.
Конфигурация этих модулей Apache входит в вашу конфигурацию Apache, и они не ищут значения из какого-либо внешнего источника, а это означает, что вам придется перезапустить Apache, чтобы изменить любое из значений. Если вы хотите ограничить полосу пропускания только после того, как клиент превысил свою квоту, вам нужно будет редактировать файлы конфигурации Apache и перезапускать Apache каждый раз, когда любой из них делает это, и делать это снова, когда истекает их использование квоты.
Я бы написал небольшое приложение на любом используемом вами языке, которое принимает запрос на файл, проверяет в базе данных, не превышает ли клиент квоту, а затем отправляет им файл с любой подходящей скоростью. Парень, который написал mod_bw, объяснил, как ему удалось добиться троттлинга: он просто делит файл на небольшие «куски» (скажем, по 5 КБ на кусок), а затем имеет короткий sleep()
между пересылкой каждого фрагмента клиенту.
Я бы тогда использовал mod_rewrite
чтобы перевести запросы исходного файла (которые, по вашему мнению, выглядят как /customer1/page1
) во что-то вроде /throttle.php?customer=customer1&file=page1
.
Приложение может записывать данные в базу данных в начале загрузки, чтобы указать, что в данный момент оно обрабатывает файл, и еще раз в конце, чтобы указать, что теперь она завершена. Это должно позволить вам помешать одному клиенту забрать всех ваших детей Apache.