SlideShare une entreprise Scribd logo
1  sur  21
Télécharger pour lire hors ligne
RequestBufferingHandler
필터 로직 상세 소개
JBoss EAP 7.1 Undertow
JBUG Korea
@tedwon
"default task-1" #97 prio=5 os_prio=0 tid=0x000000000401cfe0 nid=0x44d5 runnable [0x00007fd1f6dd7000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000e2fa5718> (a sun.nio.ch.Util$3)
- locked <0x00000000e2fa5708> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000e2fa55f0> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
at org.xnio.nio.SelectorUtils.await(SelectorUtils.java:51)
at org.xnio.nio.NioSocketConduit.awaitReadable(NioSocketConduit.java:358)
Issue
● Intermittent long-running request thread 발생
○ over 5 secs, normally under 1 secs
○ Causing running threads accumulation !!
● Performance Issue !!!
● Why does this occur ?
● Needs investigation
2
"default task-1" #97 prio=5 os_prio=0 tid=0x000000000401cfe0 nid=0x44d5 runnable [0x00007fd1f6dd7000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000e2fa5718> (a sun.nio.ch.Util$3)
- locked <0x00000000e2fa5708> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000e2fa55f0> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
at org.xnio.nio.SelectorUtils.await(SelectorUtils.java:51)
at org.xnio.nio.NioSocketConduit.awaitReadable(NioSocketConduit.java:358)
at org.xnio.conduits.AbstractSourceConduit.awaitReadable(AbstractSourceConduit.java:66)
at org.xnio.conduits.AbstractSourceConduit.awaitReadable(AbstractSourceConduit.java:66)
at io.undertow.conduits.ReadDataStreamSourceConduit.awaitReadable(ReadDataStreamSourceConduit.java:101)
at io.undertow.conduits.FixedLengthStreamSourceConduit.awaitReadable(FixedLengthStreamSourceConduit.java:285)
at org.xnio.conduits.ConduitStreamSourceChannel.awaitReadable(ConduitStreamSourceChannel.java:151)
at io.undertow.channels.DetachableStreamSourceChannel.awaitReadable(DetachableStreamSourceChannel.java:77)
at io.undertow.server.HttpServerExchange$ReadDispatchChannel.awaitReadable(HttpServerExchange.java:2161)
at org.xnio.channels.Channels.readBlocking(Channels.java:295)
at io.undertow.servlet.spec.ServletInputStreamImpl.readIntoBuffer(ServletInputStreamImpl.java:184)
at io.undertow.servlet.spec.ServletInputStreamImpl.read(ServletInputStreamImpl.java:160)
at com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.ensureLoaded(ByteSourceJsonBootstrapper.java:522)
...
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:326)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:812)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
3
● Web Browser => Apache => JBoss EAP
● Where is it from ?
○ EAP ?
○ Apache ?
● Access log
● Capturing tcpdumps
Investigation
4
● Web Browser => Apache => JBoss EAP
● By the tcpdump analysis,
● There is time gap between request header and body packet
● in Client side.
Investigation - conclusion
5
Undertow 버전
● EAP 7.1 은 Undertow 1.4.18.Final 버전을 사용
○ https://access.redhat.com/articles/112673#EAP_7
○ https://github.com/undertow-io/undertow/tree/1.4.18.Final
6
RequestBufferingHandler
기본 소개
7
RequestBufferingHandler 기본 소개
● Undertow 가 제공하는 HTTP Handler(filter) 중 하나
● 기능:
○ Request 의 모든 패킷 데이터가 도착 하면 Request를 Worker Thread 로 dispatch 한다.
● 효과:
○ 해당 필터를 추가하면 간헐적 네트워크 지연등으로 Request 패킷 전송이 늦어지는 경우
Worker Thread 의 데이터 읽기 대기 상태(epollWait)로 인한 thread blocking 상태를 피할 수
있다.
● 영향:
○ GC 대상 객체 추가 발생. 지연 발생 요청 건마다 RequestBufferingHandler 의 이벤트 listener
객체(40 bytes)가 생성되고 요청 완료 후 GC의 대상이됨.
● 소스코드:
○ https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/serv
er/handlers/RequestBufferingHandler.java
8
RequestBufferingHandler
수행 로직 소개
9
● Undertow의 Thread 실행은 IO Thread 와 Worker Thread 로 구성되어 실행
RequestBufferingHandler 수행 로직 소개
10
● IO Thread 는 이름 그대로 I/O 만 담당하는 Thread
● Request의 비즈니스 로직 수행은 Worker Thread 에서 실행
● IO Thread 는 항상 non-blocking 방식으로 처리된다.
○ IO Thread 는 I/O 수행 요청이 생기면 즉시 I/O 에 대한 부분만 처리 후 다른 처리 부분은
Worker Thread 로 넘기고 즉시 또 다른 I/O 수행을 처리하거나 대기하게됨
● 반면 Worker Thread 는 하나의 Request의 완전한 처리를 위해서 blocking 되어 처리를 수행함
● Undertow는 request/response 의 모든 데이터를 HttpServerExchange 객체에 담아서 처리한다.
RequestBufferingHandler 수행 로직 소개
11
● Undertow는 Request header가 도착하면 HttpServerExchange 객체를 생성하여
RequestBufferingHandler.handleRequest() 메소드를 호출한다.
● RequestBufferingHandler.handleRequest() 메소드는 Request의 모든 데이터를 읽기 시도한다.
● 하지만 만약 패킷 전송 지연과 같은 경우 데이터 읽기를 기다려야 하는 경우 ChannelListener
객체를 생성하여 Connection 객체에 event listener로 등록한다.
● RequestBufferingHandler.handleRequest() 메소드의 수행은 종료된다.
● 이제 다시 나머지 패킷 데이터가 전송되면 Connection 객체가 등록된 listener 객체에 데이터 전송
이벤트를 알려주어 ChannelListener 객체의 handleEvent() 메소드가 콜백되어 다시 데이터를
읽게된다.
● 데이터를 모두 읽었다면 버퍼링 데이터 객체(bufferedData[]) 에 데이터를 넣고 HttpServerExchange
객체에 담은 후 다음 handler로 호출을 넘긴다.
RequestBufferingHandler 수행 로직 소개
12
RequestBufferingHandler
수행 로직 상세
13
● 새로운 Request가 도착하면, 가장 먼저 해당 Request 의 모든 데이터가 이미 모두 읽혀졌는지
확인한다. 그리고 동시에 header에 "Expect: 100-continue" 가 존재하는지 확인한다.
○ if(!exchange.isRequestComplete() &&
!HttpContinue.requiresContinueResponse(exchange.getRequestHeaders()))
● 만약 Request 의 모든 데이터가 이미 모두 읽혀졌다면 RequestBufferingHandler의 버퍼링 로직
수행 없이 바로 다음 handler로 호출이 넘겨진다(=> 다음 filter 수행 또는 Worker Thread 로
dispatch).
● 만약 아직 Request 의 모든 데이터를 읽지 못 하였고, "Expect: 100-continue" header 가 존재하지
않는다면, 다음의 버퍼링 로직을 수행하게된다.
RequestBufferingHandler 수행 로직 상세
14
RequestBufferingHandler 수행 로직 상세
● Connection 채널에서 데이터를 읽어서 버퍼(b)에 채워넣는 루프를 수행한다.
● 데이터를 모두 읽었다면 버퍼(b) 데이터를 bufferedData[] 에 넣고 exchange 객체에 담은 후 다음
handler로 호출을 넘기고 루프를 종료한다.
● 하지만 데이터를 읽는 중에 네트워크 지연등의 이유로 데이터가 아직 도착하지 않고 기다려야 하는
조건이 발생하면 기다리지 않고(non-blocking) 즉시 ChannelListener 객체를 생성하여 Connection
객체에 event listener로 등록한다. 이렇게되면 더이상 Thread 실행 없이 기다릴 수 있게된다
(non-blocking).
● (나머지 패킷) 데이터가 다시 도착하면 IO Thread에서 Connection 객체가 등록된 event listener
객체에 데이터 전송 이벤트를 알려주어 handleEvent() 메소드가 콜백되어 데이터를 읽게된다.
● 이제 다시 나머지 패킷 데이터가 전송되면, 위의 수행 로직과 동일한 "Connection 채널에서
데이터를 읽어서 버퍼(b)에 채워넣는 루프"를 수행한다. 데이터를 모두 읽었다면 버퍼(b) 데이터를
bufferedData[] 에 넣고 exchange 객체에 담은 후 다음 handler로 호출을 넘기고 루프를 종료한다. 15
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if(!exchange.isRequestComplete() && !HttpContinue.requiresContinueResponse(exchange.getRequestHeaders())) {
do {
// 채널에서 데이터를 읽어서 버퍼(b)에 채워넣기기 루프
ByteBuffer b = buffer.getBuffer();
r = channel.read(b);
if (r == -1) {
// 데이터 다읽어서 exchange 객체에 담고 리턴
} else if(r == 0) {
// 데이터 없어서 기다림
channel.getReadSetter().set(new ChannelListener<StreamSourceChannel>() {
public void handleEvent(StreamSourceChannel channel) {
do {
// 채널에서 데이터를 읽어서 버퍼(b)에 채워넣기 루프
if (r == -1) {
// 데이터 다읽어서 exchange 객체에 담고 리턴
} else if (r == 0) {
// 데이터 없어서 기다림
} else if (!b.hasRemaining()) {
// 버퍼(b)가 꽉참 => 데이터 크기가 버퍼보다 크다는 의미
// expression="buffer-request(buffers=2)" 와 같이 buffers 사이즈가 1보다 크다면
// bufferedData[]에 버퍼(b)를 백업하고 새로운 버퍼(b)를 할당 받아서 "채널에서 데이터 읽어서 버퍼(b)에 채워넣기기 루프"를 돌면서 나머지 데이터를 읽게됨
}
// 버퍼(b)에 아직 빈 공간이 남아있음
} while (true);
}
});
} else if (!b.hasRemaining()) {
// 버퍼(b)가 꽉참 => 데이터 크기가 버퍼보다 크다는 의미
}
// 버퍼(b)에 아직 빈 공간이 남아있음
} while (true);
}
next.handleRequest(exchange);
}
16
● Connection 채널에서 데이터를 읽는 단위가 버퍼(b) 사이즈이다.
○ 버퍼(b) 사이즈는 IO subsystem의 buffer-size 값으로 설정된다.
○ <buffer-pool name="default" buffer-size="<정수값>"/>
○ 기본값 16 kbytes
● buffer-size * buffers 배열 사이즈 만큼 Request 데이터를 버퍼링 할 수 있다.
○ buffers 는 버퍼(b)들을 담는 배열 객체
○ <expression-filter name="buf" expression="buffer-request(buffers=<정수값>)"/>
● buffer-size 를 기본값 보다 크게 buffers 값을 1보다 크게 설정한다면 “java.lang.OutOfMemoryError:
Direct buffer memory” 에러가 발생할 수 있다.
● RequestBufferingHandler 에서 버퍼링 사이즈가 부족하더라도
FixedLengthStreamSourceConduit.read() 에서 데이터를 모두 읽어서 Request는 정상 처리됨
● 기본 설정값 사용 권장 buffer-size 기본값(16kb), buffers=1
추가 상세 정보
17
추가 상세 정보
[1] buffer-size 를 기본값 보다 크게 buffers 값을 1보다 크게 설정한다면 “java.lang.OutOfMemoryError: Direct buffer memory”
에러가 발생할 수 있다.
2018-02-17 11:25:30,259 ERROR [org.xnio.listener] (default I/O-1) org.xnio.ChannelListeners:94 - XNIO001007: A channel event listener threw an
exception: java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:693)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:57)
at org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:55)
at org.xnio.ByteBufferSlicePool.allocate(ByteBufferSlicePool.java:147)
at io.undertow.server.XnioByteBufferPool.allocate(XnioByteBufferPool.java:53)
at io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:177)
at io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:97)
at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
at io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:231)
at io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:218)
at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89)
at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) 18
[2] 데이터를 읽는 중에 네트워크 지연등의 이유로 데이터가 아직 도착하지 않고 기다려야 하는 조건이 발생하면
ChannelListener 객체를 생성하여 Connection 객체에 event listener로 등록한다.
https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/server/handlers/RequestBufferingHandler.java#L124-L125
RETURN *** Called io.undertow.server.handlers.RequestBufferingHandler.handleRequest() in thread default I/O-1
io.undertow.server.handlers.RequestBufferingHandler.handleRequest(RequestBufferingHandler.java:125)
io.undertow.predicate.PredicatesHandler.handleRequest(PredicatesHandler.java:93)
io.undertow.server.handlers.SetHeaderHandler.handleRequest(SetHeaderHandler.java:90)
io.undertow.server.handlers.accesslog.AccessLogHandler.handleRequest(AccessLogHandler.java:138)
org.wildfly.extension.undertow.Host$HostRootHandler.handleRequest(Host.java:345)
io.undertow.server.handlers.NameVirtualHostHandler.handleRequest(NameVirtualHostHandler.java:54)
io.undertow.server.handlers.error.SimpleErrorPageHandler.handleRequest(SimpleErrorPageHandler.java:78)
io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:49)
org.wildfly.extension.undertow.Server$DefaultHostHandler.handleRequest(Server.java:189)
io.undertow.server.handlers.ChannelUpgradeHandler.handleRequest(ChannelUpgradeHandler.java:211)
io.undertow.server.protocol.http2.Http2UpgradeHandler.handleRequest(Http2UpgradeHandler.java:129)
io.undertow.server.handlers.DisallowedMethodsHandler.handleRequest(DisallowedMethodsHandler.java:61)
io.undertow.server.Connectors.executeRootHandler(Connectors.java:326)
io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:254)
io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136)
io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59)
org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89)
org.xnio.nio.WorkerThread.run(WorkerThread.java:591)
19
[3] (나머지 패킷) 데이터가 다시 도착하면 IO Thread에서 Connection 객체가 등록된 event listener 객체에 데이터 전송
이벤트를 알려주어 handleEvent() 메소드가 콜백되어 데이터를 읽게된다.
https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/server/handlers/RequestBufferingHandler.java#L77-L99
RETURN *** Called io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent() in thread default I/O-1
io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:99)
io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:77)
org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:231)
io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:218)
org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89)
org.xnio.nio.WorkerThread.run(WorkerThread.java:591)
20
References
● https://gist.github.com/tedwon/e89afe58a458850d0ebd30efa9967971
●

