Guides
«Kiss My Stat!» Data Warehouse; customTask, на примере Tilda и AmoCRM
Дима Родин
Hustler
1. Интро
2. Почему выбирают ClickHouse вместо облачных BigQuery, RedShift
3. Обзор открытой платформы Rockstat: Jupyter, Grafana, Theia, ClickHouse, микросервисная архитектура.
4. Почему блокноты Jupyter это не программа и как писать правильный код
5. Screencast: Регистрация, создание сервера, установка Rockstat в Google Cloud (облако на 6 мес бесплатно от google)
6. Google Analytics и GTM: cамый верный способ записывать ClientIId в custom dimension получая 100% результат.
7. При помощи GTM настроим подстановку ClientId и UID и передачу в AmoCRM на примере сайта на Tilda

Канал с анонсами
TG: @kissmystat
Анонсы, дополнительные материалы,
важные оповещение
Чат для вопросов
TG: @kissmystats
Обсуждение, вопросы, помощь, флуд,
закидывание какашками
Бот для навигации
TG: совсем скоро
Ссылки на трансляции,
персональные коммуникации
Интро
Тут будет запись с трансляции

В этом руководстве пройдемся по особенностям хранилищ разберем способы установки Google Analytics на свой сайт.
Почему выбирают ClickHouse, BigQuery или RedShift?
Выбор технологии зависит от множества факторов. Для Rockstat выбрана self-hosted версия ClickHouse. Разберемся почему.

ClickHouse
  • это замечательный инструмент, устанавливается на собственный сервер, от него не ждешь неожиданностей и проблем с доступом.
  • невероятно быстр и эффективен: данные хранятся в сжатом виде и занимают очень мало места, а скорость их чтения просто невероятна.
  • огромное кол-во агрегатных аналитических функций, оконных функций. Есть функции для работы с цепочками/воронкам, например sequenceMatch, sequenceCount.
  • поддерживает декларативный язык запросов на основе SQL и во многих случаях совпадающий с SQL стандартом.
  • JOIN в ClickHouse не тоже самое, что JOIN в реляционной базе, тут это средство сведения результатов запросов, а не подстановка данных из другой таблицы. В наше время нет проблем с дисковым пространством, поэтому проще и быстрее писать во все записи сразу, и не использовать JOIN и таблицы.
Преимущества облачных решений
Удобно, все само работает, не надо администрировать. Множество готовых наработок и не надо изобретать велосипед.
Обзор цен
Amazon Redshift – продается инстанс, который администрирует сам Amazon. Взяв минимально доступный инстанс dc1.large в Ирландии, где одни из самых низких цен в Европе, цена составит 0.3$ в час, в месяц вы потратите 24*30.5*0.3=~220$.
Только за базу данных отдавать 220$ / 14409₽. Для кого-то дорого, для компаний нет.

Google BigQuery – стоимость зависит от объема хранимой информации и начинается от 0.02$ за Gb, объема записи от 0.01$ за 200 Мб и запрашиваемой информации от 5.00$ за Тb. Все цены на сайте Google Cloud.

ClickHouse бесплатен, но есть плата за сервер, какая она именно – слишком большой разброс и дело предпочтений. Лично мне вполне хватает сервера за 3200₽ на VScale или у Hetzner за 10.68€ / 12.22$ / 800₽.

Облачный ClickHouse доступен в Облаке Yandex, цена от 2065₽ в месяц. Специалисты Yandex будут заниматься поддержкой. Тип услуги аналогичен Amazon RedShift

Возможные проблемы с доступом к Google и Amazon.
Вспомним, что было когда началась блокировка Telegram? У огромнейшего кол-ва компаний были проблемы. Даже у крупного продуктового ритейлера отказали кассы.
Минимальное время выполнения запроса в BigQuery в несколько ms.
В BigQuery вам не выделяется персональный сервер, а используется большое общее облако.
С одной стороны, это дает невероятную скорость обработки больших запросов, т.к. используемые мощности будут в разы больше минимального сервера ClickHouse или инстанса в RedShift.
С другой, есть минимальное время обработки запроса и оно около 3 секунд.

Это очень значительно на примере, когда во время загрузки сайта у пользователя нужно достать историю его действий и посмотреть нет ли в ней определенной цепочки.
Если это будет занимать 3 секунды, он может успеть уйти.
А если за 0.2 секунды, то это даже раньше чем загрузилась страничка и ему можно показать/не показать какой-то ништяк.
Скорость выполнения запросов в ClickHouse
Виртуальный сервер на VScale: 4 vCPI, 8 GB.
Запрос на холодную (впервые за долгое время, никакого кеша нет).
SELECT
    name,
    count()
