Однажды у меня был разговор с разработчиком из компании Netflix. Я рассказывал ему про хранилища данных, а он остановил меня и сказал: «А не проще ли восстановить базу из бэкапа и с ней работать?» Во-первых, если вы не пользуетесь облачными сервисами, как это делает Netflix, то восстанавливать данные из бэкапа не так легко. Во-вторых, хранилища часто содержат свои агрегаты (о них расскажу позже), которые нужно поддерживать. В-третьих, если источников несколько и это разные базы данных или хранилища файлов, то будет невозможно делать запросы с соединением этих источников.
Слои хранилища данных
Само хранилище может состоять из нескольких слоев (рис. 6.1) [34]:
Данные из источников «как есть» (Первичный слой данных), или по-другому сырых данных. Как я уже писал выше, лучше их хранить в виде, максимально совпадающем с источником.
Данные, приведенные в целостную форму, независимую от источника (Центральный слой). Это означает, что мы уже можем работать с логической схемой, человеко-понятными терминами. Аналитику не придется думать, как соотносятся термины в разных источниках, все уже сделано в этом слое.
Данные, представленные в виде витрин для определенного круга пользователей (Витрины данных). Деление происходит по предметной области: маркетинг, продажи, склад Лучшим примером будет подготовка данных для OLAP-кубов. Данные для них приходится специально готовить. Подробней об этом поговорим в следующей главе об инструментах анализа данных.
Рис. 6.1. Слои хранилища данных
Эти слои логические, и они весьма условны; физически они могут размещаться как в разных системах, так и в одной.
В Retail Rocket я много работал с данными активности пользователей. Данные приходят в кластер в режиме реального времени в формате JSON и складируются в одну папку. Это первый слой сырые данные. Сразу же делаем преобразование данных, чтобы было удобно работать с ними в формате CSV, складируем их во вторую папку. Это второй слой. Далее данные из второго слоя отправляются в аналитическую базу данных ClickHouse, где уже построены специальные таблицы для каких-либо задач например, для отслеживания эффективности алгоритмов рекомендаций. Это третий слой витрины данных.
Какие бывают хранилища
Если распределить все созданные хранилища по популярности использования, то я бы их расставил так:
1. Реляционные базы данных Postgre, Oracle, MS SQL Server и т. д.
2. «Колоночные» базы данных Vertica, Greenplum, ClickHouse; облачные Google BigQuery, Amazon Redshift.
3. Файловые Hadoop.
Я не стал включать в список большие энтерпрайзные системы от IBM, Teradata и других вендоров, у них своя ниша, в которой я не работал.
Лично я работал с Microsoft SQL Server в Ozon.ru и Wikimart.ru, Postgres в Ostrovok.ru, Hadoop в Wikimart.ru и Retail Rocket, Clickhouse в Retail Rocket. У меня остались только положительные впечатления об этих технологиях. В последнее время я предпочитаю экономить и пользоваться открытыми технологиями (open-source).
Итак, реляционные базы данных (рис. 6.2) рабочая лошадка многих бизнесов. Они все еще популярны, несмотря на атаку NoSQL-технологий. Данные в них хранятся в таблицах с колонками и строками, между таблицами есть «отношения», также можно выставлять логику при операциях с полями и т. д. Оптимизация производительности делается с помощью настройки индексов
Рис. 6.2. Таблицы реляционной базы данных
и различных хаков, которые у каждого вендора свои. Они популярны, с ними умеют работать множество специалистов. Самое главное, что базы этого типа привнесли в мир, это язык программирования SQL (Structured Query Language). Этот язык может использоваться как для внесения изменений, так и для получения данных. Минус реляционных баз низкая производительность, когда идет работа с большими данными. И в Ozon.ru, и в Wikimart.ru я держал данные по статистике посещения сайтов в обычной таблице, а это миллиарды строк. Можно было сходить на обед, пока считался нужный запрос.
На помощь реляционным базам данных, в которых данные хранятся построчно [35], пришли колоночные базы. И совершили революцию. Вот пример таблицы реляционной базы (табл. 6.1).
Таблица 6.1. Пример данных реляционной таблицы
Чтобы найти все товары с типом (колонка Type) «Гостиная», придется прочитать все строки данных (если нет индекса по этому столбцу), что удручает, если их миллиарды и даже триллионы. В колоночной базе данные хранятся по столбцам отдельно, отсюда и название колоночные:
На помощь реляционным базам данных, в которых данные хранятся построчно [35], пришли колоночные базы. И совершили революцию. Вот пример таблицы реляционной базы (табл. 6.1).
Таблица 6.1. Пример данных реляционной таблицы
Чтобы найти все товары с типом (колонка Type) «Гостиная», придется прочитать все строки данных (если нет индекса по этому столбцу), что удручает, если их миллиарды и даже триллионы. В колоночной базе данные хранятся по столбцам отдельно, отсюда и название колоночные:
ID: 1 (1), 2 (2), 3 (3)
Name: Стул (1), Стол (2), Стул (3)
Type: Кухонная мебель (1), Кухонная мебель (2), Гостиная (3)
Color: Белый (1), Красный (2), Синий (3)
Теперь, если делать выборку товаров по типу «Гостиная», придется прочитать только нужный столбец. Но как найти нужные записи? Это не проблема: каждое значение столбца содержит номер записи, к которому оно относится. Дополнительно значения столбцов можно отсортировать и даже сжать, что делает такие базы еще быстрее. В них тоже есть минус требовательность к «железу» сервера, на котором она работает. Колоночные базы идеально подходят для аналитических задач, которые изобилуют запросами по фильтрации и агрегации данных.
Если нужна «молотилка» для совсем больших данных то это Hadoop. Она была разработана в компании Yahoo, которая сделала эту технологию общедоступной. Эта система работает на распределенной файловой системе HDFS и не требовательна к оборудованию. Для Hadoop компания Facebook разработала SQL-движок под названием Hive, позволяющий писать запросы к данным на языке SQL. Главное преимущество Hadoop большая надежность. Минус медленная скорость, зато там, где обычная БД не справится с каким-то запросом, Hadoop доведет дело до конца, медленно, как черепаха, но верно. Я использовал Hive и был доволен результатом, мне удавалось даже писать на нем простейшие алгоритмы рекомендаций.
Теперь главный вопрос когда и какие технологии использовать?
Мой рецепт следующий:
Если данных относительно немного и нет таблиц с миллиардами строк, то проще использовать обычную реляционную базу.
Если данных больше миллиарда строк или требуется хорошая скорость для аналитических запросов (агрегация и выборки) то лучше всего использовать колоночную базу данных.
Если требуется хранить очень большой объем с сотнями миллиардов строк, вы готовы мириться с медленной скоростью или хотите иметь архив исходных данных то Hadoop.
В Retail Rocket использовался Hive поверх Hadoop для службы технической поддержки, но запросы могли выполняться больше получаса. Поэтому требуемые ими данные были переведены в Clickhouse (колоночная база данных), и обработка запросов ускорилась в сотни раз. А скорость очень важна для интерактивных аналитических задач. Сотрудники Retail Rocket мгновенно полюбили новое решение за его скорость. Hadoop при этом остался в качестве рабочей лошадки для расчета рекомендаций.
Как данные попадают в хранилища
Чтобы данные оставались актуальными, их нужно периодически обновлять. Делать это можно путем полного или инкрементального обновления.
Полное обновление применяют к справочникам и состояниям на определенный момент времени (об этих типах я писал в главе 5). Выглядит оно следующим образом данные скачиваются из источника в промежуточную таблицу или папку (staging) хранилища, и если операция прошла успешно, эти старые данные меняются на свежие. Плюсом такого типа обновления является полное соответствие данных источнику на момент скачивания. Первым минусом является время для обновления таблиц, которое напрямую зависит от размера исходных данных. Второй минус потеря изменений после обновления данных. Представьте, что у вас есть справочник с товарами магазина, в исходной системе он всегда актуален, а в хранилище обновляется каждый день в полночь. Если какой-то товар был заведен и удален из справочника вы этого не заметите в хранилище. Для аналитика это будет выглядеть так, будто такого товара не существовало. Заказы этого товара могли совершаться. Поэтому при анализе заказов возникнет ситуация нарушения целостности данных: в таблице этот заказ есть, в справочнике товаров нет.
Инкрементальное обновление данных применяется для лога изменений (я писал о нем в главе 5). Конечно, можно его полностью перезагружать, но обычно это нецелесообразно из-за большого объема, а следовательно, медленной скорости обновления. Само инкрементальное обновление выглядит следующим образом: система смотрит в хранилище, какие данные были загружены последними (это может быть время или какой-то идентификатор). Далее делается запрос к источнику: «Отдай мне данные, которые поступили после момента X». После получения эти данные добавляются к старым в хранилище. Плюсом инкрементального обновления является скорость. Минусом возможна рассинхронизация данных, когда были добавлены лишние записи, которые уже были, или, наоборот, произошла потеря данных.