Contenu connexe

Tendances

Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing SwaggerTony Tam
 
Getting Started with Spring for GraphQL
Getting Started with Spring for GraphQLGetting Started with Spring for GraphQL
Getting Started with Spring for GraphQLVMware Tanzu
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOTVMware Tanzu
 
An Introduction To Automated API Testing
An Introduction To Automated API TestingAn Introduction To Automated API Testing
An Introduction To Automated API TestingSauce Labs
 
Understanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple StepsUnderstanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple StepsTessa Mero
 
Building Modern APIs with GraphQL
Building Modern APIs with GraphQLBuilding Modern APIs with GraphQL
Building Modern APIs with GraphQLAmazon Web Services
 
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkNative Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkZachary Klein
 
Test in Rest. API testing with the help of Rest Assured.
Test in Rest. API testing with the help of  Rest Assured.Test in Rest. API testing with the help of  Rest Assured.
Test in Rest. API testing with the help of Rest Assured.Artem Korchevyi
 
Thousands of Threads and Blocking I/O
Thousands of Threads and Blocking I/OThousands of Threads and Blocking I/O
Thousands of Threads and Blocking I/OGeorge Cao
 
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기정민 안
 
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...luisw19
 
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECK
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECKDeploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECK
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECKImma Valls Bernaus
 
