Selenium Headless Chrome - проблема с кучей Java - PullRequest
0 голосов
/ 21 декабря 2018

Я делаю очистку веб-страниц с помощью Headless Chrome (Selenium Chrome Web driver), установленного в Ubuntu на EC2.Для небольшого числа запросов это работает нормально ... но когда выполняется большое количество одновременных запросов (сотни), они продолжают падать, и мне всегда приходилось перезагружать сервер.

Кто-нибудь использовал это для поддержкибольшая нагрузка?Я использую сервер t2.medium ec2.

В журналах я вижу сообщение об ошибке связи с браузером:

2018-12-20 19:18:04.565 ERROR 1292 --- [io-8080-exec-79] o.s.boot.context.web.ErrorPageFilter     : Forwarding to error page from request [/v1.0/search] due to exception [Error communicating with the remote browser. It may have died.
Build info: version: '3.11.0', revision: 'e59cfb3', time: '2018-03-11T20:26:55.152Z'
System info: host: 'ip-172-31-17-81', ip: '172.31.17.81', os.name: 'Linux', os.arch: 'amd64', os.version: '4.4.0-1072-aws', java.version: '1.8.0_191'
Driver info: driver.version: RemoteWebDriver
Capabilities {acceptInsecureCerts: false, acceptSslCerts: false, applicationCacheEnabled: false, browserConnectionEnabled: false, browserName: chrome, chrome: {chromedriverVersion: 2.37.544315 (730aa6a5fdba15..., userDataDir: /tmp/.org.ch
romium.Chromium...}, cssSelectorsEnabled: true, databaseEnabled: false, handlesAlerts: true, hasTouchScreen: false, javascriptEnabled: true, locationContextEnabled: true, mobileEmulationEnabled: false, nativeEvents: true, networkConnectio
nEnabled: false, pageLoadStrategy: normal, platform: LINUX, platformName: LINUX, rotatable: false, setWindowRect: true, takesHeapSnapshot: true, takesScreenshot: true, unexpectedAlertBehaviour: , unhandledPromptBehavior: , version: 69.0.3
497.100, webStorageEnabled: true}
Session ID: e47c3c443164cbd2a3586ee6321d26f8]

org.openqa.selenium.remote.UnreachableBrowserException: Error communicating with the remote browser. It may have died.
Build info: version: '3.11.0', revision: 'e59cfb3', time: '2018-03-11T20:26:55.152Z'
System info: host: 'ip-172-31-17-81', ip: '172.31.17.81', os.name: 'Linux', os.arch: 'amd64', os.version: '4.4.0-1072-aws', java.version: '1.8.0_191'
Driver info: driver.version: RemoteWebDriver
Capabilities {acceptInsecureCerts: false, acceptSslCerts: false, applicationCacheEnabled: false, browserConnectionEnabled: false, browserName: chrome, chrome: {chromedriverVersion: 2.37.544315 (730aa6a5fdba15..., userDataDir: /tmp/.org.ch
romium.Chromium...}, cssSelectorsEnabled: true, databaseEnabled: false, handlesAlerts: true, hasTouchScreen: false, javascriptEnabled: true, locationContextEnabled: true, mobileEmulationEnabled: false, nativeEvents: true, networkConnectio
nEnabled: false, pageLoadStrategy: normal, platform: LINUX, platformName: LINUX, rotatable: false, setWindowRect: true, takesHeapSnapshot: true, takesScreenshot: true, unexpectedAlertBehaviour: , unhandledPromptBehavior: , version: 69.0.3
497.100, webStorageEnabled: true}
Session ID: e47c3c443164cbd2a3586ee6321d26f8
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:566)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:602)
        at org.openqa.selenium.remote.RemoteWebDriver.quit(RemoteWebDriver.java:445)
        at mt.service.KlookServiceImpl.searchTrips(KlookServiceImpl.java:138)
        at mt.controller.TripSearchController.getTripResults(TripSearchController.java:120)
        at sun.reflect.GeneratedMethodAccessor163.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
...
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:436)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: java.util.concurrent.TimeoutException
        at org.openqa.selenium.net.UrlChecker.waitUntilUnavailable(UrlChecker.java:145)
        at org.openqa.selenium.remote.service.DriverService.stop(DriverService.java:214)
        at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:95)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:545)
        ... 58 common frames omitted
Caused by: java.util.concurrent.TimeoutException: null
        at java.util.concurrent.FutureTask.get(FutureTask.java:205)
        at com.google.common.util.concurrent.SimpleTimeLimiter.callWithTimeout(SimpleTimeLimiter.java:156)
        at org.openqa.selenium.net.UrlChecker.waitUntilUnavailable(UrlChecker.java:115)
        ... 61 common frames omitted

Существует также проблема с пространством кучи Java:

2018-12-20 19:18:20.294 ERROR 1292 --- [io-8080-exec-84] o.s.boot.context.web.ErrorPageFilter     : Forwarding to error page from request [/v1.0/search] due to exception [Java heap space]

java.lang.OutOfMemoryError: Java heap space


Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "http-bio-8080-exec-96"

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

1 Ответ

0 голосов
/ 21 декабря 2018

Эти сообщения об ошибках ...

