Upstash Redis
Коротко: Провайдер «бессерверного Redis» — база данных в памяти для быстрых, недолговечных данных (например, сеансов, счётчиков ограничения частоты запросов), доступная через REST API вместо классического подключения Redis.
Подробнее: Доступ идёт через REST URL + токен (UPSTASH_REDIS_REST_URL/_TOKEN), которые постоянно можно посмотреть в панели. Если подключение отсутствует, многие приложения переходят в резервный режим, что часто проявляется как внезапная медлительность.
Наш контекст: Используется в Emzett, среди прочего, для глобального ограничения частоты запросов — когда после переноса подключение к Redis отсутствовало, это привело к заметно медленным страницам (каждый запрос безуспешно пытался подключиться).
Подробности
Классический Redis обычно работает как постоянно открытое TCP-соединение, удерживаемое в долго работающем серверном процессе. Бессерверные среды (например, Vercel Functions), напротив, постоянно запускают и останавливают экземпляры функций — постоянное TCP-соединение не вписывается в эту модель, и каждому новому экземпляру пришлось бы сначала снова устанавливать дорогое соединение. Upstash решает это, принимая команды Redis через обычные HTTP-запросы (GET/POST с командой в теле вместо специального двоичного протокола) — это как раз вписывается в модель «недолговечных вызовов функций», без проблем с пулами соединений.
Типичное применение такой базы данных в памяти — данные, которые должны быть быстро доступны, но не обязаны попадать навсегда в основную базу данных (PostgreSQL/Neon): состояние сеанса, счётчики для ограничения частоты запросов, недолговечные кэши или значения флагов функций (см. Флаги функций). Важное отличие от обычной базы данных: значениям Redis можно задать TTL (time to live) — они автоматически исчезают по истечении срока, без собственного задания очистки.
await redis.set(`ratelimit:${ip}`, count, { ex: 60 }) // автоматически истекает через 60 сБольше, чем просто ключ–значение
Помимо простых строковых значений Redis (а значит, и Upstash) предлагает специализированные структуры данных, гораздо эффективнее для определённых задач, чем их воссоздание в классической реляционной базе данных: упорядоченные множества (ZADD/ZRANGE) идеальны, например, для таблиц лидеров (значения автоматически сортируются по очкам), списки (LPUSH/RPOP) — для простых очередей, а хэши — для структурированных объектов под одним ключом, без необходимости отдельного ключа Redis для каждого поля.
Скользящее и фиксированное окно при ограничении частоты
Для ограничения частоты (как в примере выше) существуют две распространённые стратегии: фиксированное окно считает запросы в фиксированных временных окнах (например, «0–60 с», «60–120 с») — просто реализовать, но у него есть слабое место на границах окон (пользователь мог бы использовать полный лимит и непосредственно ПЕРЕД границей, и сразу ПОСЛЕ, пропустив за короткое время вдвое больше запросов, чем предполагалось). Скользящее окно вместо этого всегда смотрит на последние N секунд относительно текущего момента, независимо от фиксированных границ — точнее, но реализовать несколько сложнее. Готовые библиотеки вроде @upstash/ratelimit предлагают обе стратегии сразу, без необходимости воссоздавать их самим.
См. также: Ограничение частоты запросов, TTL, Neon