Какое-то время назад я написал статью на Хабре. В ней же пообещал продолжение через пару недель. Но, как известно, обещанного три года ждут — и с тех пор действительно прошло три года. Если вы не запомнили со времён той статьи, то напомню — я работаю в Avito, строю хранилище на основе Vertica.
Из того, что поменялось — теперь я могу не просто написать статью, а сделать это в блоге компании. И, надеюсь, не один раз. Самопиар окончен, теперь к делу.
Мое хранилище основано на методологии Anchor Modeling. В 2013 такой выбор методологии был, во многом, прыжком веры (leap of fate). Сейчас, по прошествии почти 4 лет, можно сказать, что прыжок удался. В первой статье было приведено довольно много аргументов за Anchor Modeling. Сейчас эти аргументы остались верны, но отошли на второй план.
На сегодняшний день главный аргумент за использование Anchor Modeling+Vertica один: возможен почти безграничный рост. Рост в объемах, скорости поступления и в разнообразии — все то, что принято называть 3V (Volume, Velocity, Variety), и что характеризует большие данные.
Представьте, что ваше хранилище — это маленькая грибница. Она начинается с одной споры, а потом начинает разрастаться, покрывая метр за метром, оплетает деревья, пока не получится многотонный монстр… рост которого не останавливается… никак не останавливается.
Представьте себя на месте архитектора хранилища. Хорошо, когда вы можете на старте оценить примерные объемы данных, интегрируемые системы, алгоритмы анализа данных. Тогда вы можете подобрать модель данных и платформу обработки под свою ситуацию. И не факт, что в таком случае выбор Vertica+Anchor Modeling будет оптимальным.
Сущность первая — Anchor
Anchor — это существительное, объект реального мира. Товар, пользователь, платеж. Соответственно, каждому существительному — своя таблица. Anchor таблица должна хранить ТОЛЬКО суррогатный ключ (в Vertica лучший ключ - int) и несколько технических полей. Концептуально Anchor нужен только для одной задачи — грузить каждый уникальный товар/пользователя/платеж только один раз. Избежать повторной загрузки, и помнить, в какой момент и из какой системы пришла исходная запись. Все.
Чтобы понять, как решается задача идентификации товара/пользователя/платежа — переходим ко второй сущности.
Сущность вторая — Attribute
Attribute — это таблица для хранения свойства, атрибута объекта. Названия товара, логина и даты рождения пользователя, суммы платежа. Одно свойство у объекта — одна Attribute-таблица. Десять свойств у объекта (имя, фамилия, дата рождения, пол, адрес регистрации, ...) — десять Attribute-таблиц. Все просто. Тяжело для психики, ведь количество таблиц по началу очень пугает, но просто.
Каждая Attribute-таблица содержит суррогатный ключ объекта, которым являетсяссылка на соответствующий Anchor, поле для значения атрибута, и, опционально, дату для историчности и технические поля. Соответственно, Attribute-таблица для имени (Name) покупателя (Customer) должна называться S_Customer_Name и содержать поля Customer_id (суррогатный ключ), Name (значение атрибута) и Actual_date (дата для SC2 историчности). Как видите, название таблицы и названия всех ее полей предельно однозначно определяются ее содержимым (имя покупателя).
Какой нюанс добавляет Vertica?… Все просто, все Attribute-таблицы для одного Anchor-а должны быть идентично сегментированы: сегментированы по хешу суррогатного ключа, отсортированы по суррогатному ключу и по дате историчности. Простое правило, соблюдая которое, вы получите гарантию, что все join между Attribute-таблицами одного Anchor-а будут MERGE JOIN — самым эффективным join в Vertica. Аналогично, указанная сегментация гарантирует оптимальность оконных функций, необходимых для обслуживания ETL операций с SC2 историчностью на одной дате.
В предыдущем разделе было анонсировано описание подхода к идентификации объектов: приходит строка данных про пользователя — как понять, этот пользователь уже есть в Anchor, или он новый? Естественно, ответ на этот вопрос ищется в атрибутах. Главное достоинство Anchor Modeling — возможность использовать сначала одни атрибуты (ФИО), а потом начать использовать другие (ФИО+ИНН). Причем с учетом историчности.
Сущность третья — Tie
Tie — это таблица для хранения связей между объектами. Например, таблица для хранения факта наличия у покупателя гражданства в определенной стране. Соответственно, таблица должна содержать суррогатный ключ левого объекта (customer_id), правого объекта (country_id) и, по необходимости, даты историчности и технических полей.
С точки зрения Vertica добавляется следующий нюанс — Tie таблица должна быть создана с двумя проекциями — сегментированной по левому суррогату и сегментированной по правому суррогату. Чтобы как минимум один из JOIN-ов этой таблицы был MERGE JOIN.
Важный нюанс с точки зрения моделирований — Anchor Modeling сильно отличается от Data Vault тем, что в Data Vault можно вешать данные (сателлиты) на связь (link), а в Anchor Modeling данные (Attribute) можно повесить только на Anchor, на Tie нельзя (важно — НЕЛЬЗЯ). Это на первый взгляд избыточное ограничение позволяет более точно моделировать реальный физический мир. Например, традиционная связь со свойствами в Data Vault — это факт продажи товара клиенту, свойством которого является сумма продажи. Anchor Modeling заставляет немного подумать и понять, что факт продажи товара клиента — это не элемент реального мира, а абстракция. Элементом реального мира является чек (бумажка) с номером, датой и т.п. Соответственно, в Anchor modeling описанный пример описывается тремя Anchor — Покупатель, Чек, Товар, и двумя Tie: Покупатель-Чек и Чек-Товар.
(внимательный читатель заметит, что даже картинка-пример в начале раздела не совсем корректна. Факт гражданства фиксируется определенным документом (паспортом), и более корректно представлять указанные данные именно через Anchor с паспортом).
Итого — 4 года с Anchor Modeling
Когда первый раз читаешь про Anchor Modeling, становится страшно.
Страшно утонуть в таблицах. Страх справедлив, важно не дать ему себя остановить. Приведенная выше иллюстрация демонстрирует темпы роста количества таблица каждого типа в Avito на протяжении 4 лет (правый график — суммарное количество Anchor+Attribute+Tie).
Напомню вам первый график в статье — хранилище Avito в конце 2016 включало данные из более чем 29 исходных систем. Как видите, таблиц много. Но не устрашающе много. Можно сказать, что большой скачок количества таблиц происходит в начале, а потом, за счет нарастающего повторного использования старых таблиц, темпы роста снижаются. Резкий скачок количества таблиц в конце 2016 года объясняется подключением необычно большого количества новых систем и демонстрирует, что несмотря на размер системы, она по-прежнему способна расширяться.
Вторая причина опасаться большого количества таблиц — сложности анализа со стороны внешних аналитиков.
О способе борьбы с подобным опасением я расскажу в следующей статье. Надеюсь, в этот раз ее не придется ждать еще три года :) А пока можно изучить записи моих выступлений по теме на семинарах, конференциях и вебинарах.
Автор: Avito