Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Подсчет уникальных
комбинаций на примере
статистики групп в
Одноклассниках
Александр Шарак
Руководитель
отдела статистики
...
Задача
• Необходимо посчитать «уники» для отображения на графиках
в разделе «Статистика» для администраторов групп
Задача
• Надо посчитать, сколько у нас уникальных комбинаций такого
типа:
• группа, пол, возраст
• группа, тип активности
...
Типичные ошибки подсчетов
• Данные не должны дублироваться:
• меняется возраст
• меняется место жительства
• меняется пол
...
Выбор платформы

• Статистика должна быть точной.
• Подсчёты «задним числом» другим алгоритмом.
• Подсчёты должны быть быс...
Наш выбор
• Учитывая:
• требования
• доступные человеческие ресурсы и их компетенцию

• Выбрали:
• MS SQL 2012 Always On a...
В SQL всё просто!
• Select groupid, country, count(distinct userid)
from table
where timestamp between @datefrom and @date...
Однако объёмы не маленькие
• Более 400 000 активных групп в день.
• Более 1 000 000 активных групп в год.
• Более 800 000 ...
Как SQL считает «уники»
• Select groupid, country, gender, count(distinct userid)
from table
where timestamp between @date...
Как SQL считает «уники» при не
достаточной памяти
• Подсчеты делятся на более мелкие части и промежуточные результаты (хеш...
Упрощаем задачу для SQL
• Необходимо, чтобы селекты укладывались в память
• Самое простое - делим все группы на несколько ...
Доставка логов
• На сервере, куда параллельными потоками пишется много
данных, делать серьезные подсчеты невозможно.
• Пос...
Выкачка логов из «буфера»
• С большой периодичностью в одном потоке выкачиваем данные
из «буфера».
• Обработку строковых т...
Выкачка логов из «буфера»
• Сделали кластерный индекс по времени события с партициями
по дням.
• Такой индекс нам позволяе...
Как передать результаты обратно
на сайт
• Full dump:
•

легко реализовать;

•

годится только для небольшого объёма данных...
Топология
Система
групп

Буфер

Буфер
резерв
•

MS SQL Server
•
•
•
•

80 GB RAM
2 CPU (6 ядер) (мощные)
Temp db – SAS-дис...
Big Fail
• Сначала всё, как обычно, работало достаточно быстро.
• Но со временем система начала все больше тормозить:
•
•
...
Big Fail

•

И всё равно надо было предпринимать шаги по масштабированию, так как мы понимали, что долго так не
протянем.
О масштабируемости
• Масштабируется MS SQL AlwaysOn HA group легко:
•

можно добавить в кластер secondary сервера для подс...
Эффективный алгоритм
• Мы придумали быстрый алгоритм, как при помощи Merge Sorta файлов
посчитать «уники», нагружая IO и C...
Выгрузка данных в файлы
• Из базы данных в память выкачиваем данные за последний закрытый период
(например, день), отсорти...
день
#1

день
#2

день
#3

день
#4

день
#5

день
#6

день
#7

каждый файл отдельно уже отсортирован по ID_Group, ID_User
...
Распараллеливаем
• Данный алгоритм работает только в одном потоке, то есть, на одном ядре.
• Поэтому мы и создавали не 7 ф...
Топология
Система
групп

Буфер

Буфер
резерв

•

MS SQL
Primary

MS SQL
Secondary
(mirror)

.NET
«уники»

.NET
«уники»

Дв...
Нагрузка на CPU

•

CPU не нагружен на 100% потому, что есть дисковая очередь.
Ускоряем ещё больше
• Днем, когда сервер отдыхает, можем высчитывать агрегат за 364 дня. Потом
после полуночи надо будет с...
Tips and Tricks
• Для подсчета «уников» за 365 дней нам надо открыть много файлов – 365x24
(число ядер). Необходимо под ка...
Итоги
• Мы вынесли подсчеты из MS SQL и используем его только как хранилище. К тому
же используем не оптимально, так как н...
Итоги
• «Уники» за 365 дней мы можем посчитать за 4 часа на одном сервере, а
потенциально можем посчитать менее чем за час...
Спасибо за
внимание!
Александр Шарак
Руководитель отдела статистики
Одноклассники
aleksandr.sharak@odnoklassniki.ru
Upcoming SlideShare
Loading in …5
×

Александр Шарак, "Одноклассники"

1,136 views

Published on

HighLoad++ 2013

  • Be the first to comment

Александр Шарак, "Одноклассники"

  1. 1. Подсчет уникальных комбинаций на примере статистики групп в Одноклассниках Александр Шарак Руководитель отдела статистики Одноклассников
  2. 2. Задача • Необходимо посчитать «уники» для отображения на графиках в разделе «Статистика» для администраторов групп
  3. 3. Задача • Надо посчитать, сколько у нас уникальных комбинаций такого типа: • группа, пол, возраст • группа, тип активности • Каждый тип комбинаций надо посчитать за разные периоды: • • • • • • • час 6 часов сутки текущие 24 часа последние 7 дней календарный месяц последние 365 дней
  4. 4. Типичные ошибки подсчетов • Данные не должны дублироваться: • меняется возраст • меняется место жительства • меняется пол • Ну и конечно нельзя просто суммировать данные по дням, чтобы получить данные за неделю.
  5. 5. Выбор платформы • Статистика должна быть точной. • Подсчёты «задним числом» другим алгоритмом. • Подсчёты должны быть быстрыми, не обязательно в realtime: • Статистика за текущие 24 часа должна быть готова раз в час (для начала). • Статистика за закрытые периоды, например 1 астрономический час, должна быть готова за 15 минут. • Статистика за последние 365 дней должна быть готова «утром». • Должна быть возможность запросить новые данные по всем группам или все данные за любую дату по отдельно взятой группе. • Подсчёты должны быть экономными. • Разработка системы должна быть быстрой. • Данные должны быть доступны для внутреннего анализа.
  6. 6. Наш выбор • Учитывая: • требования • доступные человеческие ресурсы и их компетенцию • Выбрали: • MS SQL 2012 Always On availability group • Некоторые сомнения у нас были, особенно про подсчет статистики за последние 365 дней.
  7. 7. В SQL всё просто! • Select groupid, country, count(distinct userid) from table where timestamp between @datefrom and @dateto group by groupid, country
  8. 8. Однако объёмы не маленькие • Более 400 000 активных групп в день. • Более 1 000 000 активных групп в год. • Более 800 000 000 действий в день. • Для подсчета «уников» за последние 365 дней «тупым подходом» необходимо обработать более 200 000 000 000 записей каждый день.
  9. 9. Как SQL считает «уники» • Select groupid, country, gender, count(distinct userid) from table where timestamp between @datefrom and @dateto group by groupid, country, gender • Алгоритм: • Считываются данные по кластерному индексу. • • Данные делятся на столько частей, сколько доступно ядер. Каждый поток создает хеш-таблицу: (hash key, (groupid, country, gender, user), count). Каждый поток из предыдущей хеш-таблицы создает новую: (hash key, (groupid, county, gender), count). Хеш-таблицы объединяются и выдается результат. • • • Хеш-таблица для первоначального агрегирования может получиться огромной и в памяти не уложится.
  10. 10. Как SQL считает «уники» при не достаточной памяти • Подсчеты делятся на более мелкие части и промежуточные результаты (хеш -таблицы скидываются в temp db на диск). • SQL-сервер делает следующие итерации: • • • • • • • считываются данные по кластерному индексу; данные делятся на столько частей, сколько доступно ядер; каждый поток создает хеш-таблицу; если памяти не хватает, то хеш-таблица скидывается на диск и берётся следующая пачка данных; потом хеш-таблицы считываются с диска и объединяются; если опять не хватает памяти, то опять всё скидывается на диск; и так до тех пор, пока не получается результат. • «Со стороны» это выглядит так: • • • • сначала наблюдаются бешеные процессы чтения и высокая нагрузка на CPU; процессы чтения прекращаются, но нагрузка на CPU все еще высокая; нагрузка на CPU падает и начинается интенсивная запись на диск; эти три шага повторяются много раз. • В результате: • • подсчеты очень медленные; IO-система так нагружена, что параллельные процессы «проседают».
  11. 11. Упрощаем задачу для SQL • Необходимо, чтобы селекты укладывались в память • Самое простое - делим все группы на несколько частей и считаем «уники» для каждой части отдельно. • • Данные надо хранить с кластеризацией по ID групп, что вызовет проблемы при загрузке – сплошные вставки и фрагментация. Исторические данные нельзя было бы удалить. Если данные кластеризовать по дате, то для каждой части придется делать full scan за весь период • Делается много лишних операций, описанных ниже • Для «уников» за большие периоды надо использовать результаты подсчетов за меньшие периоды, посчитанные ранее, например: • • для подсчета часа использовать минутные «уники»; для подсчета месяца использовать суточные «уники».
  12. 12. Доставка логов • На сервере, куда параллельными потоками пишется много данных, делать серьезные подсчеты невозможно. • Поставили «буферную» базу для принятия логов и передачи дальше системе статистики Система групп Буфер Система статистики
  13. 13. Выкачка логов из «буфера» • С большой периодичностью в одном потоке выкачиваем данные из «буфера». • Обработку строковых типов не делаем, так как это крайне неэффективно. • Преобразование строк в цифровые значение (нормализация данных) тоже, соответственно, не делаем. • Получаем только целые числа (ID сущностей) и даты. COLUMN_NAME DATA_TYPE Registered smalldatetime ID_Group bigint ID_User bigint ActionType tinyint VisitType tinyint MemberType tinyint
  14. 14. Выкачка логов из «буфера» • Сделали кластерный индекс по времени события с партициями по дням. • Такой индекс нам позволяет быстро записать и прочитать данные с постепенно возрастающим временем события. • Время сброса данных растет пропорционально росту активности в группах, но не пропорционально росту размера всей таблицы. • Однако данные за один квартал мы храним в отдельной базе: • чтобы бэкапы происходили «быстро»; • чтобы «старые» данные можно было эффективно убрать в архив.
  15. 15. Как передать результаты обратно на сайт • Full dump: • легко реализовать; • годится только для небольшого объёма данных. • По changetime: • • • трудно отследить удаления (например, когда в группе всего один пользователь и он стал старше); если изменилась одна запись в группе, то надо пометить все связанные; постоянный апдейт колонки changetime и деградация индекса. • Лента изменений: • • • в ленту идут только инсерты; удаления отслеживать не надо; сайт получает полный комплект измененных статистик, которым можно заменить старый комплект без дополнительно обработки.
  16. 16. Топология Система групп Буфер Буфер резерв • MS SQL Server • • • • 80 GB RAM 2 CPU (6 ядер) (мощные) Temp db – SAS-диски Данные – массив из SATA-дисков MS SQL Primary MS SQL Secondary (mirror)
  17. 17. Big Fail • Сначала всё, как обычно, работало достаточно быстро. • Но со временем система начала все больше тормозить: • • • • группы стали популярнее; расчеты стали немного сложнее; данных за большие периоды накапливалось все больше (особенно для подсчета последних 365 дней); подсчеты «уников» за большие периоды так начали нагружать IO, что начали проседать параллельные процессы загрузки данных и подсчеты маленьких периодов. • Поэтому мы решили, что MS SQL secondary (mirror), который доступен в режиме read only, должен заняться полезным делом: • Сделали так, чтобы сервис забирал результаты не с primary, а с secondary сервера. • В результате: • нагрузка на IO систему сильно снизилась.
  18. 18. Big Fail • И всё равно надо было предпринимать шаги по масштабированию, так как мы понимали, что долго так не протянем.
  19. 19. О масштабируемости • Масштабируется MS SQL AlwaysOn HA group легко: • можно добавить в кластер secondary сервера для подсчетов. • Но это дорого стоит. • Мы начали думать: можем ли мы посчитать «уники» за большие периоды эффективней, чем MS SQL? • Тогда мы бы могли в MS SQL оставить только то, что хорошо и быстро работает: • • • хранилище для исходных данных; хранилище для результатов; подсчеты «уников» за маленькие периоды – до часа.
  20. 20. Эффективный алгоритм • Мы придумали быстрый алгоритм, как при помощи Merge Sorta файлов посчитать «уники», нагружая IO и CPU по максимуму, при этом делая минимум лишних операций и используя минимум памяти. • Далее рассмотрим частный случай, когда мы из семи дневных результатов высчитываем недельные «уники».
  21. 21. Выгрузка данных в файлы • Из базы данных в память выкачиваем данные за последний закрытый период (например, день), отсортированные по (groupid, userid). • Записываем эти данные в 100 файлов, распределяя по groupid mod 100, чтобы все записи одной группы попали только в один файл. Это необходимо для распараллеливания. • Формат файлов – бинарный, чтобы мы могли четко знать. где именно начинается и заканчивать одна запись. • Мы пробовали использовать json и csv форматы но сразу от них отказались, потому что на парсинг этих файлов уходила львиная доля мощностей CPU. • Исходные данные в таком формате: • • • За один день – 3 Gb За 7 дней – 21 Gb За 365 дней – 1.1 Tb
  22. 22. день #1 день #2 день #3 день #4 день #5 день #6 день #7 каждый файл отдельно уже отсортирован по ID_Group, ID_User (1x вначале) сортируем список открытых файлов по ID_Group, ID_User первой считанной записи (дальше в цикле) отдаем дальше запись с наименьшим ID_Group, ID_User берем следующую запись из того файла, чья запись «ушла» перемещаем файл в списке файлов на место, соответствующее следующей считанной записи Отсортированный список всех данных по ID_Group, ID_User Накопленные данные за предыдущую группу можно считать готовыми, когда начинаются данные про следующую группу ID_Group ID_User ActionType G1 U1 7 G1 U1 7 G1 U2 5 G2 U2 G2 U3 данные про поведение конкретного пользователя в рамках конкретной групы
  23. 23. Распараллеливаем • Данный алгоритм работает только в одном потоке, то есть, на одном ядре. • Поэтому мы и создавали не 7 файлов, а 100 комплектов по 7 файлов, распределяя по groupid mod 100. • И запустили подсчеты в столько потоков, сколько было ядер на сервере – 24. • Каждый поток обрабатывал отдельный комплект файлов. • После завершения подсчетов все результаты записываем (bulk insert) в MS SQL для передачи далее в «прод». • А выгруженные файлы не удаляем, а оставляем для подсчетов следующих периодов, но не дольше 365 дней. • «Уники» за 7 дней высчитываем за 3 минуты.
  24. 24. Топология Система групп Буфер Буфер резерв • MS SQL Primary MS SQL Secondary (mirror) .NET «уники» .NET «уники» Два .NET сервера для «уников» - для HA. Оба делают одно и то же.
  25. 25. Нагрузка на CPU • CPU не нагружен на 100% потому, что есть дисковая очередь.
  26. 26. Ускоряем ещё больше • Днем, когда сервер отдыхает, можем высчитывать агрегат за 364 дня. Потом после полуночи надо будет сделать Merge Sort всего двум файлам. Ускорим в 5 раз. • Для подсчетов «уников» за последние 364 дня можно использовать комбинацию дневных и месячных агрегатов. Ускорим на 25%. • Для подсчетов можем использовать оба .NET сервера (первый сначала подсчитывает чётные группы, второй – нечётные). Ускорим в два раза.
  27. 27. Tips and Tricks • Для подсчета «уников» за 365 дней нам надо открыть много файлов – 365x24 (число ядер). Необходимо под каждый FileHandle выделять такой размер буфера, чтобы он не превышал некую MagicConstant (~1Gb). Иначе Windows Server начинает делать swap памяти. • Файлы, в которых храним числовую (IDs) информацию в бинарном виде, не стоит пытаться зиповать. • Если шедулируете подсчеты, используя Windows Task Scheduler, то по умолчанию у тасков стоит низкий приоритет на ресурсы. Через UI его повысить нельзя – надо экспортировать XML дефиницию таска, повысить в нем соответствующую настройку и импортировать обратно.
  28. 28. Итоги • Мы вынесли подсчеты из MS SQL и используем его только как хранилище. К тому же используем не оптимально, так как нам надо, чтобы данные можно было бы хранить с кластеризацией по (groupid, userid). • То есть использование MS SQL не обосновано. Вместо него мы будем использовать или Open Source базы, или переделаем всё на обработку файлов в .NET. • .NET и Windows Server 2008 R2 показал себя как хорошая платформа для обработки данных и файлов • • • быстрая и стабильная с хорошим файл-кешем удобный язык программирования для аппликации параллельной обработки информации.
  29. 29. Итоги • «Уники» за 365 дней мы можем посчитать за 4 часа на одном сервере, а потенциально можем посчитать менее чем за час. • Это в десятки раз быстрее, чем может MS SQL. • Подсчеты за меньшие периоды занимают несущественное время. • Количество серверов, необходимых для подсчетов – 2 (+2 для HA). • Количество трудозатрат – 3 человеко-месяца. • А если делать сразу всё правильно – 1 человеко-месяц.
  30. 30. Спасибо за внимание! Александр Шарак Руководитель отдела статистики Одноклассники aleksandr.sharak@odnoklassniki.ru

×