Управление загрузкой с помощью PostgreSQL и pg_headerkit

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет, Хабр!

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/companies/otus/articles/785290/


Интересные статьи

Интересные статьи

В мире, где данные говорят больше, чем слова, рассказывание историй с помощью данных становится ключевым навыком для аналитиков. В этой статье мы погрузимся в мир data storytelling и узнаем, как Pytho...
Сегодня использование виртуальных машин повсеместно. Кто-то на них держит продакшн-сервисы, кто-то тестовые хосты, кто-то раскатывает на них лабораторные работы.Я сижу на Linux и для виртуализации исп...
Привет, Хабр!При автоматизации работы с документацией иногда приходится иметь дело со сканами плохого качества. Особенно удручает ситуация, при которой вместо сканированного документа предоставляется ...
Добрый день, уважаемые читатели! Не открою для большинства секрета, если скажу, что большая часть задач в материалах к учебным курсам сформулирована шаблонно. Какие-то вопросы в принципе могут предста...
На эту тему было много толковых публикаций, однако я сделал все по своему, вдобавок создал трехмерную модель корпуса с практичным и оригинальным дизайном. В результате получился вполне законченны...