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

702 views

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
702
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

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

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

×