Почему select () занимает в моей программе так много процессорного времени?

У меня есть несколько приложений Java, использующих MINA, и все они используют 20 потоков MINA. Одно приложение обслуживает около 10 000 одновременных подключений, которые обычно простаивают, но иногда получают ввод. 20, вероятно, является разумным количеством потоков для этого приложения, хотя я точно не профилировал его (что касается этого вопроса). Другое приложение обслуживает только около 15 подключений одновременно, но инициирует операции ввода-вывода, поэтому они очень заняты и в любом случае имеют 20 потоков MINA, что, очевидно, слишком много.

Для меня странно то, что оба приложения всегда отводят около 30%, а иногда и 60% своего процессорного времени методу MINA select (), профилированному в VisualVM. Стек вызовов выглядит так:

java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:228)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:81)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
- locked <40ca5d54> (a sun.nio.ch.Util$2)
- locked <24649fe8> (a java.util.Collections$UnmodifiableSet)
- locked <3fae9662> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
at org.apache.mina.transport.socket.nio.NioProcessor.select(NioProcessor.java:72)
at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.java:1093)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

Похоже, это основано на напряженном опросе, который мне кажется неправильным.

Стоит ли мне волноваться, когда я вижу такое большое число? Что вызывает это? Это что-то, что мне нужно оптимизировать, или это больше похоже на режим сна или бездействия? Если это больше похоже на режим сна, у него каким-то образом запланирован более низкий приоритет, чем у другой работы ЦП?

Обновление: этот поток кажется той же проблемой. Я последовал его совету и теперь использую Java 1.7.0_45, но я все еще вижу, что select занимает до 90% процессорного времени в приложении с 10 тыс. Подключений.

Мы используем MINA 2.0.4, что означает, что эта соответствующая ошибка исправлена.


person djechlin    schedule 09.12.2013    source источник
comment
Какую версию MINA вы используете? возможно, это ошибка в NioProcessor, issues.apache.org/jira/browse/DIRMINA-678   -  person vzamanillo    schedule 24.12.2013
comment
@vzamanillo мы находимся на версии 2.0.4; он сказал, что исправлено в 2.0.3.   -  person djechlin    schedule 24.12.2013
comment
Возможно, это связано с другой ошибкой, решенной в 2.0.5, issues.apache.org/jira/ просмотр / DIRMINA-681   -  person vzamanillo    schedule 26.12.2013


Ответы (4)


К сожалению, это неправильная интерпретация чисел.

Я сталкивался с этой ситуацией много раз (и задаю вопрос по stackoverflow тоже).

Основная причина в том, что VisualVM не показывает правильное время процессора. Он показывает процент времени потока в состоянии RUNNING. Но из документации на Thread.State:

Состояние потока для работающего потока. Поток в состоянии выполнения выполняется на виртуальной машине Java , но он может ожидать других ресурсов от операционной системы, например процессора.

Это именно то, что происходит. Фактически, поток заблокирован внутри epoll_wait() вызова ОС. В Linux есть несколько способов подтвердить, что это так.

strace'ing поток

$ strace -tttT -f -p [thread-id]

Идентификатор потока можно получить из вывода jstack:

$ jstack [java-pid]
[...]
"Netty Builtin Server 1" #17 prio=5 os_prio=31 tid=0x00000001013dd800 nid=0xe12f runnable [0x0000700001fe4000]
  java.lang.Thread.State: RUNNABLE
  at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
  at sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.java:198)
[...]

в этом случае идентификатор потока 0xe12f (должен быть преобразован в десятичный). Вы увидите, что большую часть времени поток будет находиться в epoll_wait() вызове.

pidstating поток

$ pidstat -tu -p [java-pid] | grep [thread pid]

вы увидите, что у этого потока мало системного времени, а также пользовательского процессорного времени, что означает, что он не потребляет процессор.

опрос состояния потока с использованием ps

$ ps -eL -o pid,tid,state | grep [thread-id]

вы увидите большую часть времени поток в состоянии S или Sl (прерывистый сон) вместо R (работоспособен).

