Эта статья была первоначально создана "AI Frontline", оригинальная ссылка:Практическое руководство Netflix: хранение данных масштабированных временных рядов
Автор | Кетан Дуведи и др.
Переводчик|Гай Лэй
Редактор | Наталья
Руководство по передовой ИИ:”Netflix использует историю просмотра видео участниками, чтобы точно записывать просмотр пользователей в режиме реального времени и предоставлять участникам персонализированные рекомендации. Развитие Netflix ставит проблему масштаба хранения данных временных рядов записей просмотра видео, а исходная архитектура хранилища с одной таблицей не может адаптироваться к крупномасштабному росту участников. В этой статье описывается подход команды Netflix к масштабированию хранилища временных рядов, включая улучшения в способах хранения данных и добавление уровня кэширования в архитектуру хранилища. Практическое применение архитектуры хранения в Netflix подтверждает эффективность хранения данных временных рядов. "
введение
Развитие устройств, подключенных к Интернету, предоставило большое количество легкодоступных данных временных рядов. Все больше и больше компаний заинтересованы в анализе этих данных, чтобы получить осмысленную информацию и принимать решения на ее основе. Последние достижения в области технологий сделали сбор, хранение и анализ данных временных рядов более эффективными, что побуждает задуматься о том, как следует обрабатывать эти данные. Однако вычислительная мощность большинства существующих архитектур данных временных рядов может быть не в состоянии справиться со взрывным ростом данных временных рядов.
Как компания, основанная на данных, Netflix привык к таким проблемам и на протяжении многих лет продвигает решения для такого роста. В этой серии сообщений в блоге, состоящей из двух частей, мы расскажем о подходе Netflix к улучшению своей архитектуры хранения данных временных рядов и о том, насколько хорошо он может справляться с экспоненциальным ростом размера данных.
Данные временных рядов: записи просмотров видео участников
Каждый день все участники Netflix просматривают более 140 миллионов часов видеоконтента вместе взятых. При просмотре видео каждый участник создает несколько точек данных, которые сохраняются в виде записей о просмотре видео. Netflix анализирует эти данные о просмотре видео, чтобы точно записывать закладки просмотра в режиме реального времени и предоставлять участникам персонализированные рекомендации. Для конкретной реализации, пожалуйста, обратитесь к следующему сообщению:
- Как узнать, где участник смотрит видео?
- Как я могу помочь участникам находить видео, которые стоит продолжать смотреть на Netflix?
Исторические данные о просмотрах видео будут увеличиваться по трем параметрам:
- Со временем каждый участник генерирует больше данных о просмотре видео, которые необходимо хранить.
- По мере увеличения числа участников необходимо хранить больше данных о просмотре видео.
- С увеличением ежемесячного времени просмотра видео участниками необходимо хранить больше данных о просмотре видео для каждого участника.
После почти десяти лет разработки у Netflix более 100 миллионов пользователей по всему миру, и исторические данные о просмотре видео также растут в больших масштабах. Этот пост в блоге будет посвящен одной из самых больших проблем — тому, как наша команда решила проблему хранения данных истории просмотров видео в масштабе.
Первоначальный проект базовой архитектуры
Первоначально облачная архитектура хранения данных Netflix использовала Cassandra для хранения данных истории просмотров. Команда основывается на следующих соображениях:
- Cassandra обеспечивает хорошую поддержку моделирования данных временных рядов, поддерживая динамически изменяющееся количество столбцов в строке.
- При просмотре исторических данных соотношение количества операций чтения к операциям записи составляет примерно 1:9. Поскольку Cassandra обеспечивает очень эффективные операции записи, она особенно подходит для таких рабочих нагрузок, требующих интенсивной записи.
- С точки зрения теоремы CAP, команда больше сосредоточена на достижении возможной согласованности, чем на доступности. Cassandra поддерживает настраиваемую согласованность, что облегчает компромиссы в отношении CAP.
В исходной архитектуре Cassandra использовалась для хранения истории просмотров всех участников. Среди них история просмотров каждого участника хранится в виде строки, идентифицируемой CustomerId. Этот горизонтально разделенный дизайн поддерживает эффективное масштабирование хранилища данных по мере роста числа участников и обеспечивает простое и эффективное чтение полных данных истории просмотров участников. Эта операция чтения является наиболее часто выполняемой операцией в хранилище исторических данных. Однако по мере того, как количество участников продолжает расти, особенно по мере того, как каждый участник просматривает все больше и больше видеопотоков, количество хранимых строк данных и общий объем данных также увеличиваются. Со временем это приведет к увеличению складских и эксплуатационных расходов. А для участников, которые смотрят много видео, производительность сильно снижается.
На следующей диаграмме показан поток операций чтения и записи в исходной модели данных.
Рисунок 1: Модель данных с одной таблицей
запись потока
Когда участник начинает воспроизводить видео, история просмотров вставляется в новый столбец. История просмотра обновляется, когда участник приостанавливает или прекращает просмотр видеопотока. В Cassandra запись в значение одного столбца выполняется быстро и эффективно.
чтение потока операций
Чтобы получить всю историю просмотров для участника, необходимо прочитать всю строку. Если количество просмотренных записей на члена невелико, операция чтения эффективна. Если участник смотрит много видео, то количество его просмотровых записей увеличится, то есть увеличится количество столбцов записей. Чтение строки с большим количеством столбцов создает дополнительную нагрузку на Cassandra, что, в свою очередь, негативно влияет на задержку чтения.
Чтобы прочитать данные участников за определенный период времени, необходимо выполнить запрос временного диапазона. Это также приводит к несоответствиям производительности, описанным выше. Потому что производительность запроса зависит от количества просмотренных записей в заданный период времени.
Если масштаб исторических данных для просмотра велик, для чтения всей строки требуется разбиение на страницы. Пейджинг лучше подходит для Cassandra, потому что запросам не нужно ждать, пока все данные будут готовы, прежде чем вернуться к пользователю. Пейджинг также позволяет избежать проблем с тайм-аутом клиента. Однако по мере роста записи о просмотре пейджинг увеличивает общую задержку чтения всей строки.
Причина задержки
Давайте взглянем на некоторые внутренние компоненты Cassandra, чтобы понять, почему наша первоначальная простая конструкция страдает от снижения производительности. По мере роста данных растет и количество SSTables. Поскольку в памяти хранятся только самые последние данные, для извлечения истории просмотров во многих случаях требуется чтение как memtable, так и SSTable. Это негативно влияет на задержку чтения. Кроме того, по мере роста данных операция сжатия будет занимать больше операций ввода-вывода и времени. Кроме того, по мере того, как ряд записей становится шире, восстановление чтения (Read repair) и полное восстановление столбца (Full column repair) также будет замедляться.
слой кэша
Cassandra может прекрасно выполнять операции записи данных просмотра, но необходимо уменьшить задержку операций чтения. Чтобы оптимизировать задержку чтения, мы рассматриваем возможность добавления уровня кэширования сегментов в памяти (т. е. EVCache) перед хранилищем Cassandra за счет увеличения объема работы на пути записи. Кэш реализован как базовое хранилище ключей и значений, где ключ — это CustomerId, а значение — это двоичное сжатое представление данных истории просмотров. Для каждой операции записи Cassandra будет сгенерирована дополнительная операция поиска в кэше. Как только кеш попадает, существующее значение в кеше дается напрямую. Для операций чтения истории просмотра в первую очередь используются сервисы, предоставляемые кешем. Как только кеш отсутствует, запись считывается из Cassandra, сжимается и вставляется в кеш.
С добавлением уровня кэширования однотабличное хранилище Cassandra хорошо работало в течение многих лет. В кластерах Cassandra разделение на основе CustomerId обеспечивает отличное масштабирование. К 2012 году кластер Cassandra для просмотра истории был одним из крупнейших выделенных кластеров Cassandra в Netflix. Для дальнейшего масштабирования хранилища команде потребовалось удвоить размер кластера. Это означало, что команде нужно было проникнуть в области, в которые Netflix еще не решался использовать Cassandra. В то же время бизнес Netflix продолжает быстро расти, включая рост международного членства и предстоящий бизнес по программированию собственного производства компании.
Редизайн: хранилище в реальном времени и сжатое хранилище
Очевидно, что для обеспечения роста предприятия в течение следующих пяти лет команде потребуется опробовать ряд различных подходов к масштабированию хранилища. Команда проанализировала характеристики данных и шаблоны использования, чтобы переопределить хранилище истории просмотров. Команда поставила перед собой две основные цели:
- меньше места для хранения;
- Обеспечивает стабильную производительность чтения и записи с учетом роста количества просмотров видео на одного участника.
Команда разделила данные истории просмотров каждого участника на два набора данных:
- Live/Recent Viewing History (LiveVH): небольшая коллекция часто обновляемой недавней истории просмотров. Данные LiveVH хранятся в несжатом виде, подробное оформление описано далее.
- Сжатая/Архивная история просмотров (CompressedVH): наиболее редко обновляемая история просмотров. Эта часть данных будет сжата для уменьшения места для хранения. Сжатая история просмотра в виде одного столбца и значения ключа, хранящегося в одной строке.
Для повышения производительности LiveVH и CompressedVH хранятся в разных таблицах базы данных и по-разному оптимизируются. Учитывая, что LiveVH часто обновляется, а количество задействованных записей просмотра невелико, на LiveVH можно выполнять частые операции уплотнения. А для того, чтобы уменьшить количество SSTables и размер данных, вы можете установить очень маленькое значение gc_grace_seconds. Для повышения согласованности данных также можно часто выполнять восстановление чтения и полное восстановление семейства столбцов. Для CompressedVH, поскольку эта часть данных редко обновляется, для уменьшения количества SSTables достаточно время от времени выполнять полное уплотнение вручную. При периодическом обновлении проверяется непротиворечивость данных, поэтому нет необходимости выполнять восстановление чтения и полное восстановление семейства столбцов.
запись потока
Для получения новых записей о просмотрах пишите в LiveVH тем же способом, что и выше.
чтение потока операций
Чтобы эффективно использовать преимущества нового дизайна, команда обновила API истории просмотров, чтобы предоставить опции для чтения последних данных и чтения полных данных.
- Чтение недавней истории просмотров: в большинстве случаев недавнюю историю просмотров нужно читать только из LiveVH. Это ограничивает размер данных, что, в свою очередь, снижает задержку.
- Чтение всей истории просмотра: реализовано как параллельное чтение LiveVH и CompressVH.
Учитывая, что данные сжаты, а в CompressedVH меньше столбцов, операции чтения включают меньше данных, что значительно ускоряет операции чтения.
Сжатый поток обновления VH
При чтении истории просмотра из LiveVH, если количество записей превышает заданный порог, самая последняя история просмотра будет свернута фоновой задачей, сжата и сохранена в CompressedVH. Упакованные данные сохраняются в новой строке с идентификатором строки CustomerId. Вновь упакованным данным будет предоставлена версия после записи, которая используется для операций чтения для проверки согласованности данных. Только после проверки согласованности новой версии упакованные данные старой версии будут удалены. Для упрощения блокировка в упаковке не рассматривается, и Cassandra отвечает за решение очень редких проблем с повторной записью (то есть последние записанные данные имеют преимущественную силу).
Рис. 2. Операционные модели для оперативных данных и сжатых данных
Как показано на рис. 2, упакованная строка CompressedVH также хранит информацию о метаданных, включая информацию о последней версии, размере объекта и информации о фрагментах, подробности которых описаны ниже. В записи есть столбец версии, указывающий на последнюю версию упакованных данных. Таким образом, чтение CustomerId всегда возвращает самые последние упакованные данные. Чтобы уменьшить нагрузку на хранилище, мы используем хранилище столбцов для упаковки данных. Чтобы свести к минимуму количество пакетов для участников с частыми моделями просмотра, в LiveVH хранится только история просмотров за последние несколько дней. После упаковки оставшиеся записи объединяются с записями в CompressedVH во время упаковки.
Автоматическое масштабирование через фрагментацию
Как правило, у большинства участников вся история просмотров может храниться в одной строке сжатых данных, а считываемый поток будет давать достаточно хорошую производительность. В редких случаях для небольшой группы участников с большой историей просмотров производительность чтения CompressedVH из строки будет постепенно ухудшаться из-за той же проблемы в исходной архитектуре. Для таких редких случаев нам нужно установить верхнюю границу задержки чтения и записи, чтобы избежать негативного влияния на задержки чтения и записи в обычном случае.
Чтобы решить эту проблему, если размер данных превышает предварительно установленный порог, мы разделим упакованные сжатые данные на несколько фрагментов и сохраним их на разных узлах Cassandra. Даже если история просмотра участника очень велика, параллельное чтение и запись блоков будет контролировать задержку чтения и записи в пределах установленного верхнего предела.
Рис. 3. Автоматическое масштабирование с помощью фрагментации данных
запись потока
Как показано на рисунке 3, упакованные сжатые данные делятся на несколько блоков в зависимости от заданного размера блока. Каждый фрагмент записывается в разные строки параллельно с использованием идентификатора CustomerId$Version$ChunkNumber. После того, как раздробленные данные успешно записаны, метаданные записываются в отдельную строку, идентифицированную как CustomerId. Для очень больших упакованных данных просмотра этот подход ограничивает задержку записи двумя операциями записи. В этом случае строка метаданных реализована как строка без столбцов данных. Эта реализация поддерживает операции быстрого чтения метаданных.
Чтобы ускорить обработку для распространенного случая, когда размер сжатых данных просмотра меньше заданного порога, мы объединяем метаданные с данными просмотра в одну строку, устраняя накладные расходы на поиск метаданных, как показано на рисунке 2.
чтение потока операций
При чтении строка метаданных сначала считывается с использованием идентификатора строки CustomerId. В обычном случае количество фрагментов равно 1, а строка метаданных включает последнюю версию упакованных сжатых данных просмотра. В редких случаях существует несколько фрагментов сжатых данных просмотра. Мы используем информацию метаданных, такую как версия и количество чанков, чтобы генерировать разные идентификаторы строк для разных чанков и читать все чанки параллельно. Это ограничивает задержку чтения двумя операциями чтения.
Улучшить слой кеша
Для поддержки разделения больших записей мы также улучшили уровень кэширования в памяти. Для участников с большой историей просмотров вся сжатая история просмотров может не уместиться в одну запись EVCache. Поэтому мы делаем что-то похожее на модель CompressedVH, разбивая каждую большую запись кэша на несколько фрагментов и сохраняя метаданные в первом фрагменте.
результат
Внедрив параллельное чтение и запись, сжатие данных и усовершенствования модели данных, команда достигла следующих целей:
- Благодаря сжатию данных он занимает меньше места для хранения;
- Благодаря блочному и параллельному чтению и записи обеспечивается стабильная производительность чтения и записи;
- В обычном случае задержка ограничивается одним чтением и записью. В редких случаях задержка ограничивается двумя операциями чтения и записи.
Рисунок 4: Результаты выполнения
Команда добилась примерно 6-кратного сокращения размера данных, примерно 13-кратного сокращения времени обслуживания Cassandra, примерно 5-кратного сокращения средней задержки чтения и примерно 1,5-кратного сокращения среднего времени записи. Что еще более важно, команда создала масштабируемую архитектуру и хранилище, способные справиться с быстрым ростом данных о просмотрах Netflix.
Во второй части этой серии блогов мы рассмотрим некоторые из последних проблем масштабирования хранилища. Эти проблемы приводят к следующему раунду обновлений архитектуры хранения данных истории просмотров участников. Если читатели заинтересованы в решении подобных задач, они могут присоединиться к нашей команде.
Посмотреть исходный английский текст:
medium.com/Netflix - настоящим...
Для большего содержания сухих товаров вы можете обратить внимание на AI Frontline, ID:ai-front, фоновый ответ "AI", "TF", "Большие данные«Вы можете получить серию мини-книг и карт навыков «AI Frontline» в формате PDF.