이 기사를 통해 주로 Java 개발에서 Servlet 3.0 비동기 처리 및 솔루션에서 발생하는 문제를 설명합니다. 다음은 특정 내용입니다.
Servlet 3.0은 요청의 비동기 처리를 지원하기 위해 AsyncContext를 제공하기 시작했습니다. 그렇다면 요청을 비동기식으로 처리 할 수있는 이점은 무엇입니까?
일반적으로 웹 컨테이너가 요청을 처리하는 방식은 각 요청에 스레드를 할당하는 것입니다. 우리는 스레드의 생성에 비용이 들지 않으며 웹 컨테이너의 스레드 풀에는 상한이 있음을 알고 있습니다.
매우 예측 가능한 문제는 높은 하중 조건에서 스레드 풀이 점유되므로 후속 요청 만 기다릴 수 있다는 것입니다. 운이 좋지 않으면 클라이언트는 대기 시간 초과 오류를보고합니다.
AsyncContext가 나타나기 전에이 문제를 해결하는 유일한 방법은 웹 컨테이너의 스레드 풀을 확장하는 것이 었습니다.
그러나 여전히 문제가 있습니다. 다음 시나리오를 고려하십시오.
스레드 풀 크기가 200 인 웹 컨테이너가 있습니다. 두 개의 서블릿이있는 웹 앱이 있으며, Servlet-A가 단일 요청을 처리하는 데 걸리는 시간은 10 초이며, 단일 요청을 처리하는 데 Servlet-B가 필요한 시간은 1입니다.
이제 우리는 Servlet-A에 200 개가 넘는 요청으로 높은 부하를 만납니다. 현재 Servlet-B가 요청되면 모든 HTTP 스레드가 Servlet-A에 의해 점유되었으므로 기다립니다.
현재 엔지니어는 문제를 발견하고 스레드 풀 크기를 400으로 확장했지만 하중은 계속 상승했습니다. 이제 Servlet-A에 400 개의 요청이 있으며 Servlet-B는 여전히 응답 할 수 없습니다.
문제를 본 적이 있습니까? HTTP 스레드와 작업자 스레드가 함께 연결되어 있으므로 많은 수의 요청이 시간이 많이 걸리는 작업에 대한 수많은 요청이 이루어지면 전체 웹 컨테이너가 응답 할 수 없게됩니다.
그러나 AsyncContext를 사용하는 경우 시간 소모적 작업을 다른 스레드에 넘겨 주어 HTTP 스레드가 릴리스되고 다른 요청을 처리 할 수 있습니다.
AsyncContext 만 사용하면 위에서 언급 한 효과를 달성 할 수 있습니다. 새 스레드 () 또는 이와 유사한 메소드를 직접 사용하는 경우 HTTP 스레드는 컨테이너로 반환되지 않습니다.
공식적인 예는 다음과 같습니다.
@webservlet (urlpatterns = { "/asyncservlet"}, asyncsupported = true) public class asyncservlet는 httpservlet {/ * ... syncservlet에서와 동일한 변수 및 init 메소드를 확장합니다 ... */@override public void dooid (httpervlerquest 요청, httpervletrget 응답) Response.setContentType ( "Text/Html; charset = utf-8"); 최종 AsyncContext acontext = request.startasync (); acontext.start (new runnable () {public void run () {String param = acontext.getRequest (). getParameter ( "param"); String result = resource.process (param); httpservletresponse reponship = acontext.getResponse ( / * ... 응답으로 인쇄)); }} 덫
이 공식적인 예에서 각 HTTP 스레드는 다른 작업자 스레드를 열어 요청을 처리 한 다음 HTTP 스레드를 웹 컨테이너로 반환합니다. 그러나 asynccontext.start () 메소드의 javadoc을보십시오.
컨테이너가 관리되는 스레드 풀에서 스레드를 발송하여 지정된 런 가능성을 실행하게됩니다.
실제로, 여기서 작업자 실이 나오는 규제는 없습니다. 어쩌면 HTTP 스레드 풀 이외의 다른 스레드 풀일까요? 아니면 HTTP 스레드 풀입니까?
asynccontext.start () 기사의 유용성은 다음과 같습니다. 다른 웹 컨테이너 마다이 구현이 다르지만 Tomcat은 실제로 http 스레드 풀을 사용하여 asynccontext.start ()를 처리합니다.
이는 원래 HTTP 스레드를 해제하고 싶었지만 실제로는 HTTP 스레드가 여전히 작업자 스레드로 사용되기 때문에 그렇지 않았습니다. 그러나이 스레드는 요청을 수신하는 HTTP 스레드와 동일하지 않습니다.
또한 AsyncServlet1 및 SyncServlet의 JMeter 벤치 마크를 통해이 결론을 볼 수 있으며 두 처리량의 결과는 비슷합니다. 시작 방법 : 메인을 시작한 다음 JMeter를 사용하여 Benchmark.jmx를 시작하십시오 (Tomcat 기본 구성에서 HTTP 스레드 풀 = 200).
ExecutorService 사용
나는 Tomcat이 작업자 스레드 풀을 별도로 유지하지 못한다는 것을 이전에 보았으므로 스레드 풀이있는 ExecutorService를 사용하여 AsyncContext를 처리하는 AsyncServlet2를 참조해야합니다.
다른 방법
따라서 AsyncContext를 사용하는 고정 된 방법은 없습니다. 실제 요구에 따라 다른 방법을 사용하여 처리 할 수 있습니다. 이러한 이유로 Java 동시 프로그래밍에 대한 지식이 필요합니다.
성능의 오해
AsyncContext의 목적은 성능을 향상시키지 않으며 성능 향상을 직접 제공하지 않습니다. HTTP 스레드와 작업자 스레드를 분리하는 메커니즘을 제공하여 웹 컨테이너의 응답 성을 향상시킵니다.
그러나 AsyncContext는 어느 시점에서 성능을 향상시킬 수 있지만 이는 코드 작성 방법에 따라 다릅니다.
예를 들어, 웹 컨테이너의 HTTP 스레드 풀의 수는 200이며 서블릿은 300 개의 작업자 스레드 풀을 사용하여 AsyncContext를 처리합니다.
Sync 메소드 작업자 스레드 풀 = http 스레드 풀 = 200과 비교할 때,이 경우 300의 작업자 스레드 풀이 있으므로 성능 개선을 확실히 가져올 것입니다 (결국 더 많은 사람들이 일하는 사람들이 더 많습니다).
반대로, 작업자 스레드의 수가 <= HTTP 스레드 수인 경우, 처리 요청을위한 병목 현상이 작업자 스레드에 있기 때문에 성능 향상이 없을 것입니다.
AsyncServlet2의 스레드 풀 크기를 수정하고 동기 보틀 벤치 마크 결과와 비교 하여이 결론을 확인할 수 있습니다.
작업자 스레드 풀이 HTTP 스레드 풀보다 커야한다고 생각하지 마십시오. 이유는 다음과 같습니다.
두 가지 책임은 다릅니다. 하나는 웹 컨테이너가 외부 요청을받는 데 사용되고 다른 하나는 비즈니스 로직을 처리하는 것입니다.
스레드 생성 비용은 비용이 많이 듭니다. HTTP 스레드 풀이 이미 큰 경우 더 큰 작업자 스레드 풀을 만들면 너무 많은 컨텍스트 스위치와 메모리 오버 헤드가 발생합니다.
AsyncContext의 목적은 HTTP 스레드를 해제하여 장기적인 작업 사용을 피하고 웹 컨테이너가 응답 할 수 없게하는 것입니다.
따라서 대부분의 경우 작업자 스레드 풀은 크지 않으며 다른 작업자 스레드 풀이 다른 비즈니스에 따라 구축됩니다.
예를 들어, 웹 컨테이너 스레드 풀 크기는 200이고, 작업자 스레드 풀 크기는 느린 서블릿의 경우 10입니다. 이런 식으로, 운영 속도를 늦추기 위해 얼마나 많은 요청이 사용 되더라도 HTTP 스레드를 채우지 않고 다른 요청을 처리 할 수 없습니다.