Конференция разработчиков
высоконагруженных систем
Хочу быть в курсе событий!
Как мы храним 60 тысяч событий в секунду
1. Введение.
1.1. Про AdRiver.
1.2. Определение события как информационной единицы системы.
1.3. Условное разделение системы на две части: realtime-часть отвечает за выборку баннеров и порождает события, а статистическая подсистема отвечает за их хранение и обработку.
1.4. Обоснование необходимости хранения событий и несколько примеров аналитической информации, которая предоставляется клиентам.
1.5. Обоснование необходимости обеспечения консистентности данных - это основное бизнес-требование к подсистеме хранения. Рассказ про далекие времена, когда события хранились в текстовых логах и регулярно приходилось объяснять клиентам природу расхождений цифр в различных отчетах.
2. Постановка задачи и требования.
2.1. Описание рабочих объемов данных: 4 млрд событий в сутки или ~500 Гб сериализованных данных в сутки. Минимальный период хранения - 1 год.
2.2. Обеспечение консистентности данных.
2.3. Обеспечение произвольного доступа к данным.
2.4. Обеспечение надежности, отказоустойчивости и масштабируемости.
3. Реализация и ключевые решения.
3.1. Сравнительный анализ предметной области. Эксперименты с map/reduce фреймворками и СУБД. Обоснование разработки собственной системы хранения.
3.2. Общее описание разработанной системы History.
3.3. Обоснование важности алгоритмической оптимизации и отказа от "лишней" логики в высоконагруженных серверах.
3.3.1. Наша аксиома проектирования: каждый компонент должен ХОРОШО выполнять одну функцию, вместо того, чтобы ПЛОХО предоставлять множество.
3.3.2. Сервер, предоставляющий произвольный доступ к данным, абстрагирован от самих данных и не производит никакой их обработки. Это позволяет уменьшить нагрузку на процессор при обслуживании множественных запросов к данным.
3.4. Краткое описание используемых механизмов сериализации. Аналогия c Google Protobuf.
3.5. Описание используемого механизма индексации данных, который позволяет идентифицировать любое событие системы. Это решение является ключевым к обеспечению консистентности.
3.6. Потоковое хранение данных и страничная организация - панацея в решении проблем с оперативной памятью. Предпочтительнее "упереться" в производительность дисковой подсистемы или процессора, чем в "Out of Memory", потому что в первом случае произойдет лишь снижение производительности системы, а во втором - отказ в обслуживании.
3.7. Сжатие данных, страничная организация хранения и абстрагирование сервера от самих данных позволяют любой нашей ноде отдавать гигабит информации в секунду, обслуживая 200 клиентов и обрабатывая 1000 файлов. Загрузка процессора, диска и памяти в этот момент не больше минимальной. Сервер отдает клиенту пожатые страницы данных, которые клиент должен распаковать и обработать перед тем как запросить следующую порцию. За это время сервер успевает подготовить следующую порцию данных и обслужить остальных клиентов.
4. Ремарки к реализации.
4.1. Однажды мы нарушили собственную аксиому проектирования и нагрузили сервер оптимизацией чтения данных (группировка по ключам). В результате "открылся ящик Пандоры" - теперь при ошибках в конфигурации система может "закопаться" в io wait.
4.2. Работа с диском производится асинхронно посредством POSIX AIO. В планах осуществить переход на kernel AIO и сравнить эксплуатационные характеристики.
5. Выводы и перспективы.
5.1. Задача решена, все довольны.
5.2. Подведение итога для эксплуатационных характеристик системы: год данных - 200Тб, параллельное обслуживание 1000 клиентов, суммарный исходящий трафик подсистемы - 20Гбит/сек. Оценка стоимости.
5.3. Краткий обзор инструментов аналитики, построенных на базе History. Размышления на тему того, что вся "лишняя" логика, от которой отказались в п.3.3., ушла на более высокие уровни.
5.4. Требуется существенное увеличение скорости получения данных. Описание способов реализации этого требования.
5.5. Требуется уменьшение задержки в работе (latency) системы без потери консистентности данных.