
Привет, Хабр!
Supabase – это крутой open-source аналог Firebase, с его помощью можно организовать крутые штуки вроде ограничения скорости запросов.
Supabase – это инструмент, который дает возможность создавать масштабируемые серверные решения, используя PostgreSQL. С его помощью можно легко управлять базами данных, аутентификацией, хранением данных и реальным временем, но без всяких vendor lock-ins.
Rate Limiting контролирует поток запросов, чтобы ваш сервер не ушел в нокаут от перегрузки. Это спасает сервера от DDOS-атакти помогает обеспечить более равномерное распределение ресурсов среди пользователей.
pg_headerkit
pg_headerkit – это расширение PostgreSQL, предназначенное для управления HTTP-заголовками прямо из вашей базы данных. Это расширение позволяет вам манипулировать HTTP-заголовками на уровне бдшки, что открывает широкие возможности для контроля и управления вашими API-запросами.
С pg_headerkit можно установить различные правила и логику для обработки входящих и исходящих HTTP-запросов. Например, вы можете настроить ограничение скорости на основе IP-адреса или API-ключа, а также управлять кэшированием или даже блокировать запросы, не соответствующие определенным критериям.
Для установки pg_headerkit потребуется иметь учетку supbase и установить dbdev на гитхабе.
Устанавливаем:
SELECT dbdev.install('burggraf-pg_headerkit'); CREATE EXTENSION "burggraf-pg_headerkit" VERSION '1.0.0';
Далее создадмим проект на официальном сайте Supabase.
Войдите в Supabase Dashboard. Откройте раздел SQL.
Запустим SQL-запрос для создания таблицы rate_limit:
CREATE TABLE rate_limit ( api_key VARCHAR(255) NOT NULL, last_request_time TIMESTAMP NOT NULL DEFAULT now(), request_count INTEGER NOT NULL DEFAULT 1 );
Реализация ограничения скорости запросов
Входим в нашу БД постгреса и создаем расширение pg_headerkit:
psql -U username -d database CREATE EXTENSION pg_headerkit;
Создадим таблицу, которая будет использоваться для контроля скорости запросов:
CREATE TABLE rate_limit ( api_key VARCHAR(255) NOT NULL, last_request_time TIMESTAMP NOT NULL DEFAULT now(), request_count INTEGER NOT NULL DEFAULT 1 );
Напишем функцию, которая будет проверять и обновлять счетчик запросов:
CREATE OR REPLACE FUNCTION check_rate_limit() RETURNS TRIGGER AS $$ DECLARE time_difference INTERVAL; BEGIN -- Проверяем время с последнего запроса SELECT now() - last_request_time INTO time_difference FROM rate_limit WHERE api_key = NEW.api_key; IF time_difference > INTERVAL '1 minute' THEN -- Сброс счетчика запросов после 1 минуты UPDATE rate_limit SET request_count = 1, last_request_time = now() WHERE api_key = NEW.api_key; ELSE -- Увеличиваем счетчик запросов UPDATE rate_limit SET request_count = request_count + 1 WHERE api_key = NEW.api_key; IF (SELECT request_count FROM rate_limit WHERE api_key = NEW.api_key) > 10 THEN -- Превышен лимит запросов RAISE EXCEPTION 'Превышен лимит запросов'; END IF; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql;
Cоздадим триггер, который будет вызывать нашу функцию при каждом запросе:
CREATE TRIGGER rate_limit_trigger BEFORE INSERT ON your_table FOR EACH ROW EXECUTE FUNCTION check_rate_limit();
Теперь каждый раз, когда кто-то пытается сделать запрос, наш триггер проверяет, не превышен ли лимит запросов, и если да, то выкидывает исключение.
Другие возможности
Можно настроить более гибкие ограничения скорости, которые будут меняться в зависимости от времени суток. Например, установить более жесткие ограничения в часы пик и более мягкие в нерабочее время:
CREATE OR REPLACE FUNCTION dynamic_rate_limit() RETURNS TRIGGER AS $$ DECLARE current_hour INT; BEGIN current_hour := EXTRACT(HOUR FROM now()); IF current_hour BETWEEN 8 AND 18 THEN -- Жесткие ограничения в рабочее время ELSE -- Мягкие ограничения в нерабочее времни] END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER dynamic_rate_limit_trigger BEFORE INSERT ON your_table FOR EACH ROW EXECUTE FUNCTION dynamic_rate_limit();
Можно создать более сложную систему лимитов, которая будет учитывать, к примеру, разные уровни доступа пользователей или их группы:
CREATE OR REPLACE FUNCTION user_specific_rate_limit() RETURNS TRIGGER AS $$ DECLARE user_role VARCHAR; BEGIN SELECT role INTO user_role FROM users WHERE api_key = NEW.api_key; IF user_role = 'premium' THEN -- Высокие лимиты для премиум пользователей ELSE -- Стандартные лимиты для обычных пользователей END IF; -- [Остальная логика функции] RETURN NEW; END; $$ LANGUAGE plpgsql;
Можно использовать pg_headerkit для добавления HTTP-заголовков в ответ, информирующих пользователя о текущем состоянии его лимитов:
CREATE OR REPLACE FUNCTION add_rate_limit_headers() RETURNS TRIGGER AS $$ DECLARE remaining_requests INTEGER; BEGIN SELECT (10 - request_count) INTO remaining_requests FROM rate_limit WHERE api_key = NEW.api_key; PERFORM headerkit.add('X-RateLimit-Remaining', remaining_requests::TEXT); RETURN NEW; END; $$ LANGUAGE plpgsql;
Если у вас есть список IP-адресов, с которых не должно быть доступа к вашему API, вы можете легко заблокировать их:
CREATE TABLE blocked_ips ( ip_address VARCHAR(15) ); INSERT INTO blocked_ips (ip_address) VALUES ('192.168.1.1'); CREATE OR REPLACE FUNCTION check_blocked_ips() RETURNS TRIGGER AS $$ BEGIN IF EXISTS (SELECT 1 FROM blocked_ips WHERE ip_address = NEW.ip_address) THEN RAISE EXCEPTION 'Доступ запрещен с вашего IP-адреса'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER ip_block_trigger BEFORE INSERT ON your_requests_table FOR EACH ROW EXECUTE FUNCTION check_blocked_ips();
pg_headerkit только улучшит производительность баз данных за счет более гибкого и точного управления загрузкой, и обеспечивает возможность более тонкой настройки процессов в соответствии с потребностями конкретной системы.
Больше практических инструментов и навыков эксперты отрасли показывают в рамках онлайн-курса PostgreSQL для администраторов баз данных и разработчиков. Присоединяйтесь.
ссылка на оригинал статьи https://habr.com/ru/articles/785290/
Добавить комментарий