2014-12-08 2 views
0

У меня есть таблица базы данных requests_pending, которая содержит запросы (сообщения) от пользователя, подлежащего обработке. Скорость входящего запроса составляет 1000/секунду. После обработки запроса он удаляется из таблицы requests_pending и вставлен в requests_processed. И ответ для каждого запроса вставляется в таблицу response, которая затем отправляется пользователю. Чтобы не отставать от входящих запросов, я попытался использовать несколько потоков для извлечения и обработки запроса. Я использовал synchronized BLOCK на выборке запроса, чтобы только один поток обращался к таблице за раз и, следовательно, избегал дублирования обработки запросов.Многопоточность для повышения производительности

synchronized (this) { 
     fetch request... 
    } 
    processRequest(); 

Но synchronized блок замедляет работу приложения. Один Thread работает лучше, чем несколько Threads, я думаю, потому что накладные расходы отсутствуют. Любой альтернативный подход для повышения производительности.

+0

Похоже, вы переопределяете JMS. Поэтому, возможно, * используйте * реализацию JMS. –

+0

Вы открываете/закрываете соединение по каждому запросу? это также замедляет его. –

+0

@BartHofma Я использую пул соединений. – Abhay

ответ

1

Отдельная тема работает лучше, чем несколько потоков, я думаю, потому что накладные расходы отсутствуют.

Это предложение имеет мало смысла для меня, но накладные расходы синхронизации, безусловно, не имеют значения в размере 1000 в секунду.

Как уже писал Марко Топольник, посвященные потоки решают проблему красиво. Пусть один поток выберет все обрабатываемые запросы, отправьте их всем Executor, удалите их. Если запросов не было найдено, просто спать некоторое время.

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

0

Как говорят люди, ваша история выглядит как история асинхронного выполнения, которая действительно может быть реализована, например, с использованием стандартного JMS-контейнера. Но если вы хотите настаивать на своем собственном решении:

  1. Попытайтесь уменьшить конкуренцию. Используйте блокировку объекта User для извлечения и обработки своих запросов вместо блокировки на процессоре.

  2. Используйте SELECT FOR UPDATE, если ваша СУБД поддерживает ее, чтобы заблокировать пользователя в таблице «user» до того, как будет обработан запрос этого пользователя. Это перемещает синхронизацию с java-кода на уровень DB и по-прежнему имеет значительную стоимость.

  3. Или попробуйте избавиться от замков вообще. Разделяйте данные пользователя среди N потоков, когда каждый поток обрабатывает данные для данного подмножества пользователей. Предположим, что первый поток обрабатывает запросы пользователей A-F, второй для пользователей G-L и т. Д. Используйте любое разумное статическое/динамическое правило. Кроме того, поскольку соединение JDBC не является потокобезопасным, каждый поток должен устанавливать и удерживать свой собственный экземпляр соединения. Как результат, у вас нет критического раздела вообще, поскольку у вас нет данных, разделяемых между любыми потоками, и это может работать даже быстрее, чем установка «из коробки» JMS, поскольку вы управляете всем процессом и у вас нет никакого «общего» кода.

И, наконец, проверить свой код JDBC, пожалуйста: убедитесь, что вы используете PreparedStatement, пакетная обработка и соответствующий уровень изоляции для транзакций.

Смежные вопросы