Стратегии оптимизации производительности унаследованного приложения EJB3

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

На сервере есть база данных, несколько bean-компонентов EJB3 (JPA) и несколько bean-компонентов без сохранения состояния только для того, чтобы разрешить CRUD для 4..5 объектов домена для удаленных клиентов. Сам клиент представляет собой java-приложение. Просто несколько подключены к серверу параллельно. Из комментариев пользователей я узнал, что

  • клиент-серверное приложение хорошо зарекомендовало себя в локальной сети
  • приложение было практически непригодно для использования в глобальной сети (1 Мбит или более), потому что операции чтения и обновления занимали слишком много времени (до нескольких минут)

Я видел одну потенциальную проблему: на всех EJB все отношения были определены со стратегией выборки FetchType.EAGER. Объясняет ли это проблемы с производительностью операций чтения? Целесообразно ли начинать настройку со стратегий выборки?

Но это не объясняет проблемы с производительностью при операциях обновления, или нет? Обновление обрабатывается EntityManager, клиент просто передает объект домена управляющему компоненту, а сохранение выполняется только с помощью manager.persist(obj). Возможно, объекты домена, отправляемые на сервер, слишком велики (возможно, это побочный эффект стратегии EAGER).

Итак, моя фактическая теория заключается в том, что слишком много байтов отправляется по довольно медленной сети, и мне следует подумать об уменьшении размера наборов результатов.

Исходя из вашего опыта, каковы типичные и наиболее распространенные ошибки кодирования, которые приводят к проблемам с производительностью в операциях CRUD, с чего мне следует начать исследование/оптимизацию?


person Andreas Dolk    schedule 29.09.2010    source источник


Ответы (4)


Во всех компонентах EJB все отношения определены с помощью стратегии выборки FetchType.EAGER. Объяснит ли это проблемы с производительностью операций чтения?

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

Целесообразно ли начинать настройку со стратегий выборки?

Я не могу сказать, что делать все отношения EAGER очень стандартным подходом. По моему опыту, вы обычно держите их ленивыми и используете "Fetch Joins" (тип соединения, позволяющий получить ассоциацию), когда вы хотите быстро загрузить ассоциацию для данного варианта использования.

Но это не объясняет проблемы с производительностью при операциях обновления, или нет?

Это могло бы. Я имею в виду, что если приложение извлекает граф больших толстых объектов при чтении, а затем отправляет тот же граф толстых объектов обратно, чтобы обновить только корневой объект, это может привести к снижению производительности. Но немного странно, что код использует em.persist(Object) для обновления сущностей.

Исходя из вашего опыта, каковы типичные и наиболее распространенные ошибки кодирования, которые приводят к проблемам с производительностью в операциях CRUD, с чего мне следует начать исследование/оптимизацию?

К очевидным относятся:

  1. Получение большего количества данных, чем требуется
  2. Проблемы с запросами N+1 (неверная стратегия выборки)
  3. Плохо написанные запросы JPQL
  4. Неподходящие стратегии наследования
  5. Ненужные обращения к базе данных (например, отсутствие кэширования)

Я бы начал с написания нескольких интеграционных или функциональных тестов, прежде чем прикасаться к чему-либо, чтобы гарантировать, что вы не измените функциональное поведение. Затем я бы активировал ведение журнала SQL и начал смотреть на сгенерированный SQL для основных вариантов использования и работать над вышеуказанными пунктами.

person Pascal Thivent    schedule 29.09.2010
comment
внимательно посмотрел на bean-компоненты, автор использовал persist для вставки и merge для обновления. Имеет ли это больше смысла или все еще странно? - person Andreas Dolk; 29.09.2010
comment
@Andreas_D Хорошо, я этого и ожидал. - person Pascal Thivent; 29.09.2010

С позиции DBA.

