Измерение и мониторинг
клиентской части сайта у 150М
       пользователей

Павел Довбуш @ Badoo Development
         http://badoo.com/
Скорость сайта == деньги



- Известные рекомендации по оптимизации
- Много статей, книг
- Утилита Google Page Speed
Waterfall отчеты
Знакомая картинка?

                                 DOMContentLoaded   onLoad
   time




          Загрузка документа и
                статики
Рекомендации

- меньше HTTP запросов
- меньше DNS запросов
- кэширование
- CDN
- сжатие: minify, gzip
- оптимизация картинок, спрайты
Старт приложения



- оптимизировали загрузку статики
- Page Speed 100/100

- Достаточно ли этого?
Скорость сайта == деньги

                                 DOMContentLoaded           JS init   onLoad
   time




                                            инициализация
                                             приложения

          Загрузка документа и
                статики
Что важно пользователю



- явно не рейтинг в Page Speed :)
- Время до "рабочей страницы"
- Время полной загрузки ("часики" пропали)
Что важно разработчику

Общее время инициализации:
- Сколько секунд?
- Как найти узкое место?
- Переписывание какой страницы
(компонента) даст наибольший выигрыш?
Как увидеть реальное влияние
изменений?
- На глазок
- Перегрев гаджета :)
Как увидеть реальное влияние
изменений?
- Искусcтвенные тесты компонент   http://jsperf.com/
Как увидеть реальное влияние
изменений?
- Waterfall отчеты по запросу   http://www.webpagetest.org/
Как увидеть реальное влияние
изменений?
- Регулярный мониторинг   http://www.gomeznetworks.com/
Как увидеть реальное влияние
изменений?

- Измерения внутри приложения,
работающего у реальных пользователей

- Мы сами расставляем таймеры
Что измерять?

Самый простой набор:
- JavaScript/CSS download time
(cкорость скачивания)

- DOMContentLoaded
- JavaScript init time
(первичная инициализация)

- OnLoad
Что измерять?


<!DOCTYPE html>
<html><head>
<script>var start = Date.now();</script>
<script src=".../page.js"></script>
<script>var js_load = Date.now() - start;</script>
Что измерять?
<script>
document.addEventListener('DOMContentLoaded',
function(){
     var dom_ready = Date.now() - start;
}, false);

window.addEventListener('load',
function(){
     var on_load = Date.now() - start;
}, false);
</script>
Время инициализации приложения
- Архитектура приложения должна
содержать точки для замера

- У нас - одна точка входа
обертка вокруг DOMContentLoaded

- Асинхронная инициализация, подгрузка
компонентов - отдельно
Время инициализации приложения
var pages = [];

document.addEventListener('DOMContentLoaded',
function(){
     var begin = Date.now();
     for (var i=0; i < pages; i++){
         pages[i].init();
     }
     var js_init = Date.now() - begin;
}, false);
Время инициализации приложения
function Page(){
   pages.push(this);
}

function Example(){
   Page.apply(this);
}

Example.prototype.init = function(){
   // document is ready
};
Общая информация по всем
пользователям
- Как послать результаты измерений на
сервер?
   * Ajax или hidden-image

<script>
var img = new Image();
img.src = ".../log.php?stats=" +
   [ js_load, dom_ready, js_init, on_load ].join
(',');
</script>
Общая информация по всем
пользователям
   * Внедрение в следующие запросы отчета
о предыдущих: Cookies

<script>
document.cookie = "stats=" +
   [ js_load, dom_ready, js_init, on_load ].join
(',');
</script>
Данные в cookies следующего
хита



- негарантированная доставка
- последний хит теряется
- нет лишних запросов
- сборщик удаляет сохраненную куку
Сбор данных на сервере


- Сбор и агрегация на стороне сервера -
отдельная задача для миллиардов хитов в
сутки

Scribe, агрегация в MySQL, графики в RRD
Сбор данных на сервере
users          www cluster


        www1
                        scribe
                                 aggregation
        www2
                        scribe

        www3                      Scribe
                        scribe              php
                                  central         MySQL




        wwwN
                        scribe
Сбор данных на сервере

Несмотря на агрегацию, данных очень много
mysql> select TABLE_NAME,TABLE_ROWS,DATA_LENGTH,INDEX_LENGTH from
information_schema.TABLES where TABLE_NAME='CookieStatsGrouped';
+--------------------+------------+-------------+--------------+
| TABLE_NAME         | TABLE_ROWS | DATA_LENGTH | INDEX_LENGTH |
+--------------------+------------+-------------+--------------+
| CookieStatsGrouped |   55866578 | 3519037440 |    2808102912 |
+--------------------+------------+-------------+--------------+




        6Tb агрегированные за неделю!
Описание графиков
                       время                                время выполнения
                     выполнения                             в разных браузерах

                     2s
                     1s

  логирифмическая
                    250 ms
       шкала

                    200 ms


                    100 ms
                                                                   время
                                        час, день, неделя

                        Легенда: браузер, время выполнения

                        ie - Internet Explorer 6-9
                        ff - Firefox 2-4+
                        cr - Google Chrome
                        wk - Safari
                        op - Opera
Что можно увидеть на графиках
- Результаты оптимизации
Что можно увидеть на графиках
- Результаты оптимизации
Что можно увидеть на графиках
- ошибки в части браузеров
Что можно увидеть на графиках
- последствия редизайна
Детальные измерения



- тестовые пользователи
- отчет с точностью до компонент
- детальная статистика внутри компонент
- любые замеры подозрительных мест
Детальные измерения

                                DOMContentLoaded           JS init   onLoad
  time




                                           инициализация
                                            приложения

         Загрузка документа и
               статики
Детальные измерения
var pages = [];

document.addEventListener('DOMContentLoaded',
function(){
     for (var i=0; i < pages; i++){
         var begin = Date.now();
         pages[i].init();
         var cmp_init = Date.now() - begin;
         console.log( pages[i].name + ' - ' + cmp_init );
     }
}, false);
Профайлинг

- Список компонент с их "весами"

- Высоко-уровневый профайлинг

- Обоснованный выбор компонента для
оптимизации/рефакторинга
Детальная информация на
   тестовых пользователях
        IE6
                               FF2




список компонентов
    и их времен




    4 секунды!


                     0.5 сек
Мониторинг
Графики
сутки, неделя, месяц, год

Разбиение:
- по страницам
- по браузерам
- по странам
Графики
Графики
Франция на пражском ДЦ   Бразилия на майамском ДЦ
Планы развития
- Resource Timing - W3C
  (больше сетевой информации)

- Более детальная аналитика
Спасибо!


Вопросы?



Павел Довбуш
Head of Frontend department
dpp@corp.badoo.com
http://badoo.com/

Pavel Dovbush Toster