2016-06-24 2 views
2

Я пытаюсь профилировать приложение Akka, которое постоянно находится на уровне 100% использования процессора. Я взял образец процессора, используя visualvm. Образец указывает, что есть 2 потока, которые составляют 98,9% использования ЦП. 79% времени процессора было потрачено на метод под названием sun.misc.Unsafe. Other answers on SO говорят, что это просто означает, что поток ожидает, но на собственном уровне реализации (вне jvm).Приложение Akka IO потребляет 100% cpu

В вопросах, подобных моим, люди были told to look elsewhere, не указав особенности. Где я должен посмотреть, что вызывает спад процессора?

Приложение представляет собой сервер, который в основном использует Akka IO для прослушивания соединений сокетов TCP.

+0

Вы говорите, что вы взяли образец ЦП. Что ты конкретно имеешь ввиду? –

+0

sun.misc.Unsafe - это не метод, это класс. Продемонстрируйте полную трассировку стека. –

ответ

2

Не видя какого-либо исходного кода или даже не зная, о каком канале IO вы говорите (сокеты, файлы и т. Д.), Очень мало информации о том, что каждый может вам дать.

У меня есть некоторые общие предложения.

Во-первых, вы должны использовать реактивные методы и реактивный IO в своем приложении. Эта проблема может возникнуть из-за того, что вы проверяете статус какого-либо ресурса в узком цикле или используете блокирующий вызов, когда вы должны использовать реактивный. Это, как правило, анти-шаблон и производительность, потому что вы можете проводить циклы CPU, ничего не делая, кроме «активного ожидания». Я рекомендую двойную проверку для:

  • избирательного ресурса
  • блокировки вызовов
    • системы вызывает
    • диска флеши
    • ждет на Future, когда это будет уместно map вместо этого

Во-вторых, вы не должны использовать Mutexes или другую синхронизацию потоков в своем приложении. Если да, тогда вы можете страдать от живого замка. В отличие от мертвых замков, live-locks проявляются с такими симптомами, как 100% -ное использование ЦП, поскольку потоки постоянно блокируют и разблокируют примитивы параллелизма, пытаясь «поймать их всех». Wikipedia имеет хорошее техническое описание того, как выглядит живой замок. При использовании Akka вам не нужно будет использовать Mutexes или примитивы синхронизации нитей. Если вы тогда, вам, вероятно, придется перепроектировать свое приложение.

В-третьих, вы должны дросселировать IO (а также обработку ошибок, например, попытки повторного соединения). Эта проблема может возникать, потому что вашей системе не хватает эффективного дросселирования. Часто с каналами передачи данных мы оставляем их пропускную способность без ограничений. Однако это может стать проблемой, когда этот канал достигает 100% насыщенности и начинает красть ресурсы из других частей системы. Это может произойти, например, если вы перемещаете большие файлы без разумного ограничения.

В качестве альтернативы вам также необходимо активировать попытки повторного подключения при возникновении любых ошибок, а не повторять попытку немедленно. Многие системы попытаются повторно подключиться к серверу, если они потеряют соединение. Хотя это обычно желательно, это может привести к проблемному поведению, если вы используете стратегию наивного пересоединения.Например, представьте себе, сетевой клиент, который был написан так:

class MyClient extends Client { 
... other code... 
    def onDisconnect() = { 
    reconnect() 
    } 
} 

Каждый раз, когда клиент отсоединяется по любой причине, он будет пытаться восстановить соединение. Вы можете увидеть, как это приведет к жесткому циклу между кодом обработки ошибок и клиентом, если отключен Wi-Fi-выход или сетевой кабель.

В-четвертых, ваше приложение должно иметь четко определенные источники данных и раковины. Ваша проблема может быть вызвана «циклом данных», то есть некоторым набором аккских актеров, которые просто отправляют сообщения следующему актеру в цепочке, а последний актер отправляет сообщение первому актеру в цепочке. Удостоверьтесь, что у вас есть четкий и четкий способ ввода сообщений и выхода из системы.

В-пятых, используйте соответствующие профили и приборы для вашего применения. Прикрепите приложение к Kamon или библиотеке Metrics Coda Hale.

Поиск подходящего профайлера будет сложнее, поскольку мы, как сообщество, должны далеко продвинуться в разработке зрелых инструментов для реактивных приложений. Лично я нашел visualvm полезной, но не всегда чрезвычайно полезной для обнаружения путей кода, связанных с ЦП. Проблема в том, что профилировщики выборки могут собирать данные только в том случае, если JVM достигает безопасного места. Это может привести к смещению определенных кодов кода. Исправление заключается в использовании профилировщика, который поддерживает AsyncGetStackTrace.

Удачи! И, пожалуйста, добавьте больше контекста, если сможете.