Класична задача системного дизайну. Важливо не одне «правильне» рішення, а структура міркувань: вимоги → оцінки → API → дані → вузькі місця.
1. Вимоги.
- функціональні: створити коротке посилання, перенаправити за ним, (опційно) власні аліаси, термін дії, статистика переходів;
- нефункціональні: переходи дуже швидкі й доступні; читань набагато більше, ніж записів; коди непередбачувані (не можна перебрати чужі посилання).
2. Оцінки (див. попередні розрахунки): ~10 записів і ~1000-5000 читань на секунду, ~1 ТБ за 5 років.
3. API:
POST /api/links {"url": "https://..."} → {"code": "aB3xK9q"}
GET /aB3xK9q → 301/302 Location: https://...
301 чи 302: 301 кешують браузери - менше навантаження, але зникає статистика повторних переходів. Для аналітики - 302.
4. Генерація коду - найцікавіша частина:
- хеш URL (перші символи base62 від SHA-256) - однакові URL дають однаковий код, але можливі колізії - потрібна перевірка;
- лічильник + base62 - унікально без колізій; 7 символів base62 = 62^7 ≈ 3,5 трлн кодів. Але послідовні коди передбачувані - перемішати (бієкція, шифрування лічильника);
- випадковий код + перевірка унікальності - простіше, при великій заповненості зростає ймовірність колізії.
5. Сховище: таблиця code → url з унікальним індексом на code. Пошук за ключем - ідеальний випадок для будь-якої бази; масштаб невеликий для шардингу.
6. Масштабування читань: кеш (Redis) перед базою: популярні посилання становлять малу частку, і кеш з LRU покриє більшість переходів. Плюс CDN/edge для редиректів.
7. Статистика переходів: не писати в базу синхронно на кожен перехід - події в чергу чи потік, агрегування пакетами.
8. Безпека й зловживання: перевірка URL на фішинг і шкідливі сайти, ліміти створення, заборона внутрішніх адрес.
Чого чекає інтерв'юер: уточнення вимог, обґрунтування вибору генерації кодів, розуміння, що основне навантаження - читання, і що кеш вирішує його дешевше за шардинг.