Redis, также называемый Remote Dictionary Server, представляет собой базу данных в оперативной памяти с открытым исходным кодом. Это система хранения структурированных данных, работающая в оперативной памяти сервера, что гораздо быстрее, чем самый быстрый твердотельный накопитель (SSD). В результате Redis обладает высокой скоростью отклика и отлично подходит для ограничения частоты запросов.
Ограничение частоты запросов ограничивает количество запросов пользователя к ресурсу на сервере. Многие службы используют ограничения частоты запросов для предотвращения злоупотреблений, например, когда пользователь пытается перегрузить сервер слишком большим объемом трафика. Например, при использовании PHP для разработки публичного API (интерфейса прикладного программирования) для вашего веб-приложения необходимы ограничения частоты запросов. Это связано с тем, что при открытии API для публичного доступа вам захочется ограничить количество повторений определенных действий пользователем за определенный промежуток времени. Пользователи, не имеющие прав в вашей системе, могут полностью парализовать ее работу.
Ограничение частоты запросов позволяет вашему приложению работать бесперебойно, отклоняя запросы пользователей, превышающие установленный лимит. Если у вас большое количество клиентов, ограничение частоты запросов вводит политику справедливого использования, которая позволяет каждому пользователю получать доступ к вашему приложению на высокой скорости. Ограничение частоты запросов также может помочь вам сэкономить деньги на пропускной способности за счет снижения нагрузки на сервер.
Отслеживая активность пользователей в такой базе данных, как MySQL, можно было бы создать программу ограничения частоты запросов. Однако, поскольку такие данные необходимо загружать с диска и сопоставлять с установленным лимитом, итоговое решение может плохо масштабироваться при одновременном обращении множества пользователей к системе. Это не только неэффективно, но и сами реляционные системы управления базами данных не были созданы для этого.
Redis — отличный выбор для создания ограничителя частоты запросов, поскольку он работает как база данных в оперативной памяти и зарекомендовал себя как надежное решение для этих целей. В этом руководстве мы проведем вас по шагам реализации ограничения частоты запросов в PHP с использованием Redis на Ubuntu 20.04.
Давайте начнем!
Предварительные требования
Для выполнения этого руководства вам понадобится следующее:
-
Последняя версия установленной Ubuntu в вашей системе.
-
Пользователи системы должны иметь привилегии sudo.
-
Стек LAMP.
-
Настройте его, следуя руководству Как настроить стек LAMP.
-
-
Сервер Redis.
-
Следуйте инструкциям в руководстве Как установить и защитить сервер Redis, чтобы настроить Redis в вашей системе.
-
Шаг 1. Установка расширения Redis для PHP
Перед началом давайте обновим репозитории, чтобы избежать конфликтов пакетов:
|
1 |
sudo apt update |
Затем установите расширение php-redis, пакет, который позволяет использовать Redis в программах на PHP. Выполните следующую команду sudo для установки php-redis:
|
1 |
sudo apt install -y php-redis |
После этого перезапустите сервер Apache, чтобы загрузить библиотеку php-redis :
|
1 |
sudo systemctl restart apache2 |
Следующим шагом является обновление информации в индексе пакетов и установка библиотеки Redis для PHP. Затем мы создадим PHP-ресурс, который ограничивает доступ на основе IP-адреса пользователя.
Шаг 2. Создание веб-ресурса PHP для ограничения частоты запросов
На этом шаге вы создадите файл demo.php в корневом каталоге вашего веб-сервера ( /var/www/html/). Этот файл будет общедоступным, и пользователи смогут открыть этот URL-адрес в своем веб-браузере. Позже мы будем использовать команду curl для проверки доступности ресурса, который мы хотим использовать. Пользователи могут получить доступ к тестовому файлу ресурса три раза в течение 15 секунд. Попытка, превышающая максимальный лимит, приведет к выводу сообщения об ошибке.
Основная функциональность этого файла сильно зависит от сервера Redis. PHP-код в файле создает ключ на сервере Redis на основе IP-адреса пользователя, когда тот обращается к ресурсу в первый раз. При повторном обращении код попытается сопоставить IP-адрес пользователя с ключами, сохраненными на сервере Redis, и увеличит значение на единицу, если ключ существует. PHP-код будет постоянно проверять, не достигло ли новое значение максимального предела.
Через 15 секунд срок действия ключа Redis, основанного на IP-адресе пользователя, истечет, и отслеживание посещений веб-ресурса пользователем начнется снова. Откройте /var/www/html/demo.php файл в nano текстовом редакторе:
|
1 |
sudo nano /var/www/html/demo.php |
Затем заполните все поля для инициализации класса Redis. Не забудьте установить REDIS_PASSWORD в правильное значение:
|
1 2 3 4 |
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('REDIS_PASSWORD'); |
Redis->auth поддерживает аутентификацию на сервере Redis в виде простого текста. Это хорошо работает, если вы работаете локально (через localhost), но если вы имеете дело с удаленным сервером Redis, SSL-аутентификация рекомендуется.
Далее в том же файле установите следующие переменные в их значения по умолчанию:
|
1 2 3 4 5 |
. . . $max_calls_limit = 3; $time_period = 15; $total_user_calls = 0; |
Давайте подробно разберем эти операторы:
-
$max_calls_limit: Пользователь не может получить доступ к ресурсу сверх этого максимального лимита вызовов.
-
$time_period: Это используется в качестве временного интервала и измеряется в секундах. Здесь пользователю разрешен доступ к ресурсу в соответствии с лимитами, установленными в $max_calls_limit .
-
$total_user_calls: Суммирует количество раз, когда пользователь запрашивал доступ. Лимит вызовов за заданный период времени.
Затем добавьте следующий код, чтобы получить IP-адрес пользователя, запрашивающего доступ к веб-странице:
|
1 2 3 4 5 6 7 8 9 10 |
. . . if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $user_ip_address = $_SERVER['HTTP_CLIENT_IP']; } elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $user_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $user_ip_address = $_SERVER['REMOTE_ADDR']; } |
В качестве демонстрации этот код регистрирует действия пользователей по их IP-адресам. Если у вас на сервере есть защищенный ресурс, требующий аутентификации, вы можете отслеживать действия пользователей, используя их имена пользователей или токены доступа.
В нашем руководстве каждому пользователю, который входит в вашу систему, будет присвоен уникальный идентификатор (например, ID клиента, ID разработчика, ID поставщика или даже ID пользователя). Не забудьте использовать эти ID вместо $user_ip адреса, если вы следуете нашему руководству.
Здесь IP-адреса пользователя достаточно для демонстрации концепции. Добавьте следующий блок кода в свой файл, как только получите IP-адрес пользователя из предыдущего фрагмента кода:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
. . . if (!$redis->exists($user_ip_address)) { $redis->set($user_ip_address, 1); $redis->expire($user_ip_address, $time_period); $total_user_calls = 1; } else { $redis->INCR($user_ip_address); $total_user_calls = $redis->get($user_ip_address); if ($total_user_calls > $max_calls_limit) { echo "Пользователь " . $user_ip_address . " превысил лимит."; exit(); } } echo "Добро пожаловать, " . $user_ip_address . " всего выполнено запросов: " . $total_user_calls . " за " . $time_period . " seconds"; |
Вот обзор этих операторов:
-
if...else: Этот оператор проверяет, определен ли на сервере Redis ключ с IP-адресом.
-
Если ключ не найден, if (!$redis->exists($user_ip_address)) {...}, вы можете установить ключ и задать его значение равным 1 с помощью $redis->set($user_ip_address, 1).
-
-
$redis->expire($user_ip_address, $time_period): Указывает ключу истечь в определенное время. В этом руководстве мы установили его на 15 секунд.
-
Если IP-адрес пользователя не найден в ключе Redis, установите переменную $total_user_calls значение как 1.
-
else {...}: Блок операторов использует команду $redis->INCR($user_ip_address); для увеличения значения ключа Redis на 1. Это будет применено к каждому IP-адресу, связанному с ключом.
-
Примечание: Это возможно только в том случае, если ключ уже установлен на сервере Redis и учитывается как повторный запрос.
-
-
$total_user_calls = $redis->get($user_ip_address): Этот оператор извлекает общее количество запросов, проверяя соответствующий ключ на основе IP-адреса на сервере Redis.
-
if ($total_user_calls > $max_calls_limit) {... }..: Этот if оператор используется для проверки превышения лимита. Если лимит превышен, вы уведомляете пользователя с помощью echo "User" . $user_ip_address . " limit exceeded.";.
Наконец, вы уведомляете пользователя о количестве его посещений за указанный период с помощью оператора echo "Welcome" . $user_ip_address . "total calls made" . $total_user_calls . "in" . $time_period . "seconds";.
После этого добавьте следующие строки кода в ваш файл /var/www/html/demo.php:
|
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 |
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('REDIS_PASSWORD'); $max_calls_limit = 3; $time_period = 15; $total_user_calls = 0; if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $user_ip_address = $_SERVER['HTTP_CLIENT_IP']; }elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $user_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $user_ip_address = $_SERVER['REMOTE_ADDR']; } if (!$redis->exists($user_ip_address)) { $redis->set($user_ip_address, 1); $redis->expire($user_ip_address, $time_period); $total_user_calls = 1; } else { $redis->INCR($user_ip_address); $total_user_calls = $redis->get($user_ip_address); if ($total_user_calls > $max_calls_limit) { echo "User " . $user_ip_address . " limit exceeded."; exit(); } } echo "Welcome " . $user_ip_address . " total calls made " . $total_user_calls . " in " . $time_period . " seconds"; ?> |
Сохраните и закройте файл /var/www/html/demo.php после того, как закончите его редактирование. На веб-странице demo.php вы создали логику, необходимую для ограничения частоты запросов пользователей. Давайте протестируем наш скрипт на следующем шаге.
Шаг 3. Запуск теста ограничения частоты запросов Redis
На этом шаге вы будете использовать команду curl для запроса веб-ресурса, который вы написали на Шаге 2. Чтобы тщательно протестировать скрипт, выполните одну команду, которая запрашивает ресурс пять раз. Это можно сделать, добавив фиктивный аргумент URL к demo.php конца файла. Чтобы выполнить curl инструкции пять раз, используйте значение ?[1-5] в конце вашего запроса.
Выполните следующую curl команду ниже:
|
1 |
curl -H "Accept: text/plain" -H "Content-Type: text/plain" -X GET http://localhost/demo.php?[1-5] |
При выполнении этого кода вы должны получить примерно следующее:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[1/5]: http://localhost/demo.php?1 --> <stdout> --_curl_--http://localhost/demo.php?1 Welcome 127.0.0.1 total calls made 1 in 15 seconds [2/5]: http://localhost/demo.php?2 --> <stdout> --_curl_--http://localhost/demo.php?2 Welcome 127.0.0.1 total calls made 2 in 15 seconds [3/5]: http://localhost/demo.php?3 --> <stdout> --_curl_--http://localhost/demo.php?3 Welcome 127.0.0.1 total calls made 3 in 15 seconds [4/5]: http://localhost/demo.php?4 --> <stdout> --_curl_--http://localhost/demo.php?4 User 127.0.0.1 limit exceeded. [5/5]: http://localhost/demo.php?5 --> <stdout> --_curl_--http://localhost/demo.php?5 User 127.0.0.1 limit exceeded. |
Первые три запроса, как видите, прошли без проблем. Четвертый и пятый запросы, однако, были ограничены вашим скриптом. Весьма вероятно, что сервер Redis снижает скорость, с которой пользователи могут делать запросы.
Вы указали низкие значения для двух переменных, перечисленных ниже в этом руководстве:
|
1 2 3 4 |
... $max_calls_limit = 3; $time_period = 15; ... |
При создании приложения для рабочей среды (production) вы можете подумать об использовании больших значений, в зависимости от того, как часто, по вашему мнению, люди будут его использовать.
Перед настройкой этих чисел рекомендуется изучить статистику в реальном времени. В этом примере, если логи вашего сервера показывают, что средний пользователь посещает ваше приложение 1000 раз каждые 60 секунд, вы можете использовать это число в качестве примера для настройки ограничения частоты запросов.
Заключение
В этом руководстве вы узнали, как использовать сервер Redis с PHP на Ubuntu 20.04. Хотя эта статья демонстрирует, как работает ограничение частоты запросов с Redis, вы можете настроить его в соответствии с требованиями вашего веб-приложения. Мы рекомендуем вам изучить реальные примеры, такие как максимальный лимит запросов Twitter, Google Custom Search JSON API, и другую подобную документацию, чтобы расширить свои знания об ограничении частоты запросов и поэкспериментировать самостоятельно, используя различные временные лимиты.
Кроме того, на нашем сайте есть множество других учебных материалов по Redis и PHP, к которым вы можете получить доступ в наших блогах:
- Развертывание PHP-приложения в кластере Kubernetes с Ubuntu 18.04
- Установка и защита phpMyAdmin на Ubuntu 20.04
- Как установить стек LEMP (Linux Nginx MySQL PHP) на Ubuntu 20.04
Приятной работы!
Комментарии
Комментариев пока нет. Будьте первым.