Writing REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger AdaWriting REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger AdaStephane Carrez
 
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin Knauf
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin KnaufWebinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin Knauf
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin KnaufVerverica
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive ProgrammingKnoldus Inc.
 
Testing RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkTesting RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkMicha Kops
 

Tendances (20)

Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing Swagger
 
Getting Started with Spring for GraphQL
Getting Started with Spring for GraphQLGetting Started with Spring for GraphQL
Getting Started with Spring for GraphQL
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOT
 
OpenAPI 3.0.2
OpenAPI 3.0.2OpenAPI 3.0.2
OpenAPI 3.0.2
 
An Introduction To Automated API Testing
An Introduction To Automated API TestingAn Introduction To Automated API Testing
An Introduction To Automated API Testing
 
Understanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple StepsUnderstanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple Steps
 
Building Modern APIs with GraphQL
Building Modern APIs with GraphQLBuilding Modern APIs with GraphQL
Building Modern APIs with GraphQL
 
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut FrameworkNative Cloud-Native: Building Agile Microservices with the Micronaut Framework
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
 
Test in Rest. API testing with the help of Rest Assured.
Test in Rest. API testing with the help of  Rest Assured.Test in Rest. API testing with the help of  Rest Assured.
Test in Rest. API testing with the help of Rest Assured.
 
