Я использовал JMeter для генерации нагрузки на свой производственный сервер для тестирования моего приложения. План тестирования имеет 13+ HTTP-сэмплеров для выполнения другого запроса и один экстрактор регулярных выражений для извлечения некоторого значения из ответа. Это значение использовалось в последовательном HTTP Sampler. Этот тестовый пример прост и понятен. Первоначально я использовал 200 потоков JMeter для имитации 200 пользователей. Сервер мог легко обрабатывать эти многочисленные запросы, но когда количество потоков увеличивалось, он не мог обрабатывать их и ждал бесконечно. Конечно, что-то происходило. Потоки JMeter ждали соединения и не могли его так ждать бесконечно. Чтобы избежать этой ситуации, я ввел «HTTP-запрос по умолчанию», чтобы добавить некоторое время ожидания соединения и ответа. Одна проблема была решена, теперь потоки не зависают там бесконечно, но они истекают со следующим исключением.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java: 129 ) at java.io.BufferedInputStream.fill(BufferedInputStream.java: 218 ) at java.io.BufferedInputStream.read(BufferedInputStream.java: 237 ) at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java: 78 ) at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java: 106 ) at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java: 1116 ) at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java: 1973 ) at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java: 1735 ) at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java: 1098 ) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java: 398 ) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java: 171 ) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 397 ) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 323 ) at org.apache.jmeter.protocol.http.sampler.HTTPHC3Impl.sample(HTTPHC3Impl.java: 258 ) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java: 62 ) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java: 1088 ) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java: 1077 ) at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java: 428 ) at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java: 256 ) at java.lang.Thread.run(Thread.java: 662 ) |
Определенно какая-то часть сервера (Apache 2.2.14 + Apache-tomcat-7.0.11) скрипела, но не была уверена, какая часть. Конечно, в настройке было узкое место. В текущей настройке сервер Apache переадресовывал запросы на движок Tomcat. Конечно, ни один из них не смог обработать более 200 запросов одновременно. Я немного изменил настройку, чтобы перенаправить все запросы непосредственно на движок Tomcat. Это было в состоянии справиться с этим, это означает, что Apache ослабевал. Я быстро проверил файл Apache error.log, присутствующий в /var/log/apache2/error.log
и обнаружил следующие строки.
1
2
3
4
|
[Wed Jun 26 16:46:19 2013] [error] server is within MinSpareThreads of MaxClients, consider raising the MaxClients setting [Wed Jun 26 16:46:20 2013] [error] server reached MaxClients setting, consider raising the MaxClients setting [Wed Jun 26 17:24:42 2013] [error] server is within MinSpareThreads of MaxClients, consider raising the MaxClients setting [Wed Jun 26 17:24:43 2013] [error] server reached MaxClients setting, consider raising the MaxClients setting |
Это ясно указывает на то, что число MaxClients должно быть увеличено, что, в свою очередь, увеличит количество потоков Apache. Я быстро отредактировал файл apache2.conf, чтобы увеличить число MaxClients, добавив следующую конфигурацию и выполнив "apache2ctl -t"
чтобы убедиться, что изменения, внесенные в файлы конфигурации, были правильными.
1
2
3
4
5
6
7
8
9
|
< IfModule mpm_worker_module> StartServers 2 MinSpareThreads 25 MaxSpareThreads 100 ThreadLimit 800 ThreadsPerChild 800 MaxClients 2400 MaxRequestsPerChild 0 </ IfModule > |
Я был немного расслаблен, думая, что теперь Apache определенно справится с нагрузкой. Но, к моему удивлению, это не могло произойти, и то же самое исключение снова ударило по JMeter. На данный момент я хотел проверить производительность Apache, включив состояние сервера. Эта функция может дать вам четкое представление о состояниях соединения. Я поместил следующие строки в /etc/apache2/mods-available/status.conf
1
2
3
4
5
6
|
< Location /server-status> SetHandler server-status Order deny,allow Deny from all Allow from .your.domain.here.com localhost </ Location > |
Я перезапустил Apache и сервер, выполнив следующую команду
1
|
/> sudo service apache2 restart; sudo service tomcat restart; |
После перезапуска Apache я нажал следующий URL, чтобы получить статус сервера.
После запуска JMeter для 200+ потоков я заметил это на странице состояния.
На странице состояния указано, что в состоянии "W"
(отправка ответа) было много соединений. Это может быть вызвано другими причинами. Я пытался гуглить, но не смог найти какое-то определенное решение. Но одна вещь была уверена, что Apache не вызывает проблем. Должно быть между Apache и tomcat. Я понял, что план тестирования JMeter отлично работает для 200 потоков, и даже Tomcat по умолчанию имеет 200 потоков. Я просто рискнул и увеличил количество потоков до 400, отредактировав файл "<APACHE_TOMCAT_HOME>/conf/server.xml"
.
1
2
|
<!-- Define an AJP 1.3 Connector on port 8009 --> < Connector port = "8009" protocol = "AJP/1.3" redirectPort = "8443" maxThreads = "400" minSpareThreads = "20" /> |
Теперь сервер может легко справиться с нагрузкой JMeter, а соединения Apache находятся в хорошем состоянии даже после завершения плана тестирования.
Хотя проблема была решена, я не мог понять, почему Tomcat смог обработать нагрузку, когда JMeter был настроен на отправку всех запросов напрямую в Tomcat, но не смог обработать нагрузку, когда Apache переадресовал запрос в Tomcat. Если у вас есть какие-либо объяснения относительно этого поведения, пожалуйста, поделитесь ниже в разделе комментариев.