2014-12-18 2 views
1

Я использую весеннюю модель MVC в своем проекте. В котором контроллер получает запрос от какого-то определенного приложения сторонней стороны. Контроллер получает 20 запросов в секунду. Код выглядит следующим образомКак улучшить производительность с использованием многопоточности весной Mvc

@Controller 
@RequestMapping("/action") 
public class FrontController{ 

@AutoWired 
private CommonService commonService; 

(First Code) 
@RequestMappint("/save") 
public String saveData(@PathParam("id")String did){ 

    List<String, Object> map = commonService.getVmn(did); 
    CallReporting callReporting = new CallReporting(); 
    callReporting.setName(map.get("name")); 
    so---on (have 15 field) 
    commonService.save(callReporting); 
    } 

    return "1"; 
} 

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

(Second Code) 
@RequestMappint("/save") 
public String saveData(@PathParam("id")String did){ 

    Thread thread = new Thread(new Runnable(){ 
     List<String, Object> map = commonService.getVmn(did); 
     CallReporting callReporting = new CallReporting(); 
     callReporting.setName(map.get("name")); 
     so---on (have 15 field) 
     commonService.save(callReporting); 
    }); 
    } 

    return "1"; 
} 

Я начал использовать код примерно так. Так что вызывающая сторона может немедленно получить ответ (уменьшить время ответа), а затем мое приложение продолжит работу. Но в первом коде я тестирую нагрузку с помощью JMeter (20 req/sec) и обнаружил, что он работает нормально с нагрузкой процессора (3%). Но во втором коде с той же загрузкой загрузка процессора будет более чем на 100%. Когда я начал использовать ThreadPoolTaskExecutor с более низкой конфигурацией.

@AutoWired 
private ThreadPoolTaskExecutor executor; 

@RequestMappint("/save") 
public String saveData(@PathParam("id")String did){ 

//Assume this code is in MyRunnableWorker Class 
     List<String, Object> map = commonService.getVmn(did); 
     CallReporting callReporting = new CallReporting(); 
     callReporting.setName(map.get("name")); 
     so---on (have 15 field) 
     commonService.save(callReporting); 

    MyRunnableWorker worker = new MyRunnableWorker(); 
    executor.execute(worker) 

    return "1"; 
} 

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
    <property name="corePoolSize" value="50" /> 
    <property name="maxPoolSize" value="100" /> 
    <property name="keep-alive" value="10" /> 
    <property name="queueCapacity" value="200" /> 
</bean> 

но нашел тот же результат. Что-то не так с кодом, может кто-нибудь мне подскажет. Одна важная вещь, когда я тестирую Jmeter в стадии застройки, тогда загрузка перемещается между 30% и 70%. Но на сервере производства это всегда около 100%. Это java, потребляющий 100%, другой процесс довольно низок. Производственная машина, оснащенная ОС Linux. обработчик гексакора, имеющий 128 ГБ ОЗУ. Может кто-нибудь сказать мне, что делать.

ответ

2

У вашего ThreadPoolTaskExecutor слишком много потоков. CPU тратит много времени, чтобы переключить контекст между threds. В тесте вы запускаете только ваш контроллер, чтобы не было других потоков (вызовов), существующих на производстве. Основная проблема ждет БД, так как он блокирует нить

Решения

  • размера набора бассейна меньше (сделать некоторый эксперимент)
  • удалить исполнитель и использование актер систему как Акку для save работы.
  • Наиболее важная партия для сохранения объектов в БД. Будет только один вызов, например. 1000 объектов не 1k вызывает 1k объектов>JPA/Hibernate improve batch insert performance
+0

ok Than Почему cpu load increse во втором коде, где я не использовал пул потоков. Во-вторых, я не могу использовать пакет в этом случае. Система запроса часто запрашивает запрос, а затем эта запись будет просматриваться пользователем в части MIS. Другая причина, по которой какая-то временная система находится в режиме ожидания. Поэтому я должен ударить db один к одному. –

+0

Simillar причина. Вы создаете много потоков. Больше, чем количество ядер. Пожалуйста, прочитайте о Amdahl Law http://en.wikipedia.org/wiki/Amdahl%27s_law, это очень хорошее объяснение, почему создание множества потоков может снизить производительность. –

2

Похоже, вы поворачиваете неправильную ручку.

В вашей первой версии у вас было до N потоков, разбивающих вашу базу данных. Когда N настроен где-то в вашем контейнере сервлета. А также делать сервлет thingy, принимая соединения и прочее.

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

Чтобы улучшить, уменьшите количество потоков в пуле потоков, попадающем в базу данных. Измерьте количество потоков, которые может обрабатывать база данных до ухудшения производительности.

Сделайте queueCapacity достаточно большим, чтобы покрыть запросы, которые вам нужно обрабатывать.

Внедрение чего-то, что дает понятный ответ пользователю, когда этого недостаточно. Что-то вроде «Извините ...»

А затем позаботься о реальной проблеме: как сделать вашу базу данных обработкой запросов достаточно быстро.

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

Но все это для другой вопрос.

+0

Можете ли вы рассказать мне, что может быть лучшим значением конфигурации Executor, имеющим 15 req в секунду. как размер ядра, максимальный размер и queuecapacity –

+0

Я сказал вам в своем ответе: измерьте его. Любой другой ответ - ложь. –

0

бутылка шеи в вашем случае являются операции (DB)

вот несколько предложений:

  1. , если это не необходимо, чтобы данные должны быть немедленно сохранены просто использовать асинхронную работу, чтобы сделать это (JMS, в очереди памяти и т.д.)

  2. Вы можете рассмотреть возможность загрузки БД в оперативной памяти

+0

Если транзакция db является проблемой, то почему загрузка cpu не увеличивается в первом случае означает, что с кодом потока работает нормально. –

+1

Загрузка процессора связана с тем, что потоки ждут получения ресурсов (ов), поскольку я предположил, что ваш connectionPool my будет меньше, чем 200 (соединений) потока вынуждены ждать, пока соединение не будет доступно для запуска TX. Вы можете, например, позвонить, чтобы узнать, есть ли доступное соединение, если нет, то спящий поток, пока соединение не будет готово, но это что-то странное, я определенно никогда не буду использовать –