Thousands of Threads and Blocking I/O
Thousands of Threads and Blocking I/OThousands of Threads and Blocking I/O
Thousands of Threads and Blocking I/O
 
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
 
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
 
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECK
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECKDeploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECK
Deploying Elasticsearch and Kibana on Kubernetes with the Elastic Operator / ECK
 
Writing REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger AdaWriting REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger Ada
 
API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0
 
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin Knauf
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin KnaufWebinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin Knauf
Webinar: 99 Ways to Enrich Streaming Data with Apache Flink - Konstantin Knauf
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
 
Rest assured
Rest assuredRest assured
Rest assured
 
Api Testing
Api TestingApi Testing
Api Testing
 
Testing RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkTesting RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured framework
 

Similaire à Undertow RequestBufferingHandler 소개

하스켈학교 세미나 - Haxl
하스켈학교 세미나 - Haxl하스켈학교 세미나 - Haxl
하스켈학교 세미나 - HaxlJooyung Han
 
Iocp 기본 구조 이해
Iocp 기본 구조 이해Iocp 기본 구조 이해
Iocp 기본 구조 이해Nam Hyeonuk
 
android_thread
android_threadandroid_thread
android_threadhandfoot
 
고급시스템프로그래밍
고급시스템프로그래밍고급시스템프로그래밍
고급시스템프로그래밍kimkiweon
 
