Presentation highload-2011-openstat-myakshin - копия
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Presentation highload-2011-openstat-myakshin - копия

on

  • 691 views

 

Statistics

Views

Total Views
691
Views on SlideShare
691
Embed Views
0

Actions

Likes
1
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Presentation highload-2011-openstat-myakshin - копия Presentation Transcript

  • 1. Управляемый code injection: как мы считаем всепользовательские отчёты за один проходв системе интернет-статистики Openstat Михаил Якшин http://www.openstat.ru/ myakshin@openstat.ru
  • 2. О чём этот доклад● Какие бывают отчёты в веб-аналитике?● Как эти отчёты реализуются традиционно и не очень традиционно?● Как посчитать много отчётов в одном потоке?● Какую пользу из этого можно извлечь?
  • 3. Веб-аналитика:взгляд с высоты птичьего полета Логи веб-сервера Сайт Отчёты Счётчик Логи счетчика
  • 4. Типы отчётов● Стандартные отчёты – предоставляются всем клиентам по умолчанию, не требуют никакой дополнительной настройки ● Хорошо параллелизуются и считаются на потоке● Нестандартные отчёты – требуют понимания специфики задач клиента, дополнительной настройки или программирования ● Возникает проблема с параллелизацией и масштабированием
  • 5. Типы отчётов Стандартные: Нестандартные:● Популярные страницы ● Разделы сайта● Точки входа, точки выхода ● Характеристики посетителей● Источники трафика ● Популярные темы и комментарии в форуме● Браузеры ● Продажи интернет-магазина● Операционные системы ● Каналы привлечения аудитории● Экранные разрешения ● SEO● Мобильные устройства ● ...● География● ...
  • 6. Тридцатисекундный экскурс в термины веб-аналитики● Просмотры (Pageviews) – события загрузки страницы сайта посетителем● Визиты/сессии (Visits/Sessions) – последовательность обращений посетителя к сайту, интервал между которыми не превышает 30 минут● Посетители (Visitors) – пользователи, совершившие обращение к сайту и идентифицируемые некоторым образом (по IP, cookie и т.д.)
  • 7. Про термины в картинкахПосетитель 1 Не менее 30 минутПосетитель 2Посетитель 3 t P = 14 S=4 V=3
  • 8. Какие отчёты заказываютпотребители веб-аналитики? (1)Раздел P S VНовости 4905 490 301Пресс-релизы 3691 527 301Магазин 4548 413 391Техподдержка 2548 509 364Файлы 4092 511 378
  • 9. Какие отчёты заказываютпотребители веб-аналитики? (2) Пол → Мужской Женский Всего Раздел ↓ Новости 80 15 95 Статьи 60 50 110 Магазин 50 100 150На пересечении – один из показателей,например, P – число pageviews
  • 10. Какие отчёты заказывают потребители веб-аналитики? (3)Группа ↓ Источник → SEO Поисковики Контекст Прямые Товар ↓ переходыКабель UTP 30 90 60 100 STP 40 20 0 740Коннекторы RJ45 80 150 300 30 На пересечении – один из показателей, например, V – число уникальных посетителей
  • 11. Level 1: сегментация ”Сегменты” – механизм для построения статистики по характеристикам, которые:● имеют относительно немного интересующих значений, например: ● пол: мужской / женский ● география: Москва / остальная Россия / зарубежье ● совершил ли посетитель целевое действие: да / нет● не изменяются на протяжении визита
  • 12. Пользовательские сегменты● Сегмент – бинарная характеристика визита; визит либо относится к сегменту (1), либо не относится к нему (0)● Сегмент задается в виде булевой функции, оперирующих полями лога, например: ● se_name=”Google” ● geo_country=”RU” AND browser=”Firefox”● Если хотя бы в одном событии визита функция вернула true, то весь визит относится к сегменту
  • 13. Иллюстрация работы сегмента Условие: se_name = ”Google” (”посетители, пришедшие на сайт с Google”) ”Google” ”Bing”
  • 14. Иллюстрация работы сегмента Условие: se_name = ”Google” (”посетители, пришедшие на сайт с Google”) ”Google” ”Bing”
  • 15. Иллюстрация работы сегмента Условие: se_name = ”Google” (”посетители, пришедшие на сайт с Google”) ”Google” ”Bing”
  • 16. Иллюстрация работы сегмента Условие: se_name = ”Google” (”посетители, пришедшие на сайт с Google”) ”Google” ”Bing”
  • 17. Как это выглядитв веб-интерфейсе
  • 18. Как это выглядит внутри в отчёте ID счётчика Сегмент Провайдер S 1234567 0 Всего 51352 1234567 0 Ростелеком 5336 1234567 0 Корбина 2270 1234567 0 Билайн 1637 1234567 0 ... ... 1234567 1 Всего 1584 1234567 1 Ростелеком 31 1234567 1 Корбина 33 1234567 1 Билайн 104 1234567 1 ... ...
  • 19. Схема процесса работы с сегментами Сайт Логи Вычисление битмаска сегментов Отчёты Расчёт Расчёт стандартных Битмаски стандартных отчётов сегментов отчётов
  • 20. Level 2: пользовательские отчёты Сегменты не годятся в том случае, если:● Нужно посчитать статистику по характеристике, изменяющейся в течении сессии ● например, посещаемый раздел сайта● Число интересных значений характеристики исчисляется сотнями, тысячами, миллионами ● например, ассортимент товаров в интернет-магазине
  • 21. Традиционный отчёт на базе Apache Hadoop● Создается код для нескольких jobов, реализующих цепочку: mapper → reducer [→ mapper → reducer → …]● На вход подаются все логи● Нужно следить за корректным запуском jobов в нужном порядке и передаче промежуточных результатов от одного jobа к другому
  • 22. Level up: Hadoop + CascadingПереходим от терминов map-reduce киспользованию готовых примитивов:● Function – преобразование 1 строчки в 0..N● Filter – проверяет условие, оставляет или нет 1 строчку● Aggregator – реализует итератор над группой: initializer, iterator, finalizer● Buffer – предоставляет Java Iterator по группе
  • 23. Cascading: пример// Вычисляем названия разделов из URLpipe = new Each(pipe, new DeriveSections(), Fields.ALL);// Задаем группировкуpipe = new GroupBy( pipe, new Fields(F_COUNTER_ID, F_SECTION_NAME), new Fields(F_VIS_ID, F_SESSION_ID, F_ID));// Делаем агрегацию того, что нагруппировалиpipe = new Every( pipe, new BuildVPSE());
  • 24. Насколько сложно написать такой отчёт?● Основной код: 3 строчки (на предыдущем слайде)● DeriveSections: ~25 строчек● BuildVPSE: ~200 строчек● Трудозатраты: порядка часа-два (50-70% времени – написание тестов)● BuildVPSE – единожды написанный агрегатор, применяется во всех отчётах
  • 25. Чем плох такой отчёт?● Писать отдельную задачу для каждого отчёта затратно● Запуск отдельных задач на каждый отчёт - затратен● Поднимать с диска все данные всех счётчиков для обработки одного отчёта - затратно
  • 26. Как можно улучшить ситуацию?● Очевидно – найти у отчётов что-то общее и попробовать объединить расчёт всех отчётов в один проход● На первый взгляд – это кажется сложным
  • 27. Плоское представление двумерных отчётов Раздел Пол P Новости Мужской 80Пол → Мужской Женский Всего Статьи Мужской 60Раздел Магазин Мужской 50↓ Новости Женский 15Новости 80 15 95 Статьи Женский 50Статьи 60 50 110 Магазин Женский 100Магазин 50 100 150 Новости Всего 95 Статьи Всего 110 Магазин Всего 150
  • 28. Плоское представление трёхмерных отчётовГруппа ↓ Источник → SEO Поис Кон­ Группа Това Источник V Товар ↓ кови текст р ки Кабель UTP SEO 30Кабель Кабель STP SEO 40 UTP 30 90 60 Коннекторы RJ45 SEO 80 STP 40 20 0 Кабель UTP Поисковики 90Коннекторы Кабель STP Поисковики 20 RJ45 80 150 300 Коннекторы RJ45 Поисковики 150 Кабель UTP Контекст 60 Кабель STP Контекст 0 Коннекторы RJ45 Контекст 300 ... ... ... ...
  • 29. Основная идея Все подобные отчёты можно уложить в одну общую схему:● Некая специфичная для отчёта функция-обработчик● Группировка● Агрегация
  • 30. Схематично, в терминах Cascading// Вычисляем пользовательскую функциюpipe = new Each(pipe, new UserFunction(), Fields.ALL);// Задаем группировку В этом коде нужно изменять только этиpipe = new GroupBy( 2 вещи! pipe, new Fields(F_COUNTER_ID, GROUP_BY_FIELDS), new Fields(F_VIS_ID, F_SESSION_ID, F_ID));// Делаем агрегацию того, что нагруппировалиpipe = new Every( pipe, new BuildVPSE());
  • 31. Маленькая проблема №1: разные размерности набора полей группировки● Для одномерного отчета: ● (раздел)● Для двумерного: ● (раздел, пол)● Для трёхмерного: ● (группа товаров, товар, источник трафика)
  • 32. Решение проблемы разных размерностей: вложенные Tuple Конвертируем исходный поток, собирая и все поля из условия группировки в одно поле с вложенным Tuple: Единое поле,● Было: которому можно [ счётчик, раздел, … ] присвоить [ счётчик, раздел, пол, … ] название и задать это● Стало: название в [ счётчик, [раздел], …] условии [ счётчик, [раздел, пол], … ] группировки
  • 33. Проблема №2: code injection Нужно дать возможность выполнять на кластере в рамках первоначального преобразования строчки (Function в терминах Cascading) произвольный пользовательский код:// Вычисляем пользовательскую функциюpipe = new Each(pipe, new UserFunction(), Fields.ALL);
  • 34. Чем это плохо?● Функция может быть тяжелой и затратной● Разумеется, проблемы с безопасностью● Плохая локальность и много пересчёта: отчёты считаются, как правило, за большие периоды, а результат функции зависит только от конкретной строчки и может быть расчитан прямо при получении строчки
  • 35. Решение в реальном мире● Аналогично работе с сегментами, разделим процесс на 2 этапа: Вычисление Сайт Логи пользовательской функции Отчёты Расчёт пользовательских Вычисленные отчётов значения
  • 36. Этапы расчёта: первый этап● Производится как можно чаще (например, раз в час)● Расчёт значений вынесен в отдельный job – легко контролировать injection, устанавливать лимиты используемых ресурсов, выделять по JVM каждому● Пользовательский Java-код по необходимости на лету компилируется с помощью Janino
  • 37. Этапы расчёта: второй этап● Производится по необходимости ● Как правило – за отчётный период – раз в сутки, в неделю, в месяц и т.д.● Только выбирает и использует нужные заранее вычисленные значения● Не имеет никакого code injection● Имеет гарантированную алгоритмическую сложность и чётко прогнозируемое время выполнения
  • 38. Обеспечение безопасности выполнения чужого кода● Каждому счётчику – отдельный mapper ⇒ выделенный процесс JVM● Выполнение кода с максимально урезанными правами под Java security manager● Контроль за потребляемыми ресурсами средствами ОС● В перспективе – можно реализовать полноценную виртуализацию отдельных JVM
  • 39. Потенциальные угрозы● Выполнение ”опасных” действий (открытие сокетов, локальных файлов, запуск процессов, доступ к среде) ⇒ SecurityException● Перерасход ресурсов JVM ⇒ JVM аварийно завершается с OutOfMemoryException● Перерасход ресурсов процесса ОС (процессорное время) ⇒ ОС убивает JVM по исчерпании ресурса
  • 40. Пример пользовательского кодаpublic class SectionFirstPathComponent extends RST { @Override public void process(TupleEntry in, CVMap out) { String pagePath = in.getString(F_PAGE_PATH); long flag = in.getLong(F_FLAG); if (pagePath.length() >= 1 && ((flag & (FLAG_PAGE_EXTERNAL | FLAG_NOT_PAGE_VIEW)) ==0L)) { int p = pagePath.indexOf(/, 1); if (p == -1) { out.put("section", pagePath.substring(1)); } else { out.put("section", pagePath.substring(1, p)); } } }}
  • 41. Настройка пользовательского отчёта Настройка самого отчёта, т.е.:● что группировать● что агрегировать● как агрегировать● как отображать результат в веб-интерфейсе реализуется в виде простого YAML/JSON файла.
  • 42. Пример описания пользовательского отчётаecommerce.geo.region: Заказывается GroupBy gb: по 2 полям - geo.country - geo.region Заказывается сумма поля order.total sum: - order.total Заказывается cd: COUNT DISTINCT поля order.id - order.id
  • 43. Полная схема работы системы Вычисление ВычислениеСайт Логи польз. Значения польз. Битмаски сегментов функции сегментов Расчёт Расчёт Отчёты пользовательских Расчёт стандартных стандартных отчётов отчётов отчётов
  • 44. Что в итоге получили пользователи?● Сегменты могут создавать все пользователи из удобного конструктора в веб-интерфейсе● Продвинутые пользователи могут сами настраивать себе отчёты практически произвольной сложности, написав несколько строчек кода на Java и описав вид желаемого отчёта● Менее продвинутым пользователям это поможет сделать служба внедрения
  • 45. А что получили мы? Общий объем пользовательских отчётов ежедневно:● 100 мегабайт● 1.2 млн строчек● ~10000 отчётов
  • 46. Наша экономия● Обычный отчёт за сутки считается за время от ~3 до ~30 машиночасов* в зависимости от сложности● Все пользовательские отчёты считаются за один проход длиной 32-35 машиночасов* в сутки● 10000 x (3..30) = (30000..300000) vs (32..35)● Итого – экономия на 3-4 порядка * корректнее – ядрочасов
  • 47. Спасибо за внимание! Вопросы?http://www.openstat.ru/myakshin@openstat.ru