ТЕХНИЧЕСКОЕ ЗАДАНИЕ на разработку высокопроизводительной In‑Memory Cache системы (аналог Memcached/Redis) 1. Цель проекта Разработать высоконагруженное сетевое кэширующее хранилище типа «ключ‑значение» на языке C++ (или Rust). Система предназначена для снижения нагрузки на основную БД путём временного хранения часто запрашиваемых данных в оперативной памяти. Ключевые целевые показатели: Пропускная способность ≥ 10 000 операций/сек. Задержка (p99) < 10 мс. Поддержка ≥ 1 000 одновременных клиентских соединений. Потокобезопасность и отказоустойчивость (graceful shutdown). 2. Функциональные требования 2.1. Базовые команды Реализовать следующий минимальный набор команд (текстовый протокол поверх TCP): SET key value [EX seconds] – сохранить значение, опционально с временем жизни. GET key – получить значение по ключу, вернуть ошибку, если ключ отсутствует. DELETE key – удалить ключ. EXISTS key – проверить существование ключа. (опционально) INCR key – инкремент числового значения. (опционально) STATS – вывести статистику (хиты/промахи, использовано памяти и т.п.). 2.2. Управление памятью и вытеснение Реализовать политику вытеснения LRU (Least Recently Used) или LFU. При превышении заданного лимита памяти (задаётся в конфиге) автоматически удалять наименее приоритетные элементы. Для значений с TTL – ленивое удаление при доступе + фоновый сборщик с заданным интервалом. 2.3. Сетевой протокол Сервер должен принимать TCP-соединения, поддерживать keep‑alive. Обрабатывать несколько запросов в рамках одного соединения. Формат ответов: простой текстовый (например, +OK\r\n, $\r\n\r\n, -ERR ...\r\n). 2.4. Многопоточность Обработка параллельных запросов должна быть потокобезопасной. Рекомендуется шардирование данных по нескольким независимым кэш‑инстансам (каждый в своём потоке) для минимизации блокировок. 3. Нефункциональные требования (чёткие метрики) Параметр Целевое значение Пропускная способность (GET) ≥ 10 000 RPS (при 1000 клиентах, размер значения ~100 байт) Задержка (p99) < 10 мс при 80% нагрузке Количество одновременных соединений ≥ 1 000 (постоянных) Максимальный размер кэша Конфигурируется (например, 1 ГБ, 4 ГБ) Graceful shutdown По сигналу SIGTERM сервер завершает текущие запросы и корректно закрывает соединения за < 1 сек Логирование Асинхронное, с ротацией файлов 4. Архитектурные требования (общие) Сетевой I/O – использовать мультиплексирование (epoll для Linux, kqueue для macOS, IOCP для Windows) с неблокирующими сокетами. Модель потоков – реакторный паттерн: один главный поток (акцептор) распределяет соединения по пулу воркеров, либо каждый воркер владеет своим epoll-циклом (рекомендуется для NUMA). Управление памятью – избегать частых динамических аллокаций (использовать пулы объектов, слейбы или, как минимум, std::pmr). Данные значения хранить как непрерывные блоки байтов. Конфигурация – параметры (порт, максимальный размер кэша, политика вытеснения, число потоков) должны читаться из конфигурационного файла (например, JSON или TOML). 5. Технологический стек Для C++: Язык: C++17 (или C++20, на выбор) Сеть: системные вызовы (socket, epoll, accept) либо обёртки (например, Boost.Asio – по желанию) Многопоточность: std::thread, std::jthread, синхронизация через std::mutex/std::shared_mutex или lock‑free структуры Тестирование: Google Test для модульных тестов, нагрузочные утилиты wrk, hey, vegeta Сборка: CMake Для Rust (альтернатива): Язык: Rust 2021 Runtime: Tokio (многопоточный) Сеть: tokio::net::TcpListener / TcpStream Кэш: DashMap для шардирования без блокировок, lru для политики Тестирование: встроенные тесты, бенчмарки через criterion Сборка: Cargo 6. План работ на неделю (примерное распределение) День Задачи День 1 Изучение предметной области. Проектирование структур данных (классов/модулей). Написание архитектурной схемы. Согласование ТЗ. День 2 Реализация ядра кэша – хеш‑таблица + двусвязный список (LRU) с защитой мьютексами (или шардирование). Написание юнит‑тестов для этих структур. День 3 Разработка сетевого уровня: создание TCP‑сервера с epoll, парсер команд, буферизация чтения/записи. Базовое логирование. День 4 Интеграция кэша и сетевого слоя. Реализация всех команд (SET, GET, DELETE, EXISTS, TTL). Проверка сквозных сценариев. День 5 Нагрузочное тестирование, профилировка (perf, Valgrind), оптимизация «узких» мест (уменьшение копирований, улучшение локализации). День 6 Добавление команды STATS, метрик (количество операций, hit ratio, использование памяти). Настройка graceful shutdown. День 7 Финальное тестирование, написание документации (README, описание протокола, примеры запуска), подготовка демонстрационного выступления. 7. Критерии приёмки (оценка преподавателем) № Критерий Вес 1 Корректность реализации всех команд – SET, GET, DELETE, EXISTS (и TTL) работают согласно спецификации 25 2 Производительность – достигнуто не менее 10 000 RPS на GET‑запросах (подтверждено бенчмарком) 25 3 Стабильность и масштабируемость – система выдерживает ≥ 1 000 одновременно открытых соединений без падений и утечек 20 4 Потокобезопасность – отсутствие гонок данных (проверено инструментами, например, ThreadSanitizer) 10 5 Управление памятью – нет утечек (Valgrind / AddressSanitizer), корректно отрабатывает LRU 10 6 Документация – наличие README, инструкции по сборке и примеров использования 5 7 Graceful shutdown – корректное завершение по сигналу, без потери данных (запись завершается) 5 8. Возможные расширения (для дополнительных баллов) Персистентность – периодическое сохранение дампов кэша на диск и восстановление при старте. Репликация – синхронизация данных между несколькими экземплярами (master‑slave или кластер). Шардирование по ключу (consistent hashing) для горизонтального масштабирования. Экспорт метрик в Prometheus или вывод их через HTTP‑эндпоинт. Поддержка SSL/TLS для защищённого соединения. Расширенный протокол (например, поддержка списков или хешей, как у Redis).