Обзор конференции Highload++ 2016
7 и 8 ноября 2016 года в Москве проходила конференция Highload++. Здесь я тезисно опишу те доклады, которые я смог посетить.
Поиск совпадений и дедупликация в потоке (Леонид Юрьев, Positive Technologies)
Проблема: очень много данных на входе, данные произвольны (не только текст), нужно найти дубликаты.
Долго рассказывал про алгоритмы и научные работы, но не объяснил, как именно они это используют. Сослался на секретность.
“Хорошая хеш-функция поменяет половину битов после изменения одного байта на входе”
Интересная идея: использовать двойное скользящее окно в потоковой обработке. Состоит из большого внешнего (которое может двигаться только в одном направлении) и маленького внутреннего (которое может двигаться произвольно в рамках внешнего).
Архитектура современного e-сommerce на примере Lamoda (Михаил Леонов)
Глобально код состоит из фронтэнда и бекэнда. Фронтэнд обрабатывает запросы посетителей, а бекэнд - это админка для склада и обработки заказов.
Активно используют микросервисы. На момент доклада их больше 60 штук. У каждого микросервиса несколько инстансов.
Фронэнд - это монолитный php-код, собирающий вместе данные из микросервисов. Пытаются писать так, чтобы он работал при падении/выключении отдельных микросервисов.
Пишут на PHP/Python/Go/Java/Lua:
- PHP - для бекэнда и части микросервисов.
- Python - для микросервисов
- Java - для какой-то обработки склада в недрах бэкенда.
- Lua - для написания модулей к nginx
- Go - х.з.
Для выкладки используют Docker и Ansible.
Организационная структура:
- В команду входят один PM, один тимлид и несколько разработчиков. Непонятно, входят ли QA
- Одна команда поддерживает 1-2-3 микросервиса.
- Команды между собой взимодействуют через PM-ов
- Есть несколько архитекторов “по направлениям”, через которых происходит состыковка архитектуры
У каждого сервиса свой протокол, описаный страничкой в Confluence, не всегда актуальной! Пытаются внедрить OpenAPI и Swagger.
Нейронные сети: практическое применение (Наталия Ефремова, NTechLab)
Самый известный продукт от NTechLab - FindFace.
В докладе Наталия рассказала про то, откуда взялись нейронные сети (это попытка смоделировать человеческий мозг) и какие задачи они могут решать. Пересказывать всё это не буду, будет полезнее просто посмотреть презентацию.
Успехи в распознавании изображений, которые появились в последние несколько лет, связаны с появлением Imagenet, большой базы изображений, размеченных по категориям (14М изображений, 22К категорий).
При работе с изображениями они разбиваются на небольшие блоки, каждый из которых соответствует одному входному нейрону.
Интерсный факт: при обучении нейронной сети возникают “сюрпризы” - отдельные её внутренние слои учатся разпозновать что-то, что их не учат распознавать (в примере были дороги).
“считается, что такой-то вид сети лучше решает такую-то задачу” означает, что кто-то раньше попробовал этот вид сети и получил хорошие результаты, но не означает, что какой-то другой вид сети не может дать результат лучше
A/Б-тестирование: от сегментирования до профита (Кирилл Котов, Superjob)
Интересная идея: периодически проводите A/A тест (показывать один и тот же вариант и как тестовый и как контрольный) для проверки работспособности всей инфраструктуры A/B-тестирования.
Один пользователь участвует только в одном тесте. Проводят тесты для авторизованных и для неавторизованных. Авторизованных пользователей делят (?) по user_id, неавторизованным вешают “вечную” куку. В БД Хранят данные по тестам только за последний год.
На файловом хранилище есть сырые данные за больший период для восстановления нужных данных или для проверки полученных результатов. Для проверки сезонности загружают эти данные в Vertica.
Назначьте ответственного, который будет знать про все проводимые тесты.
Не затягивайте разработку админки!
Микросервисы: опыт использования в нагруженном проекте (Вадим Мадисон, М-Тех)
Описание Текстовая расшифровка
Компания занимается отдачей видео для НТВ+ / МатчТВ. Активно используют микросервисы (на момент доклада их больше 250).
Для описания протокола использовали protobuf, затем gRPC, а затем перешли на JSON + JSON schema. Причины перехода: распространённость, простота и возможность работы через HTTP/2. Для версионирования используется /v{N}/ в урле. Для каждой версии есть своя JSON schema.
Стараются избегать частичной работоспособности сервиса - когда он то работает, то нет в зависимости от нагрузки на нём. Для этого у каждого сервиса есть свой rate limit. При его превышении circuit breaker, через который происходит обращение к этому сервису, начинает сразу отдавать ошибки.
Любой сервис работает в нескольких экземплярах. При возникновении проблем на одном из экземпляров его просто прибивают, а уже потом разбираются, что с ним происходило.
Для мониторинга используют Hystrix. В логах на продакшене пишут TraceId для того, чтобы можно было “склеить” данные по одному запросу к разным микросервисам и получить “debug mode” на продакшене.
Используют автоматическое масштабирование. Оно работает только для линейно масштабируемых сервисов (линейность предварительно проверяют нагрузочных тестированием пары инстансов). Для каждого такого сервиса определены два лимита - при достижении первого начинает готовиться новый экземпляр сервиса, при достижении второго - созданный экземпляр начинает работать. В зависимости от типа сервиса лимитом может быть CPU, RAM или сеть. Кажется, у сервиса может быть только один тип и он определяется вручную.
Есть decision maker, на входе у которого min и max лимиты по сервисам + текущая нагрузка. На выходе решение о увеличении или уменьшении числа работающих инстансов для конкретных сервисов.
Советы:
- у любого серсиса должно быть хотя бы два инстанса;
- не разбирайтесь с проблемным инстансом сервиса, а сначала прибивайте его, а уже потом разбирайтесь, что это было;
- собирайте метрики, которые просты и понятны;
- alert нужно посылать только тогда, когда нужна какая-то реакция.
События, шины и интеграция данных в непростом мире микросервисов (Валентин Гогичашвили, Zalando SE)
Доклад состоял из двух больших частей: про устройство Zalando и разработку общей шины данных. Первую часть я слушал внимательно, а вторую уже не очень.
Устройство Zalando
История развития: Magento => Java + хранимые процедуры => Микросервисы.
Мы переписали всё на Java, потому что мы знали Javа. Мы поставили везде Postgres, потому что я знал Postgres.
Возникли кадровые проблемы: люди стали уходить и перестали приходить в нужном количестве из-за используемого стека технологий.
Перестроили компанию на независимые команды. Команды сами выбирают себе технологии для микросервисов, но несут ответственность за выбор - при приблемах разбираются сами. Используют AWS для быстрого получения новых серверов.
Перед разработкой микросервиса нужно согласовать его протокол. Для этого существуют специальный guideline для создания протокола и “API гильдия” внутри компании, которая одобряет протокол.
В компании много open source (см. zalando.github.io и github). Основная причина - “люди более серьезно относятся к разработке и на выходе получатся более качественный продукт”.
Шина данных
Из-за большого количества микросервисов получается, что в проекте есть куча разнородных БД с фрагментами данных. Возникают проблемы при проведении ETL для BI.
Для решение они сделали единую “шину” Nakadi, в которую микросервисы пишут свои данные. Шину стали писать сами, но “с минимальными усилиями”: стараются брать готовые части инфраструктуры и использовать их. Как траспорт используют Apache Kafka, в качесте хранилища данных PostgreSQL, а качестве хранилища конфигов Zookeeper. Самописные части:
- реестр типов данных
- версионирование схем данных
- что-то еще - в этот момент я отвлёкся и перестал слушать
“Ваши менеджеры будут в восторге от аббревиатур ML (Machine Learning) и DDDM (Data Driven Decision Maker)”
“Каким бы ужасным Zookeeper не был, у нас он уже был”
Выбираем СУБД для хранения временных рядов (Павел Филонов, Лаборатория Касперского)
Доклад про инженерный подход к выбору хранилища данных.
Примеры инженерного подхода: мы уже работали с А, мы давно хотели попробовать B, мы в итернете читали про С.
Инженерный подход:
- сначала почитать
- выбрать важные критерии для своей задачи
- выбрать конкурсантов
- выбрать методику тестирования
- провести тестирование (на конкретном стенде)
- проанализировать результаты
Нужно критически относиться и уже имеющися обзорам и сравнениям (особенно от производителей конкретных СУБД).
Был интересный подход к сравнению отдельных критериев.
Собрать набор точек, привести их все или часть к линейной зависивости (через линейную регрессию или логарифмичесую шкалу), после чего померить тангенс наклона и взять его за значение конкретного критеря для конкретного конкурсанта.
Для выбора можно использовать перемножение матриц. Для этого нужно нормировать результат - взять максимальное значение за 1.0, остальные разделить на максимум. Результаты записываются в матрицу: в строках - значения для конкретной БД, а в столбцах - конкретные критерии. Отдельно делается вектор “значимости” конкретных критериев. После пермножения получается вектор итоговых результатов для каждого конкурсанта.
В презентации есть ссылки на несколько источников.
Архитектура растущего проекта на примере ВКонтакте (Алексей Акулович, ВКонтакте)
Обзорный доклад про ВКонтакте.
Исторически используют монолитный код на PHP (но думают о внедрении микросервисов). При росте нагрузки и объёма данных стали использовать горизонтальное масштабирование. Что делали?
- уменьшали свзяность данных (убирали join-ы и внешние ключи);
- разносили таблицы по разным серверам;
- шардированли данные (использовали “виртуальные шарды” - аналог наших “спотов”).
Отходят от использования MySQL и используют самописные специализированные хранилища для различных задач. Изначально все они работали по текстововму протоколу memcache-а. За каждым сервисов стоит кластер серверов, но доступ к нему происходит через прокси и с точки знения кода он выглядит как единое целое.
Вроде бы у них самописный прокси, но советовали аналогичный от Twitter: twemproxy
Через какое-то время отошли от протокола memcache, и стали использовать свой бинарный протокол для каждого сервиса. Для описания используют самописный аналог protobuf - TL proto. Сервисы умеют работать через UDP (или они реализовали свой “TCP” поверх UDP).
KPHP: сделали чтобы сэкономить на серверах для обработки запрсоов пользователей. Код собирается в бинарник, который представляет собой однопоточный сервер с epoll.
Советовали не использовать константные ключи memchache, т.к. все пользователи будут обращаться за ними в один мемкеш и это может привести в отказу системы.
Интересная идея: используйте разные кластеры для разных фич. Это поможет:
- быстро найти причину проблем при их возникновении;
- изолирует проблемы с одной фичей от всех остальных.
Архитектура поиска в Booking.com (Иван Круглов, Booking.com)
Доклад про эволюцию поиска отелей.
Есть жесткий SLA на время работы поиска.
Ищите ограничения / требования в вашей бизнес-модели
Для Booking: отстутствие номеров при бронированиие - не проблема, этому не нужна 100% точность.
Интересная идея: материализация всех возможных комбинаций результатов поиска.
Используют две БД: Inventory и Availability.
Inventory - это база номеров от отелей. Все изменения вносятся в неё. Содержит диапазоны, интересные отелям (грубо говоря: отель А сдает номер Б на новогодние праздники и хочет получить за это $1000)
Availability - это база для поиска. Содержит все возможные варианты, которые могут быть интересны конечным пользователям. Оптимизирована под быстрые выборки. Записи кластеризованы по Z order curve для того, чтобы рядом хранились записи об отелях, расположенных недалеко друг от друга.
Все изменения в Availability идут через очередь материализации. 1 изменение в Inventory может привести к 1000 изменений в Availability.
Есть quality check скрипт, который проверяет разсхождения и если они есть, то добавляет в очередь задание на перерасчет этого варианта в Availability-базе.
Данные шардировались по checkin date. Это работает из-за двух вещей: в поиске ограничено максимальное количество ночей (30) + в шардах есть перехлесты (когда одни и те же даты есть в нескольких соседних шардах).
При росте данных и нагрузки это перестало работать и хранилище переделали с MySQL на embedded-базу RocksDB. Данные режутся по “фичам” (моё название). Пример таких фич: город, наличие парковки и т.д. У каждой ноды есть in memory индекс, за счет чего они очень быстро работают. Отели шардированы по hotel_id % {shards_count}. У каждого шарда есть один мастер и несколько реплик. При поиске для каждой фичи случайным образом выбирается реплика, при ошибке делается retry (вероятно, на другую реплику). Взяли именно embedded базу из-за отсутствия накладных расходов на работу с сетью, а именно RocksDB из-за “стабильного random read performance при random write”.
По памяти: поиск обращается к ноде координатора, которая передаёт запрос куче баз по нужным фичам, получает от них результаты и склеивает их в ответ. На тяжёлых запросах это поиск стал работать быстрее, а на лёгких - медленнее.
Тестирование через мониторинг или холакратия на практике (Максим Чистяков, Ultimate-Guitar)
Рассказ про донельзя экстремальный способ ускорения разработки web-сайта.
В какой-то момент решили ограничить рост компании. Отказались от менеджеров, QA и стен в офисе и выкладывают изменения на продакшен 40-50 раз в день. При переходе были организационные проблемы:
“часть разработчиков не смогла двигаться достаточно быстро и нам пришлось с ними расстаться”
Проверка работоспособности выкладываемого - на самом разработчике, есть какое-то code review (был тяжелый вздох при рассказе про review, видимо есть проблемы). Писать тесты или нет - дело самого разработчика.
Любая фича разбивается на мелкие части, которые релизятся каждый день. Каждый разработчик каждый день релизит свои изменения сам (включая новичков в первую неделю). После выкладки они наблюдают за графиками ошибок и времени ответа, в случае проблем - откатывают выкладку. Всё автоматизировано, выкладка и откат происходит по кнопке в Jenkins.
Есть ключевые показатели, за которыми они следят после выкладки и есть определённые лимиты, при достижении которых выкладка считается ошибочной (например: больше десяти 500-ых ошибок за 10 минут, среднее время ответа за 2 минуты больше 200 мс)
Есть несколько дублирующихся систем мониторинга на случай сбоя в одной из них.
“В 4 утра в баре ты должен уметь не только накатить, но и откатить”
Нельзя сделать фичу без мониторинга, т.к. непонятно, что с ней происходит
Основная аудитория сайта в США, этому у них минимум трафика в рабочий день
Неясно, как они вылавливают логические ошибки в коде.
Работают по 5 часов в день, но есть нюансы:
“Мы работаем по 5 часов, чтобы люди не упарывались”
Все работают с 9.00 до 15.00. Основа - не отсиживание часов, а сконцентрированная работа на результат. Утром каждая малая команда намечает план работы на день. В субботу тоже работают, но с 10.00 до 14.00. При этом 6 сотрудников могут написать, что в субботу не придут по какой-либо причине. Если кому-то седьмому тоже нужно будет не работать в субботу, он договаривается с шестью, чтобы поменяться, обосновывая нужность для него этого дня, как выходного.
Your hero images need you: Save the day with HTTP2 image loading (Tobias Baldauf, Akamai Technologies)
Disclaimer: идти сюда не планировал, попал случайно и пропустил первые минут 20.
Доклад про использование в web-е разных видов JPEG с разными протоколами. Самое интересное в докладе - демонстрации загрузки страниц с кучей картинок и их результаты.
Есть два типа JPEG: baseline (“обычные”) и progressive. Progressive JPEG не грузятся быстрее baseline, но на глаз эта загрузка лучше воспринимается. Это происходит из-за разницы в их загрузке. Baseline грузятся сверху вниз и вы видите чёткую часть изображения, а прогрессивные показываются полностью, а потом обрастают деталями.
В HTTP/2 быстрее грузятся оба вида. Используйте HTTP/2)
See also: https://www.thewebmaster.com/dev/2016/feb/10/how-progressive-jpegs-can-speed-up-your-website/
Практическое применение WebWorkers (Алексей Фомкин, Data Monsters)
Пошёл для расширения кругозора. Вынес несколько вещей:
В JS есть параллелизм, который поддерживается большинством браузеров (92%).
В нём нет разделения переменных и кода между параллельно выполняющимися процессами. Это означает, что придется в каждом процессе объявлять/подключать все модули, которые нужны для работы.
При использовании подобного подхода нужно помнить о User experience. Пользователь привык, что когда SPA что-то делает, то новые действия блокируются, а при работе Webworker-ов блокировки работы со страницей нет и такие состояния нужно как-то обрабатывать.
Оптимизация работы с данными в мобильных приложениях (Святослав Иванов и Артём Миронов, Едадил)
Доклад про оптимизацию скорости приложения.
Едадил - это что-то про список акций и купонов. Грузят на клиент данные о всех активных акциях. На момент доклада объем апдейта - несколько мегабайт и становится всё больше. Хранили в файлах (ибо legacy и всего один разработчик), а теперь переходят к embedded БД.
Рассказали про несколько простых java-related оптимизаций кода в циклах:
- не делайте в цикле new Date() для сравнения дат, а сделайте строку с текущей датой перед циклом
- если вам нужно создать несколько однотипных объектов (в их случае - партнеров), то создавайте каждый объект один раз и используйте HashMap
- избегайте использования StringBuilder-ов при сборке debug message-й при отключенном дебаге
Интересная штука: язык Kotlin, на котором они написали Android-приложение.
В докладе был слайд, показывающий ТОП-10 самых популярных телефонов с Android-ом у их пользователей. Все 10 - это разные модели Samsung.