FROM activity
GROUP BY name
┌─name─────┬─count()─┐
│ activity │ 7279733 │
│ scroll   │ 6060716 │
└──────────┴─────────┘
2 rows in set. Elapsed: 0.299 sec. Processed 13.34 million rows, 214.67 MB (44.67 million rows/s., 718.84 MB/s.)
Последующие запросы.
┌─name─────┬─count()─┐
│ activity │ 7279854 │
│ scroll   │ 6060821 │
└──────────┴─────────┘
2 rows in set. Elapsed: 0.167 sec. Processed 13.34 million rows, 214.67 MB (80.09 million rows/s., 1.29 GB/s.)
Это боевой сервер и в это же время туда пишутся данные. Такая высокая скорость обработки позволяет использовать его в онлайн запросах, при этом пользователь не будет испытывать никакого дискомфорта связанного с ожиданием.
Особо ценная информация
Некоторую информацию очень не хочется куда-либо выгружать. Вдруг с настройками доступа кто-то ошибется. А ведь надо данные о продажах и прибыли выгружать.
Далеко и медленно
Иностранные интернет каналы куда медленнее локальных. Банально на прогулку до удаленного сервера и обратно уходит в разы больше времени (ниже примеры), поэтому дольше устанавливаются соединения и т.п. Иностранные каналы уже чем локальные. Если вы работали через VPN в другой стране, вы должны были почувствовать дискомфорт и тормоза. У серверов такая же история.
user@me:~$ ping front.nktch.com -n
PING front.nktch.com (82.202.204.194) 56(84) bytes of data.
64 bytes from 82.202.204.194: icmp_seq=1 ttl=61 time=2.12 ms
64 bytes from 82.202.204.194: icmp_seq=2 ttl=61 time=1.96 ms
64 bytes from 82.202.204.194: icmp_seq=3 ttl=61 time=1.92 ms
64 bytes from 82.202.204.194: icmp_seq=4 ttl=61 time=1.91 ms
^C
--- front.nktch.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 1.914/1.983/2.129/0.102 ms
user@me:~$ ping eu.nktch.com -n
PING eu.nktch.com (52.19.115.241) 56(84) bytes of data.
64 bytes from 52.19.115.241: icmp_seq=1 ttl=44 time=71.3 ms
64 bytes from 52.19.115.241: icmp_seq=2 ttl=44 time=71.1 ms
64 bytes from 52.19.115.241: icmp_seq=3 ttl=44 time=71.1 ms
64 bytes from 52.19.115.241: icmp_seq=4 ttl=44 time=71.0 ms
^C
--- eu.nktch.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 71.085/71.179/71.375/0.221 ms
Чувствуете разницу? Первый расположен в VScale, второй в Ирландии у Amazon AWS.
user@me:~$ ping test.rstat.org -n
PING test.rstat.org (95.216.147.181) 56(84) bytes of data.
64 bytes from 95.216.147.181: icmp_seq=1 ttl=56 time=14.8 ms
64 bytes from 95.216.147.181: icmp_seq=2 ttl=56 time=14.5 ms
64 bytes from 95.216.147.181: icmp_seq=3 ttl=56 time=14.6 ms
64 bytes from 95.216.147.181: icmp_seq=4 ttl=56 time=14.7 ms
^C
--- test.rstat.org ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 14.512/14.666/14.840/0.149 ms
Это скорость ответа от сервера, расположенного в Hetzner, датацентр в Хельсинки.
Зависимость
Вы в полной зависимости от провайдера услуги, вы автоматически принимаете все изменения, которые они делают в оферте. У вас нет возможности съехать на другого провайдера, ведь BigQuery только у Google, а RedShift только у Amazon. А вот имея у себя установленную версию ClickHouse, она – ваша, даже если сменится лицензия, ведь она будет распространяться только на новые копии, а вы можете продолжать использовать свою сколько угодно долго.
Проблема роста
Это уже камень в огород ClickHouse. Как только конфигурация становится много-серверной, появляется потребность поддержки.
Для этого нужен специалист, который хочет вкусно кушать, прилично выглядеть и катать девушек на новенькой бэхе.
Но вероятнее всего, на таких объемах вполне обосновано присутствие DBA в штате.
Обзор открытой платформы Rockstat: Jupyter, Grafana, Theia, ClickHouse, микросервисная архитектура.
Разберем во время вебинара
Почему блокноты Jupyter это не программа и как писать правильный код
Оставим на вебинар.

То чувство, которое испытывают разработчики, слыша, что в блокноте пытаются построить систему сбора статистики по расписанию.
Google Analytics и GTM: самый верный способ записывать ClientId в custom dimension со 100% результатом
Зачем вообще это делать? Кто знает пролистывают дальше, а кто не знает, читаем внимательно. Когда мы рассматриваем ситуацию, когда факт конверсии устанавливается в CRM, это происходит не в момент визита пользователя на сайте и тут особенно важно установить связь с данными в CRM. Если просто передавать в заявку utm-метки, будут некорректно обрабатываться пользователи, которые сразу не конвертнулись, а сделали это позже, причем с помощью какого-то другого канала, например, ретаргетинг вернул.

Чтобы решить эту задачку нужно иметь возможность получить данные по каждому отдельно взятому посетителю. У самого Google Analytics они есть, но он не дает возможности ими воспользоваться. Это не критично, ведь в GA есть возможность добавить свои произвольные параметры (dimensions) и метрики(metrics), а также получить ClientID.

Создается пользовательский параметр dimensionX, уровня сессии, в который и передается ClientID.

