> Как оценить необходимое дисковое пространство для хранения сокращенных ссылок с учетом нагрузки и времени жизни (Python)
Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы
Компании: Международный аэропорт Шереметьево
Стек: Python
> Пример ответа
Короткий ответ
Оценка дискового пространства сводится к формуле: количество записей × размер одной записи + overhead индексов. Количество записей определяется как RPS × время жизни × коэффициент дублирования. Для сокращенных ссылок типичный размер записи - 100-200 байт (short code, оригинальный URL, timestamp, user_id). При 1000 RPS и времени жизни 1 год получаем ~31.5 млрд записей, что при 150 байтах на запись - ~4.7 ТБ без учета индексов. Индексы добавляют 30-50% к объему.
Подробное объяснение
Основные параметры модели:
-
Нагрузка (RPS) - количество создаваемых ссылок в секунду. Важно учитывать пиковые значения, а не средние, с запасом ×2-3.
-
Время жизни (TTL) - период, в течение которого ссылка должна храниться. После истечения запись удаляется или архивируется.
-
Размер записи - складывается из:
- short code: 6-8 символов (base62) - 6-8 байт
- оригинальный URL: в среднем 100-200 байт, но бывают длинные - закладывайте 500 байт
- timestamp создания и expires_at: 8 + 8 байт
- user_id (если есть): 4-8 байт
- дополнительные поля (click count, flags): 10-20 байт
- итого: 150-250 байт на запись
-
Коэффициент дублирования - если одна и та же ссылка сокращается повторно, либо создается новая запись, либо возвращается существующая. Второй вариант уменьшает объем, но требует дополнительного индекса по хешу URL.
-
Overhead БД - для PostgreSQL или MySQL это ~30-40% на страницы, транзакции, MVCC. Для Cassandra или DynamoDB - репликация ×3 и compaction overhead.
Формула:
total_bytes = writes_per_second × ttl_seconds × record_size × (1 + index_overhead) × replication_factor
Пример: 1000 RPS, TTL = 1 год (31 536 000 сек), record = 200 байт, index overhead = 0.4, replication = 1 (одиночная БД).
1000 × 31 536 000 × 200 × 1.4 ≈ 8.8 ТБ
Для распределенной системы с репликацией ×3 - 26.5 ТБ.
Важно учитывать, что реальный объем будет больше из-за:
- служебных данных (WAL, snapshots, temp files)
- фрагментации и неполного заполнения страниц
- роста размера индексов при вставках
На практике
На собеседовании важно показать, что вы учитываете не только средние значения, но и пиковые нагрузки, а также понимаете разницу между логическим и физическим размером данных.
Порядок оценки:
- Уточните RPS - спросите про пиковые значения и сезонность.
- Определите TTL - есть ли политика удаления старых ссылок.
- Оцените средний размер URL - можно взять 200 байт как разумный верхний предел.
- Посчитайте количество записей за период.
- Добавьте overhead индексов и служебных данных.
- Если система распределенная - умножьте на replication factor.
Также стоит упомянуть альтернативные подходы:
- Хранение только хеша и ID - оригинальный URL в отдельной таблице или object storage, в основной таблице только ссылка на него. Это уменьшает размер записи до 30-40 байт.
- Архивация старых записей - перемещение данных старше N месяцев в холодное хранилище (S3, Glacier), что снижает нагрузку на горячую БД.
- Использование колоночных хранилищ для аналитики, если нужны только агрегаты по ссылкам.
Пример кода
Расчет объема в Python:
PYTHONdef estimate_storage(rps: int,ttl_days: int,record_size_bytes: int = 200,index_overhead: float = 0.4,replication_factor: int = 1,peak_multiplier: float = 2.0) -> dict:ttl_seconds = ttl_days * 24 * 3600peak_rps = rps * peak_multipliertotal_records = peak_rps * ttl_secondsbase_size = total_records * record_size_byteswith_indexes = base_size * (1 + index_overhead)with_replication = with_indexes * replication_factorreturn {"total_records": total_records,"base_size_gb": base_size / (1024**3),"with_indexes_gb": with_indexes / (1024**3),"final_size_gb": with_replication / (1024**3),}# Пример: 1000 RPS, TTL 1 год, репликация ×3result = estimate_storage(rps=1000,ttl_days=365,record_size_bytes=200,replication_factor=3)for key, value in result.items():print(f"{key}: {value:,.2f}")
Вывод:
total_records: 63,072,000,000 base_size_gb: 11,748.05 with_indexes_gb: 16,447.27 final_size_gb: 49,341.80
Как отвечать на собеседовании
Начните с уточняющих вопросов: какой RPS, какое время жизни, есть ли репликация, какая БД используется. Это покажет системное мышление.
Затем предложите формулу и пройдите по каждому компоненту: количество записей, размер записи, overhead. Покажите расчет на конкретных цифрах.
Обязательно упомяните trade-off: можно уменьшить размер записи, вынеся URL в отдельное хранилище, но это усложнит чтение. Или сократить TTL, но тогда пользователи потеряют доступ к старым ссылкам.
В конце спросите, какие ограничения есть у системы - это покажет, что вы думаете о реальных constraints.
Что проверяет интервьюер
- Умение декомпозировать задачу на параметры (RPS, TTL, размер записи).
- Понимание overhead БД: индексы, репликация, служебные данные.
- Способность делать быстрые оценки (back-of-the-envelope) без калькулятора.
- Знание trade-off между хранением и скоростью доступа.
- Учет пиковых нагрузок, а не только средних.
Типичные ошибки
- Забывают про репликацию и overhead индексов - итоговая цифра занижается в 2-3 раза.
- Используют средний RPS вместо пикового - недооценка в периоды нагрузки.
- Не учитывают, что URL могут быть длинными (например, с UTM-метками) - лучше закладывать 500 байт.
- Считают только размер данных, игнорируя WAL, temp files, vacuum (для PostgreSQL).
- Не упоминают возможность архивации старых данных - это важный способ снизить объем горячего хранилища.
- Путают логический размер записи с физическим - на диске запись занимает больше из-за выравнивания и заголовков страниц.
> Похожие задачи по Python
С чем именно приходилось бороться в производительности
Какая должна быть длина короткой ссылки, чтобы избежать коллизий при заданной нагрузке и времени жизни
Как справляться с коллизиями при генерации коротких ссылок
Как хранить маппинг между длинным и коротким URL
> Похожие задачи по backend
С чем именно приходилось бороться в производительности
Какая должна быть длина короткой ссылки, чтобы избежать коллизий при заданной нагрузке и времени жизни
Как справляться с коллизиями при генерации коротких ссылок
Как хранить маппинг между длинным и коротким URL
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью