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