Существует несколько способов получения ClientId и передачи его в Analytics. Самые популярные:
// Версия без GTM
/* в трекер передается функция, которая будет вызвана, когда он загрузится */
ga(function(tracker) {
  /* получение ClientId */
  var cid = ga.getAll()[0].get('clientId');
  /* Отправляем событие с группой и действие set_client_id в analytics,
   * указав в параметрах clientId и флаг `nonInteraction`, означающий что
   * пользоватетель не производил взаимодействие с сайтом и это системное
   * событие */
  ga('send', 'event', 'set_client_id', 'set_client_id', {
    'dimension2': cid,
    'nonInteraction': 1
  });
});
// Если GTM
/* В GTM cоздается переменная типа JavaScript, код со следующим содержимым.
 * Далее создается тег события Universal Analytics, 
 * триггером которого является загрузка окна,
 * самому событию ставится произвольная категория и экшн,
 * добавляется параметр dimensionX, в который подставляется ClientId.
 * Проблема в том, что аналитикс мог еще не загрузиться.
 * Интересующиеся могут нагуглить множество руководств в Google.
 */
function(){
  var tracker = ga.getAll()[0];
  return tracker.get('clientId');
}
Правильный способ
Правильный он потому, что:
  • Не генерирует лишнее событие, которое, кстати, может потеряться или не успеть отправиться,
  • Analytics гарантированно загрузился в момент получения ClientId.
Для этого следует воспользоваться CustomTask в Google Analytics. Это возможность встроиться в цикл обработки запроса и до того, как будет отправлен просмотр страницы дописать к нему ClientId.

Создаем JavaScript переменную, у меня она называется CustomTaskSetClientId2, которая вернет JavaScript функцию, которая будет выполняться для всех событий (просмотры тоже события), начиная с самого первого
function() {
  return function(model) {
    var cid = model.get('clientId');
    /* вместо dimension2 подставьте свой вариант */
    model.set('dimension2', cid);
  };
}
Далее в разделе переменных нужно зайти в настройки Universal Analytics и установить значение поля customTask в {{CustomTaskSetClientId2}}. ременных нужно зайти в настройки Universal
Скринкаст про настройку GTM
Если напрямую используете analytics.js, решение аналогичное:

// Без GTM, при использовании analytics.js это делается так:
ga('create', 'UA-119907688-1', 'auto');
/* сразу после create подставляем значение customTask,
 * внутри уже знакомая нам функция */
ga('set', 'customTask', function(model){
  var cid = model.get('clientId');
  model.set('dimension2', cid);
})
ga('send', 'pageview');
Это было еще проще!
Канал с анонсами
TG: @kissmystat
Анонсы, дополнительные материалы,
важные оповещение
Чат для вопросов
TG: @kissmystats
Обсуждение, вопросы, помощь, флуд,
закидывание какашками
Бот для навигации
TG: совсем скоро
Ссылки на трансляции,
персональные коммуникации
При помощи GTM настроим подстановку ClientId и UID и передачу в AmoCRM на примере сайта на Tilda
Демо аккаунт для этого гайда (04 feb начало февраля 19)
Ссылка для входа: https://randomint.amocrm.ru/ 
Логин: randomint@armyspy.com
Пароль: tv2CYKPl 
Адрес тестовой странички, откуда данные уходят в AmoCRM: 
http://formtestpage.tilda.ws/lead_form
Я использую tilda и покажу на ней, полагаю, в других конструкторах аналогичная процедура.
Суть такова: у вас есть форма, которая куда-то передает данные. Требуется:
  • Добавить в форму скрытое поле, например `cid`
  • Доработать customTask, таким образом, чтобы в dataLayer отправлялось событие `shutUpAndTakeMyClientId` и clientId в параметре `cid`
  • Создать тег, подставляющий значение ClientIId на страницу в параметр `cid` формы
  • Создать триггер, срабатывающий по пользовательскому событию `shutUpAndTakeMyClientId`
  • Создать переменную уровня данных `shutUpAndTakeMyClientId` которая берет значение из параметра `cid` . в dataLayer.
  • Единственно чем отличается конфигурация с AmoCRM от других, это необходимость выбрать именно ее в списке интеграций.
function() {
  var dataLayer = window.dataLayer;
  return function(customTaskModel) {
    var cid = customTaskModel.get('clientId');
    customTaskModel.set('dimension2', cid);
    /* Пушим в даталейер */
    if(dataLayer){
      dataLayer.push({event: 'shutUpAndTakeMyClientId', cid: cid})
    }
  };
}
Создаем тег
<script> 
$('[name = "cid"]').val({{shutUpAndTakeMyClientId}})
</script> 
Триггером этого тега будет появление пользовательского события shutUpAndTakeMyClientId
Скринкаст как связать Tilda или AmoCRM
Канал с анонсами
TG: @kissmystat
Анонсы, дополнительные материалы,
важные оповещение
Чат для вопросов
TG: @kissmystats
Обсуждение, вопросы, помощь, флуд,
закидывание какашками
Бот для навигации
TG: совсем скоро
Ссылки на трансляции,
персональные коммуникации