2008-09-15 2 views
2

У меня есть веб-приложение, которое получает сообщения через интерфейс HTTP, например:Пакетная вставка с использованием JPA/Toplink

http://server/application?source=123&destination=234&text=hello 

Этот запрос содержит идентификатор отправителя, идентификатор получателя и текст из сообщение.

Это сообщение должно быть обработано как:

  • найти соответствующий объект пользователя для источника и назначения из базы данных
  • создает дерево объектов: Сообщение, содержащее поле для сообщения текст и два объекта пользователя для источника и адресата
  • сохранение этого дерева в базе данных.

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

Я использую Oracle как базу данных поддержки и JPA с помощью Toplink для задач обработки базы данных. Если возможно, я останусь с ними.

Без большой оптимизации я могу достичь ~ 30 запросов/сек пропускной способности в моей среде. Это не так много, я бы потребовал ~ 300 запросов/сек. Поэтому я измерил, где узкое место производительности и обнаружил, что звонки на em.persist() занимают большую часть времени. Если я просто прокомментирую эту строку, пропускная способность пройдет более 1000 запросов/сек.

Я попытался написать небольшое тестовое приложение, которое использовало простые вызовы JDBC для сохранения 1 миллиона сообщений в одной и той же базе данных. Я использовал пакетную обработку, то есть я сделал 100 вставок, затем фиксацию, и повторил, пока все записи не были в базе данных. В этом сценарии я измерил ~ 500 запросов в секунду, что соответствовало бы моим потребностям.

Понятно, что мне нужно оптимизировать производительность вставки здесь. Однако, как я упоминал ранее, я хотел бы использовать JPA и Toplink для этого, а не чистый JDBC.

Знаете ли вы способ создания пакетных вставок с JPA и Toplink? Можете ли вы порекомендовать какой-либо другой метод повышения производительности JPA?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

«запросы/сек» означает здесь: общее количество запросов/общее время от начала испытания до последней прочитанной записи в базу данных.

Я попытался сделать асинхронный вызов em.persist(), создав очередь в памяти между материалом сервлета и персистом. Это очень помогло выходу. Однако очередь действительно быстро развивалась, и когда приложение будет получать ~ 200 запросов в секунду, это не приемлемое решение для меня.

В этом отцепленном подходе я собрал запросы на 100 мс и вызвал em.persist() по всем собранным элементам до совершения транзакции. EntityManagerFactory кэшируется между каждой транзакцией.

ответ

3

Вы должны отделить от интерфейса JPA и использовать голый API TopLink. Вероятно, вы можете зацепить объекты, которые вы сохраняете в UnitOfWork, и зафиксировать UnitOfWork в своем расписании (синхронизация или асинхронный). Обратите внимание, что одна из затрат на em.persist() - это неявный клон, который происходит из всего графа объектов. TopLink будет работать лучше, если вы сами uou.registerObject() сами используете два пользовательских объекта, сохраняя те же тесты, что и в других случаях. Таким образом, вы будете в конечном итоге с:

uow=sess.acquireUnitOfWork(); 
for (job in batch) { 
thingyCl=uow.registerObject(new Thingy()); 
user1Cl=uow.registerObject(user1); 
user2Cl=uow.registerObject(user2); 
thingyCl.setUsers(user1Cl,user2Cl); 
} 
uow.commit(); 

Это очень старая школа TopLink кстати;)

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

Другие предметы для поиска: ваш размер последовательности. Много времени, потраченное на запись объектов в TopLink, на самом деле потрачено на чтение информации о последовательности из базы данных, особенно с небольшими значениями по умолчанию (у меня, вероятно, было бы несколько сотен или даже больше, как размер моей последовательности).

+0

Спасибо, я попробую это через несколько дней. Что вы имеете в виду о размере последовательности? – Zizzencs

0

Какое качество показаний «запрос/сек»? Другими словами, что происходит для 31-го запроса? Какой ресурс блокируется? Если это часть интерфейса/сервлета/веб-страницы, вы можете запустить em.persist() в другом потоке и немедленно вернуться?

Кроме того, вы создаете транзакции каждый раз?Вы создаете объекты EntityManagerFactory с каждым запросом?