Исходя из вашего опыта, каковы типичные и наиболее распространенные ошибки кодирования, которые приводят к проблемам с производительностью в операциях CRUD, с чего мне следует начать исследование/оптимизацию?

  1. Отключить кеширование
  2. Включить ведение журнала sql Ejb3/Hibernate по умолчанию генерирует множество крайне глупых запросов.
  3. Теперь Вы видите, что я имею в виду.
  4. Измените FetchType.EAGER на FetchType.LAZY.
  5. Скажите «нет» большой бизнес-логике между em.find em.persist
  6. Используйте ehcache http://ehcache.org/
  7. Включить кеш сущностей
  8. Если можете, сделайте первичные ключи неизменяемыми ( @Column(updatable = false, ...)
  9. Включить кэш запросов

Никогда не используйте Hibernate, если вам нужна высокая производительность: http://www.google.com/search?q=hibernate+sucks

person baklarz2048    schedule 29.09.2010
comment
Спасибо! Я начну с (4), потому что я не думаю, что сервер и база данных являются узким местом. Так что, возможно, FetchType.LAZY уже дает значительный прирост производительности и ... это поддержало бы мнение Fake Jeffs (из вашей последней ссылки) - программисты Java не думают о базах данных, когда у них есть инструмент hibernate/JPA - просто потому, что это так чертовски просто чтобы сохранить эти несколько объектов;) - person Andreas Dolk; 29.09.2010
comment
Это последнее предложение совершенно неверно, Hibernate ДЕЙСТВИТЕЛЬНО хорошо работает, когда его используют опытные люди. - person Pascal Thivent; 29.09.2010
comment
@Pascal - конечно, вы правы, и мне нравится спящий режим, но он открывает дверь в базы данных, скажем, менее опытным людям, и у меня такое чувство, что один из них оставил мое настоящее приложение позади;) - person Andreas Dolk; 30.09.2010
comment
@Andreas Hibernate не идеален, у него определенно есть недостатки. Но никогда не используйте Hibernate (...) — это очень консервативное утверждение, которое просто неверно. - person Pascal Thivent; 30.09.2010
comment
Hibernate fun boy пишет: Разработчики используют Hibernate, потому что им неудобно работать с SQL и РСУБД. Прежде чем начать использовать Hibernate, вы должны хорошо освоиться с SQL и JDBC — Hibernate строится на JDBC, а не заменяет его. Люди, хорошо разбирающиеся в sql, java, jdbc, могут дать вам сотни sql и трюков, которые нельзя сделать с ejb3. Там, где все решает масштабируемость и стоимость, нет места для Java ORM, особенно для Hibernate. alexa.com/topsites ‹› ejb3. - person baklarz2048; 30.09.2010

В моем случае аналогичная проблема с производительностью не зависела от стратегии выборки. Или, скажем, было невозможно изменить бизнес-логику в существующих стратегиях выборки. В моем случае решение заключалось в простом добавлении индексов. Когда ваша объектная модель JPA имеет много отношений (OneToOne, OneToMany,...), вы обычно будете использовать операторы JPQL с большим количеством соединений. Это может привести к сложным переводам SQL. Когда вы взглянете на модель данных (сгенерированную JPA), вы обнаружите, что ни для одной из строк вашей таблицы нет индексов. Например, если у вас есть объект Customer и Address с отношениями oneToOne, на первый взгляд все будет хорошо работать. Клиент и адрес имеют внешний ключ. Но если вы делаете такие выборки

Select c from Customer as c where c.address.zip='8888'

вы должны позаботиться о столбце таблицы «zip» в таблице ADDRESS. JPA не будет создавать для вас такой индекс во время развертывания. Так что в моем случае я смог повысить производительность базы данных, просто добавив индексы. Оператор SQL в вашей базе данных выглядит так:

 ALTER TABLE `mydatabase`.`ADDRESS` ADD INDEX `zip_index`(`IZIP`);
person Ralph    schedule 23.04.2011
comment
Спасибо! К счастью, мне не пришлось долго смотреть на эту... кодовую базу, но есть риск, что скоро появится новая задача, связанная с этим проектом, и это определенно будет одной из первых вещей, которые нужно исследовать. - person Andreas Dolk; 26.04.2011

В вопросе и в других ответах я слышу много «может быть» и «может быть».

Сначала узнайте, что происходит. Если вы этого не сделали, мы все просто ковыряемся в темноте.

Я не эксперт по такого рода системам, но этот метод работает на любом языке и в любой операционной системе.

Когда вы обнаружите, почему это занимает слишком много времени, почему бы вам не обобщить это здесь? Мне особенно интересно знать, было ли это чем-то, о чем можно было догадаться.

person Mike Dunlavey    schedule 29.09.2010