ERROR 1292 --- [io-8080-exec-79] o.s.boot.context.web.ErrorPageFilter     : Forwarding to error page from request [/v1.0/search] due to exception [Error communicating with the remote browser. It may have died.
.
org.openqa.selenium.remote.UnreachableBrowserException: Error communicating with the remote browser. It may have died.
.
2018-12-20 19:18:20.294 ERROR 1292 --- [io-8080-exec-84] o.s.boot.context.web.ErrorPageFilter     : Forwarding to error page from request [/v1.0/search] due to exception [Java heap space]
.
java.lang.OutOfMemoryError: Java heap space
.
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "http-bio-8080-exec-96"    

... означают, что java.lang.OutOfMemoryError возникла при пересылке запроса на страницу ошибки.


Исключение OutOfMemoryError

Исключение OutOfMemoryError является общим признаком утечки памяти.Эта ошибка выдается, когда недостаточно места для выделения объекта в куче Java .Эта ситуация возникает, когда сборщик мусора не может сделать пространство доступным для размещения нового объекта, и куча не может быть расширена дальше.Эта ошибка также может возникать, когда недостаточно собственной памяти для поддержки загрузки класса Java.В редком случае java.lang.OutOfMemoryError может быть выброшено, когда тратится слишком много времени на сборку мусора и освобождается небольшая память .


java.lang.OutOfMemoryError: пространство кучи Java

Подробное сообщение Java heap space указывает, что объект не может быть размещен в куче Java.Эта ошибка не обязательно означает утечку памяти.Проблема может быть такой же простой, как проблема конфигурации, когда указанный размер кучи (или размер по умолчанию, если он не указан) недостаточен для приложения.

В некоторых случаях для конкретного долгоживущего приложениясообщение может указывать на то, что приложение непреднамеренно хранит ссылки на объекты, что предотвращает сбор мусора.Это эквивалент языка Java утечка памяти .

Примечание : API, вызываемые приложением, также могут непреднамеренно хранить ссылки на объекты.

Было много дискуссий о непредсказуемом ЦП иПотребление памяти сессиями Chrome Headless.Согласно обсуждению Сборка без заголовка для минимального использования процессора + mem Использование ЦП + памяти может быть оптимизировано с помощью:

  • Используя либо собственный прокси, либо C ++ ProtocolHandlers, вы можете вернуть заглушку 1x1пиксельные изображения или даже полностью их блокировать.
  • Chromium Team работает над добавлением программного управления над созданием кадров.В настоящее время безголовый хром все еще пытается рендерить на 60 кадров в секунду , что довольно расточительно.Многие страницы нуждаются в нескольких кадрах (возможно, 10-20 кадров в секунду ) для правильного рендеринга (из-за использования requestAnimationFrame и animation triggers), но мы ожидаем, что здесь будет много сбережений ЦП.
  • MemoryInfra должно помочь вам определить, какой компонент является самым большим потребителем памяти в вашей установке.
  • Использование может быть:

    $ headless_shell --remote-debugging-port=9222 --trace-startup=*,disabled-by-default-memory-infra http://www.chromium.org
    
  • Хром всегда будет использовать столько ресурсов, сколько ему доступно.Если вы хотите эффективно ограничить его использование, вы должны изучить использование cgroups

Подробное обсуждение можно найти в Ограничение использования Chrome Headless CPU и памяти


Другие подходы

Листая ответ @ 1084 * BenChilds у вас всегда есть конечный максимальный объем памяти кучи, настроенный для использования, независимо от того, какойВы когда-нибудь на платформе.Java выбирает уменьшить значение по умолчанию.

Существует несколько подходов, которые вы можете выбрать, чтобы определить, какой объем памяти нужна вашей программе, или уменьшить объем памяти, используемый вашей программой.Одна из распространенных проблем с языками сборки мусора, такими как Java или C # , заключается в том, чтобы хранить ссылки на объекты, которые вы больше не используете, или выделять много объектов, когда вместо этого вы можете использовать их повторно.Пока объекты имеют ссылку на них, они будут продолжать использовать пространство кучи, поскольку сборщик мусора не удалит их.

В таких случаях вы можете использовать профилировщик памяти Java, чтобы определить, какие методы в вашей программе выделяют большое количество объектов, а затем определить, есть ли способ убедиться, что на них больше нет ссылок, или не выделять их впервое место.Помимо вышеупомянутого MemoryInfra еще один параметр JMP .

Если вы решите, что вы выделяете эти объекты по причине, и вам необходимоСохраняйте ссылки, вам просто нужно увеличить максимальный размер кучи при запуске вашей программы.Если вы не можете гарантировать, что ваша программа будет работать в ограниченном объеме памяти, вы всегда столкнетесь с этой проблемой.Только после исчерпания всего этого вам потребуется изучить кэширование объектов на диск и т. Д.

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

Более простой подход может состоять в запуске Java с параметром командной строки:

  • -Xms1g, который устанавливает размер кучи в 1 ГБ.
  • -Xmx2048m, который устанавливает размер кучи в 2048 МБ.
  • -Xmx2g, который устанавливает размер кучи в 2 ГБ.
  • -Xmx, который устанавливает максимальный размер кучи.

Чтобы установить эту опцию в Eclipse , вам необходимо перейти к:

Выполнить -> Выполнить настройки ... -> Щелкните на вкладке (x) = Аргументы -> в пределах Аргументы виртуальной машины Тип текстового поля -Xms1g , -Xmx2048m или -Xmx

Снимок:

VM arguments

Однако, увеличиваетсяразмер кучи не идеаленрешения и согласно передовым методикам было бы:

  • Используя правильный тип объекта, например: String, StringBuffer или StringBuilder
  • Различение между static и non static переменными.
  • Правильное использование multithreading.
...