[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성NAVER D2
 
비동기 파일 로딩
비동기 파일 로딩비동기 파일 로딩
비동기 파일 로딩Bongseok Cho
 
log-monitoring-architecture.pdf
log-monitoring-architecture.pdflog-monitoring-architecture.pdf
log-monitoring-architecture.pdfSungkyun Kim
 
Concurrent servers
Concurrent serversConcurrent servers
Concurrent serversTonyYoon12
 
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요dgmit2009
 
파이썬 웹프로그래밍 1탄
파이썬 웹프로그래밍 1탄 파이썬 웹프로그래밍 1탄
파이썬 웹프로그래밍 1탄 SeongHyun Ahn
 
HeadFisrt Servlet&JSP Chapter 13
HeadFisrt Servlet&JSP Chapter 13HeadFisrt Servlet&JSP Chapter 13
HeadFisrt Servlet&JSP Chapter 13J B
 
Servlet jsp 13장
Servlet jsp 13장Servlet jsp 13장
Servlet jsp 13장JeongBong Kim
 
C# Game Server
C# Game ServerC# Game Server
C# Game Serverlactrious
 
11 윈도우스레드풀
11 윈도우스레드풀11 윈도우스레드풀
11 윈도우스레드풀ssuser0c2478
 
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfOS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfHo Jeong Im
 

Similaire à Undertow RequestBufferingHandler 소개 (20)

하스켈학교 세미나 - Haxl
하스켈학교 세미나 - Haxl하스켈학교 세미나 - Haxl
하스켈학교 세미나 - Haxl
 
Iocp 기본 구조 이해
Iocp 기본 구조 이해Iocp 기본 구조 이해
Iocp 기본 구조 이해
 
Iocp advanced
Iocp advancedIocp advanced
Iocp advanced
 
android_thread
android_threadandroid_thread
android_thread
 
고급시스템프로그래밍
고급시스템프로그래밍고급시스템프로그래밍
고급시스템프로그래밍
 
[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성
 
비동기 파일 로딩
비동기 파일 로딩비동기 파일 로딩
비동기 파일 로딩
 
log-monitoring-architecture.pdf
log-monitoring-architecture.pdflog-monitoring-architecture.pdf
log-monitoring-architecture.pdf
 
Concurrent servers
Concurrent serversConcurrent servers
Concurrent servers
 
Servlet3
Servlet3Servlet3
Servlet3
 
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요
DGMIT 제3회 R&D 컨퍼런스 r&d1 team : HTTP 프로토콜 개요
 
파이썬 웹프로그래밍 1탄
파이썬 웹프로그래밍 1탄 파이썬 웹프로그래밍 1탄
파이썬 웹프로그래밍 1탄
 
HeadFisrt Servlet&JSP Chapter 13
HeadFisrt Servlet&JSP Chapter 13HeadFisrt Servlet&JSP Chapter 13
HeadFisrt Servlet&JSP Chapter 13
 
Servlet jsp 13장
Servlet jsp 13장Servlet jsp 13장
Servlet jsp 13장
 
Nodejs_chapter3
Nodejs_chapter3Nodejs_chapter3
Nodejs_chapter3
 
4-2. ajax
4-2. ajax4-2. ajax
4-2. ajax
 
Ropasaurusrex
RopasaurusrexRopasaurusrex
Ropasaurusrex
 
C# Game Server
C# Game ServerC# Game Server
C# Game Server
 
11 윈도우스레드풀
11 윈도우스레드풀11 윈도우스레드풀
11 윈도우스레드풀
 
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfOS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
 

Plus de Ted Won

JBoss EAP 7 & JDG 7 최신 기술 소개
JBoss EAP 7 & JDG 7 최신 기술 소개JBoss EAP 7 & JDG 7 최신 기술 소개
JBoss EAP 7 & JDG 7 최신 기술 소개Ted Won
 
JBoss Modules Internal
JBoss Modules InternalJBoss Modules Internal
JBoss Modules InternalTed Won
 
오픈 소스 컨트리뷰션 가이드
오픈 소스 컨트리뷰션 가이드오픈 소스 컨트리뷰션 가이드
오픈 소스 컨트리뷰션 가이드Ted Won
 
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...Ted Won
 
Jenkins X - automated CI/CD solution for cloud native applications on Kubernetes
Jenkins X - automated CI/CD solution for cloud native applications on KubernetesJenkins X - automated CI/CD solution for cloud native applications on Kubernetes
Jenkins X - automated CI/CD solution for cloud native applications on KubernetesTed Won
 
Hawkular overview
Hawkular overviewHawkular overview
Hawkular overviewTed Won
 
Complex Event Processing with Esper
Complex Event Processing with EsperComplex Event Processing with Esper
Complex Event Processing with EsperTed Won
 
JDG 7 & Spark Integration
JDG 7 & Spark IntegrationJDG 7 & Spark Integration
JDG 7 & Spark IntegrationTed Won
 
지금 핫한 Real-time In-memory Stream Processing 이야기
지금 핫한 Real-time In-memory Stream Processing 이야기지금 핫한 Real-time In-memory Stream Processing 이야기
지금 핫한 Real-time In-memory Stream Processing 이야기Ted Won
 
Nara - Personalized Web Recommendation Service Quick Review
Nara - Personalized Web Recommendation Service Quick ReviewNara - Personalized Web Recommendation Service Quick Review
Nara - Personalized Web Recommendation Service Quick ReviewTed Won
 
JBoss Community's Application Monitoring Platform
JBoss Community's Application Monitoring PlatformJBoss Community's Application Monitoring Platform
JBoss Community's Application Monitoring PlatformTed Won
 
Real-time Big Data Analytics Practice with Unstructured Data
Real-time Big Data Analytics Practice with Unstructured DataReal-time Big Data Analytics Practice with Unstructured Data
Real-time Big Data Analytics Practice with Unstructured DataTed Won
 
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...Ted Won
 
Building Real-time CEP Application with Open Source Projects
Building Real-time CEP Application with Open Source Projects Building Real-time CEP Application with Open Source Projects
Building Real-time CEP Application with Open Source Projects Ted Won
 
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기Ted Won
 
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링Ted Won
 
RHQ 공감 Seminar 6th
RHQ 공감 Seminar 6thRHQ 공감 Seminar 6th
RHQ 공감 Seminar 6thTed Won
 
Complex Event Processing with Esper
Complex Event Processing with EsperComplex Event Processing with Esper
Complex Event Processing with EsperTed Won
 

Plus de Ted Won (18)

JBoss EAP 7 & JDG 7 최신 기술 소개
JBoss EAP 7 & JDG 7 최신 기술 소개JBoss EAP 7 & JDG 7 최신 기술 소개
JBoss EAP 7 & JDG 7 최신 기술 소개
 
JBoss Modules Internal
JBoss Modules InternalJBoss Modules Internal
JBoss Modules Internal
 
오픈 소스 컨트리뷰션 가이드
오픈 소스 컨트리뷰션 가이드오픈 소스 컨트리뷰션 가이드
오픈 소스 컨트리뷰션 가이드
 
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...
Jenkins X Hands-on - automated CI/CD solution for cloud native applications o...
 
Jenkins X - automated CI/CD solution for cloud native applications on Kubernetes
Jenkins X - automated CI/CD solution for cloud native applications on KubernetesJenkins X - automated CI/CD solution for cloud native applications on Kubernetes
Jenkins X - automated CI/CD solution for cloud native applications on Kubernetes
 
Hawkular overview
Hawkular overviewHawkular overview
Hawkular overview
 
Complex Event Processing with Esper
Complex Event Processing with EsperComplex Event Processing with Esper
Complex Event Processing with Esper
 
JDG 7 & Spark Integration
JDG 7 & Spark IntegrationJDG 7 & Spark Integration
JDG 7 & Spark Integration
 
지금 핫한 Real-time In-memory Stream Processing 이야기
지금 핫한 Real-time In-memory Stream Processing 이야기지금 핫한 Real-time In-memory Stream Processing 이야기
지금 핫한 Real-time In-memory Stream Processing 이야기
 
Nara - Personalized Web Recommendation Service Quick Review
Nara - Personalized Web Recommendation Service Quick ReviewNara - Personalized Web Recommendation Service Quick Review
Nara - Personalized Web Recommendation Service Quick Review
 
JBoss Community's Application Monitoring Platform
JBoss Community's Application Monitoring PlatformJBoss Community's Application Monitoring Platform
JBoss Community's Application Monitoring Platform
 
Real-time Big Data Analytics Practice with Unstructured Data
Real-time Big Data Analytics Practice with Unstructured DataReal-time Big Data Analytics Practice with Unstructured Data
Real-time Big Data Analytics Practice with Unstructured Data
 
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...
Red Hat Forum 2012 - JBoss RHQ - Java Application Monitoring & Management Pla...
 
Building Real-time CEP Application with Open Source Projects
Building Real-time CEP Application with Open Source Projects Building Real-time CEP Application with Open Source Projects
Building Real-time CEP Application with Open Source Projects
 
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기
JCO 11th 클라우드 환경에서 Java EE 운영 환경 구축하기
 
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링
JBoss RHQ와 Byteman을 이용한 오픈소스 자바 애플리케이션 모니터링
 
RHQ 공감 Seminar 6th
RHQ 공감 Seminar 6thRHQ 공감 Seminar 6th
RHQ 공감 Seminar 6th
 
Complex Event Processing with Esper
Complex Event Processing with EsperComplex Event Processing with Esper
Complex Event Processing with Esper
 

Undertow RequestBufferingHandler 소개

  • 1. RequestBufferingHandler 필터 로직 상세 소개 JBoss EAP 7.1 Undertow JBUG Korea @tedwon
  • 2. "default task-1" #97 prio=5 os_prio=0 tid=0x000000000401cfe0 nid=0x44d5 runnable [0x00007fd1f6dd7000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000000e2fa5718> (a sun.nio.ch.Util$3) - locked <0x00000000e2fa5708> (a java.util.Collections$UnmodifiableSet) - locked <0x00000000e2fa55f0> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101) at org.xnio.nio.SelectorUtils.await(SelectorUtils.java:51) at org.xnio.nio.NioSocketConduit.awaitReadable(NioSocketConduit.java:358) Issue ● Intermittent long-running request thread 발생 ○ over 5 secs, normally under 1 secs ○ Causing running threads accumulation !! ● Performance Issue !!! ● Why does this occur ? ● Needs investigation 2
  • 3. "default task-1" #97 prio=5 os_prio=0 tid=0x000000000401cfe0 nid=0x44d5 runnable [0x00007fd1f6dd7000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000000e2fa5718> (a sun.nio.ch.Util$3) - locked <0x00000000e2fa5708> (a java.util.Collections$UnmodifiableSet) - locked <0x00000000e2fa55f0> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101) at org.xnio.nio.SelectorUtils.await(SelectorUtils.java:51) at org.xnio.nio.NioSocketConduit.awaitReadable(NioSocketConduit.java:358) at org.xnio.conduits.AbstractSourceConduit.awaitReadable(AbstractSourceConduit.java:66) at org.xnio.conduits.AbstractSourceConduit.awaitReadable(AbstractSourceConduit.java:66) at io.undertow.conduits.ReadDataStreamSourceConduit.awaitReadable(ReadDataStreamSourceConduit.java:101) at io.undertow.conduits.FixedLengthStreamSourceConduit.awaitReadable(FixedLengthStreamSourceConduit.java:285) at org.xnio.conduits.ConduitStreamSourceChannel.awaitReadable(ConduitStreamSourceChannel.java:151) at io.undertow.channels.DetachableStreamSourceChannel.awaitReadable(DetachableStreamSourceChannel.java:77) at io.undertow.server.HttpServerExchange$ReadDispatchChannel.awaitReadable(HttpServerExchange.java:2161) at org.xnio.channels.Channels.readBlocking(Channels.java:295) at io.undertow.servlet.spec.ServletInputStreamImpl.readIntoBuffer(ServletInputStreamImpl.java:184) at io.undertow.servlet.spec.ServletInputStreamImpl.read(ServletInputStreamImpl.java:160) at com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper.ensureLoaded(ByteSourceJsonBootstrapper.java:522) ... at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:326) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:812) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 3
  • 4. ● Web Browser => Apache => JBoss EAP ● Where is it from ? ○ EAP ? ○ Apache ? ● Access log ● Capturing tcpdumps Investigation 4
  • 5. ● Web Browser => Apache => JBoss EAP ● By the tcpdump analysis, ● There is time gap between request header and body packet ● in Client side. Investigation - conclusion 5
  • 6. Undertow 버전 ● EAP 7.1 은 Undertow 1.4.18.Final 버전을 사용 ○ https://access.redhat.com/articles/112673#EAP_7 ○ https://github.com/undertow-io/undertow/tree/1.4.18.Final 6
  • 8. RequestBufferingHandler 기본 소개 ● Undertow 가 제공하는 HTTP Handler(filter) 중 하나 ● 기능: ○ Request 의 모든 패킷 데이터가 도착 하면 Request를 Worker Thread 로 dispatch 한다. ● 효과: ○ 해당 필터를 추가하면 간헐적 네트워크 지연등으로 Request 패킷 전송이 늦어지는 경우 Worker Thread 의 데이터 읽기 대기 상태(epollWait)로 인한 thread blocking 상태를 피할 수 있다. ● 영향: ○ GC 대상 객체 추가 발생. 지연 발생 요청 건마다 RequestBufferingHandler 의 이벤트 listener 객체(40 bytes)가 생성되고 요청 완료 후 GC의 대상이됨. ● 소스코드: ○ https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/serv er/handlers/RequestBufferingHandler.java 8
  • 10. ● Undertow의 Thread 실행은 IO Thread 와 Worker Thread 로 구성되어 실행 RequestBufferingHandler 수행 로직 소개 10
  • 11. ● IO Thread 는 이름 그대로 I/O 만 담당하는 Thread ● Request의 비즈니스 로직 수행은 Worker Thread 에서 실행 ● IO Thread 는 항상 non-blocking 방식으로 처리된다. ○ IO Thread 는 I/O 수행 요청이 생기면 즉시 I/O 에 대한 부분만 처리 후 다른 처리 부분은 Worker Thread 로 넘기고 즉시 또 다른 I/O 수행을 처리하거나 대기하게됨 ● 반면 Worker Thread 는 하나의 Request의 완전한 처리를 위해서 blocking 되어 처리를 수행함 ● Undertow는 request/response 의 모든 데이터를 HttpServerExchange 객체에 담아서 처리한다. RequestBufferingHandler 수행 로직 소개 11
  • 12. ● Undertow는 Request header가 도착하면 HttpServerExchange 객체를 생성하여 RequestBufferingHandler.handleRequest() 메소드를 호출한다. ● RequestBufferingHandler.handleRequest() 메소드는 Request의 모든 데이터를 읽기 시도한다. ● 하지만 만약 패킷 전송 지연과 같은 경우 데이터 읽기를 기다려야 하는 경우 ChannelListener 객체를 생성하여 Connection 객체에 event listener로 등록한다. ● RequestBufferingHandler.handleRequest() 메소드의 수행은 종료된다. ● 이제 다시 나머지 패킷 데이터가 전송되면 Connection 객체가 등록된 listener 객체에 데이터 전송 이벤트를 알려주어 ChannelListener 객체의 handleEvent() 메소드가 콜백되어 다시 데이터를 읽게된다. ● 데이터를 모두 읽었다면 버퍼링 데이터 객체(bufferedData[]) 에 데이터를 넣고 HttpServerExchange 객체에 담은 후 다음 handler로 호출을 넘긴다. RequestBufferingHandler 수행 로직 소개 12
  • 14. ● 새로운 Request가 도착하면, 가장 먼저 해당 Request 의 모든 데이터가 이미 모두 읽혀졌는지 확인한다. 그리고 동시에 header에 "Expect: 100-continue" 가 존재하는지 확인한다. ○ if(!exchange.isRequestComplete() && !HttpContinue.requiresContinueResponse(exchange.getRequestHeaders())) ● 만약 Request 의 모든 데이터가 이미 모두 읽혀졌다면 RequestBufferingHandler의 버퍼링 로직 수행 없이 바로 다음 handler로 호출이 넘겨진다(=> 다음 filter 수행 또는 Worker Thread 로 dispatch). ● 만약 아직 Request 의 모든 데이터를 읽지 못 하였고, "Expect: 100-continue" header 가 존재하지 않는다면, 다음의 버퍼링 로직을 수행하게된다. RequestBufferingHandler 수행 로직 상세 14
  • 15. RequestBufferingHandler 수행 로직 상세 ● Connection 채널에서 데이터를 읽어서 버퍼(b)에 채워넣는 루프를 수행한다. ● 데이터를 모두 읽었다면 버퍼(b) 데이터를 bufferedData[] 에 넣고 exchange 객체에 담은 후 다음 handler로 호출을 넘기고 루프를 종료한다. ● 하지만 데이터를 읽는 중에 네트워크 지연등의 이유로 데이터가 아직 도착하지 않고 기다려야 하는 조건이 발생하면 기다리지 않고(non-blocking) 즉시 ChannelListener 객체를 생성하여 Connection 객체에 event listener로 등록한다. 이렇게되면 더이상 Thread 실행 없이 기다릴 수 있게된다 (non-blocking). ● (나머지 패킷) 데이터가 다시 도착하면 IO Thread에서 Connection 객체가 등록된 event listener 객체에 데이터 전송 이벤트를 알려주어 handleEvent() 메소드가 콜백되어 데이터를 읽게된다. ● 이제 다시 나머지 패킷 데이터가 전송되면, 위의 수행 로직과 동일한 "Connection 채널에서 데이터를 읽어서 버퍼(b)에 채워넣는 루프"를 수행한다. 데이터를 모두 읽었다면 버퍼(b) 데이터를 bufferedData[] 에 넣고 exchange 객체에 담은 후 다음 handler로 호출을 넘기고 루프를 종료한다. 15
  • 16. public void handleRequest(final HttpServerExchange exchange) throws Exception { if(!exchange.isRequestComplete() && !HttpContinue.requiresContinueResponse(exchange.getRequestHeaders())) { do { // 채널에서 데이터를 읽어서 버퍼(b)에 채워넣기기 루프 ByteBuffer b = buffer.getBuffer(); r = channel.read(b); if (r == -1) { // 데이터 다읽어서 exchange 객체에 담고 리턴 } else if(r == 0) { // 데이터 없어서 기다림 channel.getReadSetter().set(new ChannelListener<StreamSourceChannel>() { public void handleEvent(StreamSourceChannel channel) { do { // 채널에서 데이터를 읽어서 버퍼(b)에 채워넣기 루프 if (r == -1) { // 데이터 다읽어서 exchange 객체에 담고 리턴 } else if (r == 0) { // 데이터 없어서 기다림 } else if (!b.hasRemaining()) { // 버퍼(b)가 꽉참 => 데이터 크기가 버퍼보다 크다는 의미 // expression="buffer-request(buffers=2)" 와 같이 buffers 사이즈가 1보다 크다면 // bufferedData[]에 버퍼(b)를 백업하고 새로운 버퍼(b)를 할당 받아서 "채널에서 데이터 읽어서 버퍼(b)에 채워넣기기 루프"를 돌면서 나머지 데이터를 읽게됨 } // 버퍼(b)에 아직 빈 공간이 남아있음 } while (true); } }); } else if (!b.hasRemaining()) { // 버퍼(b)가 꽉참 => 데이터 크기가 버퍼보다 크다는 의미 } // 버퍼(b)에 아직 빈 공간이 남아있음 } while (true); } next.handleRequest(exchange); } 16
  • 17. ● Connection 채널에서 데이터를 읽는 단위가 버퍼(b) 사이즈이다. ○ 버퍼(b) 사이즈는 IO subsystem의 buffer-size 값으로 설정된다. ○ <buffer-pool name="default" buffer-size="<정수값>"/> ○ 기본값 16 kbytes ● buffer-size * buffers 배열 사이즈 만큼 Request 데이터를 버퍼링 할 수 있다. ○ buffers 는 버퍼(b)들을 담는 배열 객체 ○ <expression-filter name="buf" expression="buffer-request(buffers=<정수값>)"/> ● buffer-size 를 기본값 보다 크게 buffers 값을 1보다 크게 설정한다면 “java.lang.OutOfMemoryError: Direct buffer memory” 에러가 발생할 수 있다. ● RequestBufferingHandler 에서 버퍼링 사이즈가 부족하더라도 FixedLengthStreamSourceConduit.read() 에서 데이터를 모두 읽어서 Request는 정상 처리됨 ● 기본 설정값 사용 권장 buffer-size 기본값(16kb), buffers=1 추가 상세 정보 17
  • 18. 추가 상세 정보 [1] buffer-size 를 기본값 보다 크게 buffers 값을 1보다 크게 설정한다면 “java.lang.OutOfMemoryError: Direct buffer memory” 에러가 발생할 수 있다. 2018-02-17 11:25:30,259 ERROR [org.xnio.listener] (default I/O-1) org.xnio.ChannelListeners:94 - XNIO001007: A channel event listener threw an exception: java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:693) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:57) at org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:55) at org.xnio.ByteBufferSlicePool.allocate(ByteBufferSlicePool.java:147) at io.undertow.server.XnioByteBufferPool.allocate(XnioByteBufferPool.java:53) at io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:177) at io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:97) at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:231) at io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:218) at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) 18
  • 19. [2] 데이터를 읽는 중에 네트워크 지연등의 이유로 데이터가 아직 도착하지 않고 기다려야 하는 조건이 발생하면 ChannelListener 객체를 생성하여 Connection 객체에 event listener로 등록한다. https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/server/handlers/RequestBufferingHandler.java#L124-L125 RETURN *** Called io.undertow.server.handlers.RequestBufferingHandler.handleRequest() in thread default I/O-1 io.undertow.server.handlers.RequestBufferingHandler.handleRequest(RequestBufferingHandler.java:125) io.undertow.predicate.PredicatesHandler.handleRequest(PredicatesHandler.java:93) io.undertow.server.handlers.SetHeaderHandler.handleRequest(SetHeaderHandler.java:90) io.undertow.server.handlers.accesslog.AccessLogHandler.handleRequest(AccessLogHandler.java:138) org.wildfly.extension.undertow.Host$HostRootHandler.handleRequest(Host.java:345) io.undertow.server.handlers.NameVirtualHostHandler.handleRequest(NameVirtualHostHandler.java:54) io.undertow.server.handlers.error.SimpleErrorPageHandler.handleRequest(SimpleErrorPageHandler.java:78) io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:49) org.wildfly.extension.undertow.Server$DefaultHostHandler.handleRequest(Server.java:189) io.undertow.server.handlers.ChannelUpgradeHandler.handleRequest(ChannelUpgradeHandler.java:211) io.undertow.server.protocol.http2.Http2UpgradeHandler.handleRequest(Http2UpgradeHandler.java:129) io.undertow.server.handlers.DisallowedMethodsHandler.handleRequest(DisallowedMethodsHandler.java:61) io.undertow.server.Connectors.executeRootHandler(Connectors.java:326) io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:254) io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136) io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59) org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) org.xnio.nio.WorkerThread.run(WorkerThread.java:591) 19
  • 20. [3] (나머지 패킷) 데이터가 다시 도착하면 IO Thread에서 Connection 객체가 등록된 event listener 객체에 데이터 전송 이벤트를 알려주어 handleEvent() 메소드가 콜백되어 데이터를 읽게된다. https://github.com/undertow-io/undertow/blob/1.4.18.Final/core/src/main/java/io/undertow/server/handlers/RequestBufferingHandler.java#L77-L99 RETURN *** Called io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent() in thread default I/O-1 io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:99) io.undertow.server.handlers.RequestBufferingHandler$1.handleEvent(RequestBufferingHandler.java:77) org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:231) io.undertow.channels.DetachableStreamSourceChannel$SetterDelegatingListener.handleEvent(DetachableStreamSourceChannel.java:218) org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) org.xnio.nio.WorkerThread.run(WorkerThread.java:591) 20