Reactive 글 모음
- Iterable와 Observable의 개념
- Reactive History
- Reactive Streams
- RxJava
- Spring Reactive
- Reactive PublishOn, SubscribeOn
spring.io는 Java9과 함께 Reactive 아키텍처를 지원하는 Spring 5 버전을 내놓겠다고 발표했습니다. 그리고 현재 2017년 2월 중순 기준으로 5.0.0 M4가 릴리즈 되었습니다. 아직 Java9이 아직 릴리즈되지 않은 상태에서 spring.io가 조금 앞서 발빠르게 대응할 준비를 하고 있습니다. 개인적으로 Java 서버 개발에 아주 많은 점유율을 가지고 가고 있는 spring framework가 4.x대부터 변화하려는 것들을 보고 많이 놀랬는데 이번에도 놀랄 준비를 해야겠습니다. 특히 서버 사이드에서 Reactive Programming에 대한 필요는 늘어나고 있는데 spring이 이것을 제공해준다면 개발자들은 한발더 손쉽게 개발을 할수 있겠네요. Spring5에서부터는 java 8이상이여야 하고 servlet3.0 이상이여야 하는데 국내시장에서도 물론 많은 기업들이 java와 servlet버전을 올리고 있지만 기존 레거시 버전을 유지하려는 기업 또는 소프트웨어들이 많은 상태에서 과연 Spring5가 국내에서 얼마만큼 영향을 줄지는 미지수입니다. 하지만 spring이 트랜드에 따라 잘 쫒아가주고 있는 것을 보면 다른 언어에 뒤지지 않는 개발 생태계를 계속 끌어주고 있는거 같습니다. java가 끌고가는건지 spring이 끌고가는건지 모르겠네요… (java = spring은 아니지만 java개발자라고 불리는 사람들 중 스프링을 이용하여 개발하지 않는 분들이 얼마나 계실런지 모르겠습니다) 이번 포스팅에서는 spring에서 제공하는 reactive programming 예제를 살펴보면서 앞으로 사용하게 될지도 모를 spring reactive를 미리 경험해보도록 하겠습니다.
Project Reactor
Spring Reactive는 Reactor Core라는것을 사용하고 있습니다. Reactor Core는 Project Reactor의 프로젝트이며, 아직 다 완성되진 않았지만 Java9의 java.util.concurrent.Flow도 들어갈것으로 보입니다. Spring Reactor는 non-booking을 충분히 제공해주는 Reactive Streams라이브러리이며 많은 팀들이 조인하였는데 이중 spring.io가 눈에 보이네요 Project Reactor에는 Reactor Core, Reactor Test, Reactor IPC, Reactor Netty 4가지 프로젝트가 있으며 이중 Reactor Core가 Spring Reactive에 들어간 것입니다. 스프링부트-reactor를 통해 예제를 살펴볼텐데, 기존에 처음보는 React Core의 클래스를 몇가지 살펴본 후 예제를 보려고 합니다. Reactor Core의 도큐먼트를 보면 다음과 같이 나옵니다 제가 지금 작성하는 날짜 기준으로 3.0.4까지 버전이 나왔는데요, 스프링에서는 2.5부터 사용하고 있습니다. 우리가 하나하나 다 볼수는 없고 아래쪽에 초록색으로 링크가 바껴있는 부분들을 몇개 보면 Reactive Streams Flux, Mono라는게 나오고 reactor.core.publisher라는게 나오는데요, publisher는 우리가 Reactive Streams 스펙에서 본 퍼블리셔라고 생각하면 될거 같고 네이밍을 보니 패키지 같은데 저 안에 퍼블리셔들이 들어있나 봅니다. Flux는 처음에는 저도 잘 몰라서 열심히 구글링을 했는데 MVC와 비교하면서 페이스북은 mvc를 버리고 flux로 갔다고 하는 그 Flux인가? 도 싶었는데 그것과 연관이 있는건지는 잘 모르겠습니다. 어쨋든 Flux는 publisher에 있는걸 보니 Observable인거 같네요. 마찬가지로 mono도 검색하면 많이 나오는데요, 이거도 용어가 생소해서 검색하면 닷넷이 어쩌고 하는 위키도 나오고 하는데요, 얘도 걔랑 무슨 연관이 있는지는 잘 모르겠습니다.. 용어가 참 어렵네요, 여튼 얘도 보면 퍼블리셔 패키지에 있습니다. mono와 flux 둘다 퍼블리셔인데 무슨 차이가 있을까 보니 설명과 그림에서 차이가 납니다 우선 mono는 “at most one”이라고 해서 한건의 데이를 처리하는데 사용됩니다 (영어가 짧아서…) 결국 이 그림을 보면 mono가 데이터 한건을 처리해서 만약 operator가 잘 처리가 되었다면 원하는 데이터를 Subscriber에게 전달할 것이고, 문제가 생기면 에러를 보내주겠죠. 보면 우리가 RxJava의 예제에서 Observable.just(“hello world”)한것처럼 한건의 데이터를 처리하려고 할때 사용이 됩니다. 이게 무슨 말이면 하나의 subscription을 가질수 있다는 겁니다. 어렵지만 flux를 보면서 좀더 이해해보기로 하죠. 반대로 flux는 0에서 N개의 엘리먼트를 가질수 있고요, 그림을 보면 한건을 처리하던 mono와 달리 여러건을 처리하고 있죠, 그림에서 만약 4번에서 에러가 난다면 mono가 그랬듯이 에러를 subscriber에게 알려줄것이고, 잘 끝나면 complete하겠죠. RxJava에서 봤지만 여러건의 데이터, 즉 iterable한 데이터는 여러개의 subscription으로 나뉘고 합쳐져서 subscriber에게 전달되는데, 그와 비슷한 개념으로 flux는 iterable한 데이터들을 mono로 바꿔서 나누고 합침으로 해서 subscriber에게 전달합니다. 즉 mono가 뭉치면 flux라고 생각해도 좋을거 같습니다(이해를 돕기위해 이렇게 설명했지만 내부적으로는 어떻게 동작하는지는 아직 모르겠습니다, 나중에 기회가 되면 까보도록 하죠) 저는 이 두가지 용어가 너무 해깔렸습니다. 특히 구글에 쳐도 잘 안나왔고, 결국 깊숙히 이해하고 스프링블로그에서 여러 글들을 계속 읽으면서(영어 읽느냐 쥐나는줄 알았습니다) Project Reactor를 알게 되었고, 이 레퍼런스를 통해 이해를 하게 되었습니다. 사실 아무것도 모를때 위에 그림도 많이 봤고, Project Reactor라는 단어도 엄청 많이 본거 같은데 아는만큼 보인다고 Reactive Programming에 대해 계속 공부하다 보니 처음과는 다르게 이제는 이해가 조금씩 가는거 같습니다. 어쨋든 mono와 flux에 대해 이상한 곳에서 내용을 찾으시면서 삽질하지 마시고 Project Reactor의 레퍼런스를 참고하시길 바랍니다
Spring-boot Reactor 샘플
스프링부트-reactor 해당 링크를 통해 GitHub으로 들어가셔서 소스코드를 다운로드 받으실수 있습니다. 저 링크는 어디서 봤냐면 https://spring.io/blog/2016/07/28/reactive-programming-with-spring-5-0-m1 에서 봤습니다. 기회가 되시면 Github에서 소스코드를 받으시기 이전에 내용을 한번 읽어보셔도 좋을거 같습니다 소스코드를 받으시고 압축을 푸시셔 IDE를 통해 프로젝트를 열어보시면 여러 프로젝트가 보이실겁니다 이중 우리가 지금 살펴볼 것은 spring-boot-sample-web-reactive입니다. 쭉쭉 열어보시면 HomeController가 있는데요, 잠깐 살펴보고 가겠습니다 소스가 길지 않고 메소드도 몇개 없습니다. RestController이고 3개의 메소드가 있는데요, requestMapping으로 메소드가 url과 연결되어 있습니다. starter메소드를 보면 리턴타입이 Mono로 되어 있습니다. 우리가 금방 봤던 Reactor Core에 Mono입니다. Mono.just를 하는데 RxJava에서 Observable.just하는거와 같은 느낌이네요, new BootStarter를 해서 값을 넣어주는데 BootStart는 별거 없습니다 그냥 Vo입니다. Mono는 1건만 처리한다고 했기 때문에 저렇게 한개가 들어 갔네요. 이부분이 어떻게 사용되는지 이따가 테스트 코드에서 확인해보도록 하고 넘어가겠습니다 starters메소드는 Flux를 리턴하는데요, 얘도 마찬가지로 just로 만들고 여러 BootStarter를 받고 있습니다. customArg는 다양한 어규먼트를 받는다는걸 보여주려고 하는거 같은데 우리는 위에 두개만 보도록 하죠. 이 코드를 확인해보려면 테스트 패키지에 ReactiveSampleApplicationTests 클래스를 이용하시면 됩니다. 테스트코드라 코드가 많은데요 위에서부터 조금씩 보겠습니다 이 클래스는 유닛테스트를 위한 코드이고요, 저는 spring 2.5부터 쓰면서 테스트코드를 그때당시에 작성해서 보면 Repository나 Service는 테스트가 좀 쉽게 하는데, Controller부분이 좀 막막했었어요, Request나 Response를 가지고 Mock테스트를 하기가 번거롭고 어려웠던거 같습니다. 최근에는 SpringBootTest가 되서 저렇게 WebClient를 이용해서 편하게 테스트 하실수 있습니다. setup에서 저렇게 WebClient.create를 하시면 spring-boot가 올라가서 테스트를 진행해줍니다. 첫번째는 Mono테스트입니다 webClient를 이용해서 Mono를 받아오고요, Reactor Test에 있는 ScriptedSubscriber라는 Subscriber를 이용하여 데이터를 받아옵니다. 이건 좀 특이하게 Subsciber에 verify라는 메소드를 통해 Publisher를 주네요(Mono는 Publisher임을 잊지마세요) 보시면 consumeNextWith에서 assertThat으로 데이터를 체크하는 로직이 들어가 있습니다. 체크가 끝나면 expectComplete로 끝나게 되는 아주 간단한 예제입니다. 이코드를 보시고 어떻게 느끼실지는 각각 다 다르실것이고 생소하실수도 있고, 쉽게 느껴지실수도 있을거 같은데요. 우리가 바라보는 관점은 Reactive하게 데이터를 받아온다는 점을 주목하시길 바랍니다. 우선 다음으로 넘어가죠 두번째는 Flux테스트입니다 테스트코드만 보자면 크게 Mono와 다른점은 없습니다. 그저 consumeNextWith가 몇개 더 늘어났을 뿐입니다. mono테스트도 마찬가지로 여러개 늘리셔도 상관 없습니다. 결국 뭐냐면 Subscriber는 얘 나름대로 독립적으로 있는것이죠, 무슨말을 하고 싶냐면 데이터가 mono이든 flux든, 데이터 한건이든 여러건이든 그건 퍼블리셔의 일이고, Subscriber는 데이터가 몇건이 오든 자신이 처리해야 할 역활을 하는것이죠.
정리
사실 이 샘플만으로는 과연 스프링이 버전이 올라갔을 때 내가 꼭 Reactive를 써야 할까? 라는 의문이 들수도 있을겁니다. 단순히 코드만을 보고, 동작 자체만을 보고 ‘에이 아무것도 아니네’,’쉽게 짤수 있는걸 더 복잡하게 만드는거 아니냐’ 판단하지 마시고 우리가 처음 Observable에서 시작해서 Reactive Streams, RxJava를 거쳐서 Spring Reactive까지 오면서, 왜, 언제 Reactive Programming을 해야 하는지에 대해 많은 고민을 해야 하고, Reactive History를 통해 넷플릭스가 Reactive Programming을 도입하면서 얻은 효과들을 보면서, 우리가 넷플릭스와 같은 문제를 만났을 때 Reactive Programming을 해야 할 상황이 올때를 준비한다고 생각하시면 좋을것 같습니다.