Mysql jconnector тратит 50% времени на com.myql.jdbc.utils.ReadAheadInputStream.fill()

Я профилирую мое приложение, которое использует Spring + Hibernate + mysql-java-connector. Визуальный показывает, что более 50% процессорного времени стоит в com.myql.jdbc.utils.ReadAheadInputStream.fill(), когда есть 1000 параллельных соединений, выполняющих чтение.

Есть ли какая-нибудь оптимизация, чтобы сделать ее быстрее?

Ответ 1

VisualVM подсчитывает поток, используя время CPU, когда JVM считает его работоспособным. Это означает, что любой поток, не ожидающий блокировки, считается запущенным, более или менее, включая потоки, ожидающие ввода/вывода в ядре! Здесь происходит большая часть использования ЦП в com.myql.jdbc.utils.ReadAheadInputStream.fill(). Таким образом, вместо проблемы с процессором у вас есть проблема ввода-вывода.

Есть несколько вещей, которые вы можете сделать на стороне JVM, но не так много простой оптимизации:

  • Измените размер пула подключений. 1000 одновременных запросов много. Если ваш экземпляр MySQL не будет действительно массивным, он будет иметь проблемы с этим уровнем загрузки и будет много времени перебирать между запросами. Попробуйте удалить размер пула, до 250 или даже 50, и отметьте там.
  • Выполнять меньше или меньше запросов. Если ваше приложение мало, может быть тривиально очевидно, что каждая строка из каждого запроса необходима, но, может быть, ваше приложение больше этого. Являются ли разные места, которые запрашивают одни и те же данные, или могут быть объединены два разных запроса в один, который удовлетворит оба?

Ответ 2

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

Не в последнюю очередь убедитесь, что вы используете последнюю версию Hibernate ORM. Мы сделали версию 5.0+ намного более умной, чем предыдущие версии, особенно в отношении повышения производительности;-) Усовершенствования применяются ежедневно, так что поддерживать актуальность или, по крайней мере, пробовать последнюю можно легко выиграть.

Ответ 3

Трудно ответить на ваш вопрос без дополнительной информации. Вот некоторые информационные потребности, которые должны быть выполнены раньше.

  • Это ваша оценка времени процессора абсолютная или относительная? Если метод fill() использует половину процессорного времени, доступного системе, это кажется странным. Но если этот номер получал использование VisualVM, который сообщает время использования относительно времени, затраченного на приложение, просто может быть остальная часть вашего приложения не выполняет значительную работу?
  • Проверяются ли эти профилирующие измерения с помощью инструментов уровня системы? Вы можете использовать pidstat, mpstat и sar для перекрестной проверки, если вы используете Linux. Я видел, что VisualVM отмечал время, проведенное в SocketInputStream.socketRead0(), как время процессора, которое не было подтверждено pidstat. Я предполагаю, что это последствия некоторых измерительных аппроксимаций в самом VisualVM или JVM-поведении. Поэтому всегда рекомендуется перекрестно проверять с помощью инструментов ОС.