В конце концов, вам не стоит беспокоиться об этом, если с сервисом нет проблем в работе.

person Denis Bazhenov    schedule 25.05.2016
comment
Звучит хорошо, но следующий вопрос - как настроить профиль процессора. (К вашему сведению, я больше не работаю над этим кодом, поэтому не могу проверить, сработало ли что-то.) - person djechlin; 25.05.2016
comment
VisualVM подойдет так же, как Java Flight Recorder. Но только для потоков, ограниченных ЦП., Что может быть подтверждено pidstat. К сожалению, универсального метода не существует. Следует использовать общесистемные утилиты (например, pidstat, vmstat), а также общесистемные (JFR, VisualVM, jstack). - person Denis Bazhenov; 26.05.2016
comment
@DenisBazhenov RUNNABLE поток Java по-прежнему потребляет процессор (пространство пользователя), даже связанный собственный поток находится в состоянии S и не использует процессор. потому что он выполняется в vm (может быть, вращается для возврата нативного io) Я прав? - person hakunami; 27.04.2017
comment
@hakunami не совсем так, JVM имеет отображение 1: 1 между потоком JVM и потоком ОС. Поэтому, если поток ОС находится в спящем режиме (состояние S), поток JVM также спит и не может потреблять какой-либо процессор, в конце концов, это один и тот же поток. - person Denis Bazhenov; 04.05.2017
comment
См. Подробный пост Брендана Грегга brendangregg .com / blog / 2014-06-09 / - person Jarek Przygódzki; 02.08.2019
comment
Кстати, есть хороший профилировщик сэмплера, который основан на информации о производительности Брендана Грегга и пытается копаться в собственных вызовах ОС github.com/jvm-profiling-tools/async-profiler - person Dima Fomin; 06.12.2019

Во-первых, хорошо, что у обоих приложений одна и та же проблема; это, вероятно, указывает на то, что проблема связана либо с JVM, либо с ОС, а не с вашим приложением :-)

Как упоминал jzd, у nio.select() были проблемы. Умножение {различных версий Java} x {различных платформ, версий ядра} делает эту проблему повсеместной. Надеюсь, вам понравится один из этих вариантов:

  • Если вы работаете в Linux, попробуйте 2.6 ядро ​​на всякий случай, если вы используете 2.4

    , если ошибка похожа на: http://bugs.sun.com/view_bug.do?bug_id=6670302

  • Используйте старую версию JRE / JDK, а не последнюю версию!

    , т.е. вернуться к JRE 6 / JDK 6 вместо 7.

Пытаться

  • {более старая версия JRE (6), более старая версия ядра Linux} или
  • {более новая версия JRE (7), более новая версия ядра Linux}

вместо того, чтобы смешивать их, как в {old, newer} или {newer, old}.

person vijucat    schedule 25.12.2013
comment
На ядре версии 3.2. - person djechlin; 05.02.2014

Одно приложение опрашивает 10 000 подключений, используя очень мало ЦП на подключение, но все вместе это может составить значительную долю времени ЦП. Все, что делает приоритет, - это позволить какой-то другой работе первой встать в очередь.

Другое приложение, которое имеет меньше подключений, но выполняет больше проблем с подключением, также может показывать более высокий процент, но оно должно показывать меньшую долю времени ожидания и более высокую долю загрузки ЦП.

person Mike Dunlavey    schedule 09.12.2013

Как и ответ на связанный вопрос, распространенная проблема - старые ошибки JDK. Поскольку сейчас вы используете обновленную версию, я думаю, что это может быть узкое место в оборудовании.

Вот ссылка на проблему Glassfish, в которой описывается возможность того, что оборудование (сеть и серверы) может быть источником проблемы.

https://www.java.net//forum/topic/glassfish/glassfish/glassfish-31-deadlock-epollarraywrapperepollwait-how-handle

Кроме того, вот еще один похожий вопрос, на который пока нет ответа: SelectorImpl ЗАБЛОКИРОВАН

person jzd    schedule 20.12.2013