[카카오][세미나] Webflux로 막힘없는 프로젝트 만들기 - 정리
web/Spring

[카카오][세미나] Webflux로 막힘없는 프로젝트 만들기 - 정리

반응형

Spring Mvc

- 하나의 요청에 하나의 쓰레드만이 사용되기 때문에 직관적

- 요청 하나의 응답이 길어지게 되면 쓰레드 하나가 계속 붙잡히고 이렇게 쓰레드들이 계속 밀리게 되면 쓰레드풀이 고갈되어 전체 시스템에 문제가 발생

 

 

Spring Webflux

- 외부 시스템의 응답이 늦어져도 쓰레드가 홀딩되는 문제를 예방할 수 있다.

- reactor로 개발된 코드가 circuit breaker를 연동하는데 더욱 용이하다는 장점이 있다.

 

 

Reactor Meltdown

- webflux는 netty의 이벤트 루프 방식을 차용한 방식으로 queue에 쌓인 이벤트를 event loop 쓰레드가 이를 처리하는 방식으로 쓰레드풀 고갈 문제를 발생하지 않음

- mvc의 기본 업무 단위는 요청 webflux는 이벤트

- event 하나의 blocking 로직이 들어가게 될 경우 해당 이벤트를 처리하는 쓰레드만 블로킹이 되는 문제가 발생할 것 같지만 Event Loop 전체의 성능 저하를 야기함

 

- blocking 로직이 추가된 /sleep api와 정상 응답을 주는 /ok 응답 두개로 구성

- sleep 한번과 ok 10번이 동시에 실행되도록 작성. mvc에서는 하나의 쓰레드만 sleep으로 인해 블로킹이 되고 나머지 쓰레드는 정상 응답을 받아서 바로 종료됨. 하지만 event loop의 경우 아래 사진 처럼 ok 요청들에 blocking이 생김

 

하나의 blocking 요청으로 인해 다른 event들이 같이 block되는 테스트 코드

 

 

Reactor Meltdown 발생 이유 - event loop 동작방식에서 이유를 찾아보자.

- event loop는 이벤트와 메시지를 기다리고 전달하는 패턴을 의미.

 

- netty의 event loop는 이벤트가 발생하면 이벤트를 처리하는 적절한 handler에게 이벤트를 dispatch함

 

- event loop 하나에서 여러 채널에 event loop를 모니터링 함 

 

- event loop는 싱글 스레드로 동작함 

- 싱글 스레드이기에 들어온 이벤트를 바로 실행할 지 아니면 큐에적재할 지 항시 체크하는 로직이 들어가 있음

 

- 여러 executor service들과 같이 이벤트로 큐로 관리되며 FIFO 방식으로 이벤트가 처리됨

 

 

- 이벤트 루프의 라이프 싸이클은 다음과 같은 순서로 실행된다. 1)여러 채널의 이벤트를 모니터링 -> 2)발생된 이벤트를 처리하고 -> 3)큐에있는 모든 runnable을 take하여 처리함 

- 싱글 스레드이기 때문에 한쪽 cycle에서 지연이 발생하면 전체 루프에 영향이 끼침 

 

 

- 한쪽 채널에 지연이 발생하면 Event loop의 동작방식이 싱글 스레드이기 때문에 다른 채널에 모두 지연이 발생 되기 때문에 여러 채널에서 들어오는 모든 요청이 지연되는 meltdown이 발생됨

- 여러 채널을 통해서 들어온 이벤트를 event loop를 통해서 쓰레드풀 고갈없이 처리할 수 있다는 장점은 있지만 이런 문제로 blocking을 조심해야함

 

 

 

Rescue Event Loop

- 피치못하게 webflux내에서 blocking이 필요할 경우 subscribeOn, publishOn을 통해 Event Loop 내에서 동작하지 않고 별도 Scheduler를 통해서 동작할 수 있도록 격리를 해주는 작업이 필요

- Event Loop는 blocking 이벤트로 부터 안전하게 격리가능

 

 

- reactor는 기존의 taskExecutor를 통해 스케줄러를 생성하는 것보다 스케줄러 factory 메소드를 통해 생성하기를 권장

- single, parellel는 논블록 쓰레드를 지원하기에 순차, 동시 연차에 적합하며 blocking에 적합하지 않음

- blocking을 하기 위해서는 boundedElastic을 사용하도록 권장함

 

- 위에서 문제가 되었던 blocking 작업을 subscribeOn(Schedulers.boundedElastic())을 통해 별도 스케줄러로 격리 시켜 나머지 작업이 event loop내에서 정상 동작이 가능하도록 작성

 

 

 

Detect Bloking Code

- blockhound 라이브러리를 통해 미리 블록킹 로직이 있는 경우 에러를 탐지할 수 있도록 할 수 있듬

- 설치가 쉽고 custom이 가능해서 좋지만 복잡한 로직에서는 탐지가 불가능하고 자바 에이전트에 기동되어 자바 바이트 코드에 직접 접근하기 때문에 운영에서는 사용이 권장되지 않음

- 테스트코드와 결합해서 사용하기를 권장

 

 

 

내 생각)

- 전체적인 meltdown에 대한 개념과 blockhound등 내가 알던 것과 크게 다르지는 않았지만 하나의 blocking 이벤트가 하나의 쓰레드를 점유하고 나머지는 괜찮을거라 생각했었는데 전체 event loop의 영향을 준다는걸 알게되어서 좋았다. 

- 개념적으로 다시한번 돌이켜 볼 수 있어서 좋았다. 

 

 

출저 : https://if.kakao.com/session/107

 

반응형