Для чего разработчику Flink-приложения инструменты профилирования, и почему надо избегать сериализации Kryo и динамической загрузки классов.
Используйте инструменты профилирования
Разработка и отладка высоконагруженных приложений требует специальных средств, позволяющих понять причины их медленной работы и повысить производительность. Такой анализ работы приложение называется профилированием и выполняется с помощью специальных средств – инструментов профилирования, профилировщиков или профайлеров. Профилирование может выполняться средствами фреймворка вместе с оптимизацией программы. Например, графики пламени в Apache Flink, о которых мы писали здесь, – один из вариантов профилирования потокового приложения средствами самого движка. О том, как улучшен встроенный профилировщик Java в новом выпуске фреймворка, читайте в новой статье.
Профилировщик позволяет определить, как долго выполняются определенные части программы, как часто они выполняются, может генерировать граф вызовов, чтобы идентифицировать те участки программы, которые работают больше всего и оптимизировать эти узкие места. Также инструменты профилирования обеспечивают анализ покрытия кода, выявляя его неиспользуемые участки.
Для профилирования Java-приложений есть много различных инструментов, но они могут оказывать следующие негативные эффекты на работу приложения при анализе его производительности:
- инструмент вносит искажения в работу программы, забирая часть процессорного времени. На таких искаженных данных невозможно сделать корректные выводы о работе программы.
- отсутствие сведений о поведении JVM, сборщика мусора и JIT-компилятора, когда профилировщик сам является Java-приложением.
Тем не менее, профилирование необходимо при Flink-приложений, чтобы решить проблемы с производительностью при обработке огромных объемов данных. Для этого можно использовать следующие инструменты профилирования:
- аsync-profiler — инструмент профилирования для JVM, который используется для отслеживания многих видов событий, включая циклы ЦП, выделение кучи Java и счетчики производительности, такие как промахи в кэше и ошибки страниц. Его поддержка графиков пламени особенно полезна для проверки того, где диспетчеры задач Flink задерживаются дольше всего.
- VisualVM – еще один инструмент профилирования JVM, который не требует сложной настройки. Его можно подключить этот инструмент к работающим экземплярам JVM, чтобы в реальном времени просматривать распределение кучи и использование ЦП. Это полезно для интерактивной отладки и исследования проблем с памятью.
- Комбинация jemalloc и jeprof. jemalloc – это реализация функции управления памятью malloc() общего назначения, принятая в качестве распределителя памяти Flink по умолчанию, начиная с версии 1.12 . С jemalloc работает профилировщик jeprof. При отладке Flink-приложения можно настроить диспетчеры задач и заданий на автоматический дамп профилей памяти, чтобы проанализировать их с помощью jeprof. Это полезно для наблюдения за тенденциями использования памяти в течение длительных периодов времени и помогает обнаруживать утечки памяти в key-value базе RocksDB, которая часто используется в качестве хранилища состояний потоковых приложений Apache Flink, о чем мы писали здесь.
- анализатор памяти Eclipse (Eclipse MAT) —анализатор кучи Java, используемый для проверки дампов кучи JVM на предмет использования памяти, поиска утечек памяти и пр. Его можно использовать для чтения дампов кучи, выдаваемых jemalloc, чтобы обеспечить дополнительный уровень анализа и интерпретация.
Впрочем, это не единственные инструменты профилирования, которые можно использовать с приложениями Apache Flink. Виртуальная машина Java, на которой основан этот фреймворк, имеет богатую экосистему инструментов профилирования, от базовых встроенных команд, таких как jmap, до комплексных сред, таких как Java Flight Recorder.
Избегайте сериализации Kryo
Flink предоставляет множество различных сериализаторов для различных структур данных. Когда Flink не удается сериализовать запись с помощью встроенного класса Case или сериализаторов AVRO, он возвращается к сериализации Kryo. Как мы уже отмечали здесь, cериализация Kryo очень медленная. Увидеть это падение в измеримых значениях позволяет инструмент профилировавния, например, async-profiler. Отключить возврат к Kryo позволяет конфигурация среды env.getConfig().disableGenericTypes(). При этом могут возникнуть различные сбои сериализации. Например, Flink не поддерживает сериализацию значений BigDecimal Scala, но может сериализовать значения Java. По умолчанию используется Java BigDecimal, чтобы избежать сбоя сериализатора. Эта проблема может возникнуть при работе с денежными значениями.
Flink не поддерживает сериализацию ADT Scala, реализованную некоторых объектов Case, обычно представляющих структуру данных, подобную перечислению. Однако, фреймворк поддерживает перечисления Scala.
Избегайте динамической загрузки классов
У Flink есть несколько способов загрузки классов для их использования в коде приложения:
- путь к классам Java – общий путь к классам Java, включающий библиотеки JDK и весь код (классы Apache Flink и некоторые зависимости) в папке /lib;
- компоненты плагина Flink – папка /plugins с кодом плагинов, которые механизм плагинов Flink динамически загружает один раз во время запуска;
- динамический пользовательский код – все классы, которые включены в JAR-файлы динамически отправляемых заданий через REST, CLI и веб-интерфейсы. Они загружаются и выгружаются динамически для каждого задания.
Поскольку динамический пользовательский код загружается в начале каждого задания, могут случиться сбои, если есть устаревшие ссылки на старые классы. Каждый раз, когда Flink-приложению надо восстановиться после временного сбоя, оно перезапускает задание и восстанавливается с самой последней доступной контрольной точки, а также перезагружает весь динамический пользовательский код. Во время этих перезапусков наблюдаются утечки памяти в виде ошибок java.lang.OutOfMemoryError: Metaspace. После того, как приложение перезагружается до исправления, объем используемой памяти Metaspace увеличивается.
Отключение динамической загрузки классов путем помещения кода приложения в общий путь к классам Java решает проблему. Это решение применимо, если кластеры Flink запускаются в режиме приложения, и не нужно поддерживать выполнение нескольких заданий в одном кластере. Подробнее про режимы запуска Flink-приложений мы писали здесь.
Узнайте больше про использование Apache Flink для потоковой обработки событий в распределенных приложениях аналитики больших данных и машинного обучения на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники