코엑스에서 열렸던 if kakao 개발자 컨퍼런스 2018에 참여하였습니다. 컨퍼런스에서 다루었던 주제는 Map 관련, AI, 빅데이터, 모바일, 백엔드, 블록체인, 오픈소스 등이 있었는데요. 저는 이 중에서 주로 하고 있는 일인 블록체인과 백엔드 관련 세션만 참석하였고, 본 포스팅에서도 이 주제들만 후려쳐서 정리하였습니다(ㅠㅠ). 오탈자나 틀린 정보가 있다면 넓은 아량으로 양해 부탁드리겠습니다.

if kakao 2018


9RUM, kakao Cloud Native Playform - 공용준(andrew.kong)

if kakao 2018

클라우드란 무엇일까?

2016: Programmable Resource Management -> 2017: Programmable Resource Life Cycle Management -> 2018: Programmable Service Management

CMMI Model에 따라 진화하는 클라우드 세계.

KRANE, 카카오의 Iaas

IaaS를 왜하는가? 개발 서비스에 한해서 셀프 서비스를 만들어 보자.

  • BareMetal TBD, KVM, LB, DB
  • Inhouse Auth, IMS(Service Topology), AEZORO
  • Data Center Level Scalable Network

KEMI, 카카오의 Maas

컴퓨팅 리소스가 많이 필요하다보니 CMM2 단계로 올라감.

요구사항

  1. 실서비스에 들어가려면 VM 모니터링이 필요
  2. 기존 오퍼레이터들이 사용하던 것과 비슷하게 맞춰달라.

if kakao 2018

특징

  • 전형적인 람다 아키텍쳐(스트림 따로, 배치 따로)
  • 모니터링 추상화

if kakao 2018

DKOS, 카카오의 CaaS

만들어 놨는데 UI에서 VM 만드는 수준으로만 사용하고, 네트워크 function은 어려워서 다루기 꺼려함.

  • 모든 API를 사용해서 컨테이너 오케스트레이션, 컨테이너 스케줄링, 컴포넌트 플랫폼을 제공, D2Hub(도커 레지스트리) 추가해서 네트워크 레벨도 사용하기 쉽게 만들어놨다.
  • DKOS Worker 뒷단에 DKOS LoadBalancer(L7)를 놓고 물리장비 LoadBalancer를 통하도록 구성.
  • Private cloud 레벨로 전사 공용 AutoScale 가능.

지금은 쿠버네티스 지원가능하도록 만들어놨는데 기존에 Mesos에서 Kubernetes로 바꾸는데 6개월 걸림(한명이..)

Cloud Native

요구사항

  • Containerized
  • MSA
  • Dynamically ochestrated

이런게 왜 필요한지 스스로 질문해 봐야 하는데, 동적으로 조절(Dynamically orchestrated)되는 플랫폼이 필요하다(DevOps 쪽 인적 자원이 많이 줄어들고 있기도함).

그래서 CMI4로 9rum이라는 Cloud Native Platform을 만들게 되었다.

  • Isolation
  • Scheduling
  • Service Discovery

if kakao 2018

카카오에서 가장 중점적으로 개발한 것은 Integrated SSO.

  • 기존의 인증이 너무 번거로워서!!
  • OAuth2를 인증 백엔드로 사용(Inhouse auth)
  • IMS라는 CMDB는 ERP와 붙여놓음(private cloud지만, billing report까지)
  • 최초 인증 한번만 하면 KRANE, DKOS, KEMI 모두 로그인 가능

결과

  • Indexing Data: 50TB / Day
  • Expense: CPU와 메모리만 보면 연간 800억 정도 사용중
  • License Expense: 0

현재 준비 중인 오픈소스(오픈 예정)

  • https://github.com//kakao/kfield
  • https://github.com//kakao/d2hub

질의응답

  • Q. Serverless는 고려하지 않았나요?
  • A. Serverless는 URL 별로 function 따로따로 개발해서 만드는데, 무엇이 더 급할까 생각해보니, 앱 런쳐도 없는데 Function as Service가 왠말이냐해서, Serverless보다는 Container를 먼저 개발하게 되었다.

Klaytn: Service-Oriented Enterprise-Grade Public Blockchain Platform - 한재선

진행 순서: 블록체인 기술 소개, 기술 이슈, Klaytn(클레이튼) 소개

if kakao 2018

Blockchain basic

Blockchain은 이것들의 조합

  • Distributed Ledger Technology(DLT)
  • Distributed Consensus Mechanism
  • P2P
  • Smart Contract & Dapp
  • Token Economy Model
  • Decentralized Governance Model

Hash Pointer

  • Data를 무결성에 대한 체크를 가능하게끔 하는 용도

Block Hash

  • point to the previous block

Detecting Tampering

  • 데이터 수정에 대한 비교가 가능함(수정이 된 내용은 다음 포인터를 참조해서 확인).

Block Structure

  • Header + Contents(실제 트랜잭션 기록) + Hash pointer + Merkle root

Merkle Proof

  • 플라즈마 등 사이드 체인에서 많이 사용됨.
  • 트랜잭션에 대한 해쉬값들을 모두 저장하는 것이 아니라, 각 해쉬값들을 섞어서 다시 해싱한 값을 트리로 구성한 것. 모든 해쉬값들을 다 저장할 필요가 없기 때문에 데이터를 효과적으로 저장할 수 있다.
  • 이 블록 내에 특정 데이터가 있는지 확인하기 좋음(Merkle proof)

P2P Network

  • 풀노드: 모든 컨텐츠를 저장하고 있는 노드(비트코인)
  • 현재 비트코인은 1만개 정도의 노드가 있다.
  • Mining은 consensus 알고리즘이라고 볼 수 있음(이 블록이 맞는지 합의).
  • Block -> Proof-of-Work -> BlockChain에 추가

PoW(Proof-of-Work)

  • 간단히 말하자면 nonce라고 불리는 랜덤 값을 맞추는 것

BFT(비잔틴 폴트 톨로런스)

Smart Contract

  • 가스비 때문에 효율적인 작성이 요구됨.
  • 토큰은 결국 돈으로 연결되기 때문에 보안에 신경을 많이 써야함.

Dapp

  • MVC에서 MC라고 보면 됨.
  • 프론트엔드(web3) + 블록체인 백엔드(EVM위에 Smart Contract)

Blockchain Scalability Issues

Daily Active User

  • 페이스북 14억, 트위터 1억 5천, 하지만 이더리움이 받을 수 있는 트랜잭션의 수는 140만개, 비트코인은 100만개도 안됨
  • 이 환경에서 서비스를 돌린다는건 말이 안되는 상황.

On-Chain solution

  • 이더리움 자체에 성능을 향상 시키는것(Sharding). 하지만 다른 샤드간(inter shard) 커뮤니케이션 하는 것이 문제.

Off-Chain Solution

  • 이더리움은 가만히 놓은 상태에서 새로운 형태의 체인을 만드는것.
  • State Channel: On-Chain의 Smart Contract에 해당 계약에 대한 구체적인 로직을 담아 놓고(검증용), 자주 발생되는 트랜잭션은 Off-Chain(외부)에서 실행되도록.
  • Side-Chain: 별도의 Chain을 만들고, Integrate는 메인넷에서 확인.
  • local consensus이기 때문에 빠름.
  • 현재 플라즈마 사이드체인이 가장 유명한데, 머클트리 형태로 만들어서 머클트리의 루트만 플라즈마 컨트랙트에 저장함. Root Chain(Ethereum)에 스마트 컨트랙트는 만들어 놔야함.

if kakao 2018

Klaytn: Service-Oriented Enterprise-Grade Public Blockchain Platform

현재 블록체인 메인넷들이 가지고 있는 문제점

  1. Finality: 트랜잭션이 확실히 커밋이 됐다는 것
  2. Poor Performance
  3. Operation Costs
  4. Enterprise Considerations
  5. Inconvenient UX

그래서 우리는 Hybrid하게 접근하려 한다(Consensus는 private하게 하고, Auditing은 public하게).

Private consensus with public auditing = BFT-variant consensus + Open Validation

  • consensus는 제한된 노드. scalability는 올림. BFT 기반의 합의 알고리즘 사용
  • write operation은 이녀석이 처리

Rander Node(RN)

  • copy된 블록들을 가지고 Auditing
  • read request를 처리해주는 역할

Write / Read operation은 따로따로 가져가도록 구성

Proof-of-Participation

  • Proof of Replication: 블록 데이터를 다 저장하고 있다
  • Proof Serving Clients: 실제 Request에 대한 처리를 잘 해주는지를 검사

if kakao 2018

기본적으로 Klaytn은 Scalability와 Finality에 초점을 맞춰서 설계했음.

consensus 알고리즘은 기본적으로 수천 TPS가 한계임(노드를 추가한다고 해도 똑같은 일).

현재 Servicechain을 이용해서 궁극적으로 Scalability를 올릴 생각하고 있음.

Challenge

  • 솔직히 유저 입장에서 블록체인이 무엇인지 알아가면서 서비스를 이용한다는 것은 비정상적으로 보임(느리면 느린 이유를 알아야 할까?)
  • Scalability 뿐만 아니라 UI/UX에 대한 고민이 많이 필요하다. 지갑을 어떻게 유저들이 쉽게 쓸 수 있게 만들 것이냐. 토큰을 거래하고 싶은데 거래소를 무조건 가야하는가?.

계획

10월에 테스트넷 오픈. 요청하시면 검토 후 private 오픈 예정

질의응답

  • Q. 플랫폼 위에 올라갈 서비스는 고민하고 있는가?
  • A. stackoverflow & github 같은 coworking 할 수 있는 서비스도 같이 오픈할 예정이다.
  • Q. Smart Contract 개발 언어는 어떤것으로 할 예정?
  • A. Solidity

액티브X 없는 블록체인 기반 PKI 시스템 - 이한욱(nate.act)

if kakao 2018

PKI(Public Key Infrastructure) 소개

공개키 기반 -> 전자 서명 -> 인증서

기존 공인인증서의 문제점

"액티브 X" 단어 하나로 문제 설명.

기존 공인인증서의 문제점 해결

기존의 액티브X가 사용자의 컴퓨터에서 비밀키를 관리했다면, 카카오페이 인증은 국민 모두가 사용하고 있는 카카오에 비밀키를 관리하는 방식이다.

기존 NPKI 폴더 복사 가능하고, Brute Force Attack에 취약한데.. 그렇다면 비밀키를 어떻게 관리하면 좋을까?

사용자의 password와 카카오페이의 Server-side passphrase를 조합해서 비밀키를 관리한다. 카카오페이 서버를 통해 관리되기 때문에 Brute Force 공격은 원천적으로 막을 수 있음.

블록체인

비트코인 공개 네트워크 활용 -> 하이퍼레저 패브릭

왜 블록체인을 사용했어야 했는가?

  • Service provider 입장에서는 사용자의 전자서명이 옳은 것인지 확인하기 위해 public key를 꺼내서 전자서명이 옳은 것인지를 검증하게 되는데, 이 인증서 자체에 대한 검증 자체도 이루어져야 한다. 이 부분을 검증하기 위해 블록체인을 사용하게 되었다.
  • Blockchain Immutable Database

2016년 개발 당시에 사용할 수 있었던 것은 비트코인 네트워크 밖에 없었기 때문에 당시에는 이를 활용해서 개발했다. 비트코인 넷에서는 OP_RETURN 스크립트를 활용해서 일반 데이터를 저장할 수 있다(사이즈는 제한적으로). 인증서를 해쉬한 값을 비트코인 넷에 기록하였다.

Finality of Bitcoin

  1. 블록 생성 시간은 10분
  2. 적어도 6개 정도의 confirmation을 받아야함.
  3. 블록포함 시점 불분명 => 서비스 제공자 입장에서 이는 치명적임.

이를 극복하기 위해 Hyperledger fabric(리눅스 foundation에서 진행하고 있는 프로젝트)로 마이그레이션했다.

하이퍼레저 패브릭

  • Enterprise
  • Private permission Network: 아무나 참여 불가
  • No coin But Asset: 굳이 무거운 메인넷에 참여하거나, 보상을 받을 필요가 없다.
  • Hash chain, Shared Ledger, smart contracts 등 지원

트랜잭션이 ordering service(중앙화된 노드들)에 제출되면 ordering service는 블록을 생성해서 각 peer들에 전달되고, 각 peer들은 검증에 들어간다.

2초에 한번씩 블록 생성되고, 생성 즉시 블록체인에 포함됨(Immediate Finality).

질의응답

  • Q. 파트너사에서 노드를 참여하면 중앙화된 노드, 즉 ordering service에 참여하게 될거고, 트랜잭션을 직접 관리할 수 있을텐데 그럼 REST API 통신하는 것 없이 카카오페이 인증이 가능합니까? 아니면 기타 파트너사에게 득이 되는 부분은?
  • A. 아뇨 auth를 위해 rest api 통신은 해야합니다. 득이 되는 부분은…

스프링5 웹플럭스와 테스트 전략 - 이일민

대상: 자바 8+, 스프링 5.x, 스프링 기반 비동기/논블로킹, Reactor와 RxJava 기반 리액티브 프로그래밍

if kakao 2018

스프링 웹 플럭스

스프링이 5.0에 새로 등장한 웹 프레임워크 + 리액티브 스택. 초기 이름은 스프링 웹 리액티브에서 웹 플럭스로 바뀜.

Spring 5: SpringMVC + WebFlux

  • Spring MVC: 서블릿 기반 스프링 스택
  • Spring WebFlux: 리액티브 스택

WebFlux에 보이는 Reactive repository는 뭘까? (Flux가 포함된) Reactor 라이브러리가 왜 양쪽에 있는가?

Webflux와 MVC 양쪽에서 동일한 코드가 돌아간다. 그렇다면 다를바가 없는데 왜 등장한 것일까?

스프링 웹 플럭스 도입 이유

  • 100% (I/O, 데이터 처리) 논블로킹 개발
  • 확장성과 고효율성이 매우 중요
  • 업, 다운 스트리밍과 Back pressure가 필요
  • 고속 서비스 오케스트레이션 개발
  • 유사한 프로그래밍 모델의 경험
  • 유연하게 커스터마이징이 가능한 웹 프레임워크 구성
  • 본격적인 함수형 프로그래밍 모델 사용

스프링 웹 플럭스를 사용하지 않는게 좋은 이유

  • 웹 플럭스가 왜 필요한지 분명하게 모름
    • 비동기/논블로킹 방식 도입(X)
    • 리액티브 라이브러리(Reactor, RxJava) 사용(X)
  • 블로킹이 서버, 코드, 라이브러리에 존재
    • 블로킹 IO, 블로킹 서블릿 필터
    • JPA(X), JDBC(X)
    • ADBA(O), AoJ(?), R2DBC(?)
  • SpringMVC로 개발했더니 아무 문제 없음 (X)

스프링 웹 플럭스는 스프링 MVC로 시작해도 됨

스프링5 MVC는 웹 플럭스에서 제공되는 다양한 기능과 프로그래밍 모델 제공

  • 비동기/논블로킹 API 호출
  • 비동기/논블로킹 데이터 액세스
  • 리액티브 데이터 조회, 전송
  • 비동기 웹 요청
  • 서버 스트리밍
  • 클라이언트 스트리밍
  • Reactor(Flux, Mono), RxJava, Flow 등을 이용하는 코드

MVC에서 WebClient 사용이 가장 좋은 출발점

  • RestTemplate 대체

스프링 웹 플럭스를 꼭 쓸 이유도, 그렇지 않을 이유도 없다면 한번 써봐라. WebClient 하나만 알아가도 굿굿

리액티브 (함수형) 프로그래밍

  • 인터넷 시대의 복잡함을 해결하기 위해(Erik Meijer)
  • 연속적으로 일어나는 이벤트를 다루는 프로그래밍 기법
  1. UI 이벤트, 비동기적인 I/O 이벤트, 통제 불가능한 이벤트 스트림 처리
  2. 동시성, 비동기/논블록킹 호출을 다루는데 탁월
  3. 조합 가능한 비동기 로직을 다루는 함수형 프로그래밍

비동기/논블록킹 API 호출 - 가장 단순한 리액티브

동기/블록킹 API 호출(RestTemplate)

  • 장점: 쉽고 간단함
  • 단점: IO 동안 블록킹. 시스템 특성에 따라 매우 비효율적이 될 수도

비동기/논블로킹 API 호출

  • 적은 서버 리소스만 사용해서 많은 요청을 처리하자는 것이 핵심.
  • AsyncRestTemplate (Spring 4)
  • Async/Await (Java 8+)
  • WebClient (Spring 5)
  • 장점: 확장성이 뛰어나고 높은 처리율과 낮은 레이턴시를 가짐. 쉽고 직관적이고 간단하다.
  • 단점: 장점을 얻을 만한 경우가 많지 않음. 자칫하며 코드가 복잡하고 이해하기 어려움.

비동기/논블로킹 API 진화

  • Future -> DeferedResult -> CompletableFuture
  • 그리고 자바에서도 Async/Await 사용 가능
  • 마지막으로 Reactor Flux/Mono를 이용할 수 있음

Reactor Flux/Mono는 CompletableFuture와 유사해보이지만, 큰 장점이 있다.

  • Mono: 어떤 이벤트가 비동기적으로 넘어올 때 딱 1개까지만 허용함.
  • Flux: 데이터를 Stream으로 지속적으로 받을 수 있음. 캐시에 담은 다음에 Mono에 한꺼번에 넣어서 넘겨도 되긴 함.

CompletableFuture vs. Reactor Flux/Mono

공통점

  • 람다식으로 사용하는 함수형 스타일
  • 비동기와 비동기 작업의 조화(compose, flatMap)
  • 비동기와 동기 작업의 적용(apply, map)
  • Exceptional 프로그래밍
  • 작업별 쓰레드 풀 지정 가능

Flux/Mono 방식의 장점

  • 데이터 스트림(Flux) <-> List/Collection
  • 강력한 연산자 제공
  • 지연 실행, 병합, 분산, 시간 제어
  • 유연한 스케줄러
  • ReactiveStreams, 자바 9+ 표준
  • 다양한 지원 라이브러리, 서비스, 서버

리액티브 애플리케이션의 데이터 흐름

if kakao 2018

리액티브 API의 데이터 시퀀스 검증

Mono나 Flux를 가지고 있으면 이는 Reactive API라고 부를 수 있다.

단위 테스트를 할 수도 있지만, 그 뒷부분까지 통합 테스트를 할 수도 있다.

주의할 점: 테스트 코드는 항상 동기 방식이어야 한다. 하지만 우리가 테스트할 대상은 비동기/논블로킹 특성을 가지고 있다.

subscribe() + assert

@Test
void mono() {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  mono.subscribe(item -> assertThat(item).isEqualTo(1)); // 테스트 성공
}

@Test
void mono2() {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  mono.subscribe(item -> assertThat(item).isEqualTo(2)); // 테스트 성공??????
}

Mono나 Flux는 데이터를 리턴 값으로 받는 것이 아니라, 일종의 콜백을 받는 것이다.

Scheduler는 별도의 데몬 스레드에서 작동하는 것이기 때문에 subscribe() + assert 사용할때 조심해야 한다.

@Test
void mono3() throws InterruptedException {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  CountDownLatch latch = new CountDownLatch(1);

  mono.subscribe(item -> {
    assertThat(item).isEqualTo(2);
    latch.countDOwn();
  });

  latch.await();  // 테스트가 끝나지 않음!
}

그래서 CountDownLatch라는 걸 이용하면 됨. 테스트에서 동시성을 제어해야 함.

// 테스트에서 동시성을 제어해야 하는 번거로움!
@Test
void mono4() throws InterruptedException {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  CountDownLatch latch = new CountDownLatch(1);
  AtomicInteger item = new AtomicInteger();

  mono.subscribe(
    i -> item.set(i),
    e -> latch.countDown(),
    latch::countDown
  );

  latch.await();
  assertThat(item.get()).isEqualTo(1);
}

하지만 이렇게 작성해도 고통스러우니까 block()을 사용하면 좋음.

block() + assert

@Test
void mono5() throws InterruptedException {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  Integer item = mono.block();
  assertThat(item).isEqualTo(1);
}

StepVerifier

비동기/논블로킹 테스트에는 StepVerifier을 이용하자!

  • 비동기 논블로킹으로 동작하는 코드 테스트 툴
  • 데이터 스트림의 검증
  • 예외, 완료도 검증
  • 가상시간을 이용해 오랜 시간의 이벤트 테스트
@Test
void stepVerifier() {
  Mono<Integer> mono = Mono.just(1)
    .subscribeOn(Schedulers.single());

  StepVerifier.create(mono)
    .expectNext(1)          // 첫번째 데이터 아이템 값
    .verifyComplete();
}

@Test
void stepVerifier2() {
  var flux = Flux.just(1, 2, 3)
    .concatWith(Mono.error(new RuntimeException()))
    .subscribeOn(Schedulers.single())

  StepVerifier.create(flux)
    .expectNext(1)
    .expectNext(2)
    .expectNext(3)
    .expectError(RuntimeException.class)  // 에러나고 종료
    .verify();
}

리액티브 HTTP API 호출 테스트

RestTemplate

  • 동기/블록킹

AsyncRestTemplate

  • 비동기/논블록킹
  • Future 콜백, CompletionStage

WebClient

  • 비동기/논블록킹
  • Flux/Mono 요청, 응답
  • Streaming 지원
  • BackPressure 지원

WebClient를 사용하면 RestTemplate을 대신해서 비동기/논블로킹을 함수형 프로그래밍 스타일로 손쉽게 작성할 수 있다.

WebClient

@GetMapping("/api")
public Mono<String> helloAPi() {
  return client.get()
    .uri("/api/hello")
    .retrieve()
    .onStatus(HttpStatus::is4xxClientError,
      res -> Mono.error(new IllegalArgumentException()))
    .onStatus(HttpStatus::is5xxServerError,
      res -> Mono.error(new RuntimeException()))
    .bodyToMono(String.class)
    .map(body -> body.toUpperCase())  // 비지니스 로직 수행
    .switchIfEmpty(Mono.just("Empty"));
}

원격 리액티브 API 호출 - 통합테스트(feat. MockServer)

원격 테스트하려면 서버를 따로 띄워야 하는데 MockServer를 사용하면 Http API 통합 테스트를 할 수 있다.

MockServer를 포함하면, 간단하게 Http Request를 테스트할 수 있는 서버를 생성할 수 있다.

if kakao 2018

WebClientIntegrationTests는 유용한 샘플이니 참고하면 좋습니다.

private MockWebServer server;
private WebClient webClient;

@Before
public void setup() {
  var connector = new ReactorClientHttpConnector();
  this.server = new MockWebServer();
  this.webClient = WebClient
    .builder()
    .clientConnector(connector)
    .baseUrl(this.server.url("/").toString())
    .build();
}

@Test
public void shouldReceiveResponseHeaders() {
  prepareResponse(response -> response
    .setHeader("Content-Type", "text/plain")
    .setBody("Hello Spring!"));

  Mono<HttpHeaders> result = this.webClient.get()
    .uri("/greeting?name=Spring").exchange()
    .map(response -> response.headers().asHttpHeaders());

  StepVerifier.create(result).consumeNextWIth(
    httpHeaders -> {
      assertEquals(MediaType.TEXT_PLAIN, httpHeaders.getContentType());
      assertEquals(13L, httpHeaders.getContentLength()); })
    .expectComplete()
    .verify(Duration.olfSeconds(3));

  expectRequestCount(1);
  expectRequest(request -> {
    assertEquals("*/*", request.getHeader(HttpHeaders.ACCEPT));
    assertEquals("/greeting?name=Spring", request.getPath());
  });
}

interface HelloService {
  Mono<String> hello();
}

@Component
public class RemoteHelloService implements HelloService {
  public Mono<String> Hello() {
    return client.get()
      .uri("/hello")
      .retrieve()
      .onStatus(HttpStatus::is4xxClientError,
        res -> Mono.error(new IllegalArgumentException()))
      .onStatus(HttpStatus::is5xxServerError,
        res -> Mono.error(new RuntimeException()))
      .bodyToMono(String.class);
  }
}

@Autowired HelloService helloService; // Mock 서비스로 대체 가능

@GetMapping("/api")
public Mono<String> helloApi() {
  return this.helloService.hello()
    .map(body -> body.toUpperCase())
    .switchIfEmpty(Mono.just("Empty"))
    .doOnError(c -> c.printStackTrace());
}

웹 플럭스의 새로운 아키텍처

기존 MVC는 서블릿 스팩과 서버의 제약 위에 개발

  • 프론트 컨트롤러 패턴, MVC 패턴, 전략 패턴

웹 플럭스는 독자적인 아키텍처를 가지는 프레임워크

  • 서블릿(3.1+) 컨테이너를 사용할 수 있으나 의존적이지 않음
  • Netty, Undertow 서버 지원
  • 논블록킹 네트워크/논블록킹 API
  • 논블록킹 데이터 스트림
  • 서버/기술 의존적이지 않은 프레임워크 재구성 손쉬움
  • 함수형 엔드포인트
  • 뛰어난 테스트 편의성

if kakao 2018

EnableWebFlux 어노테이션을 추가하면

if kakao 2018

TestClient - @WebFluxText

Spring boot 2 애플리케이션의 Mock Test

  • bindToApplicationContext 이용
@RunWith(SpringRunner.class)
@WebFluxTest
public class WebCLientBootTest {
  @Autowired WebTestClient webTestClient;

  @Test
  public void hello() {
    webTestClient.get().uri("/hello/{name}", "Spring")
      .exchange()
      .expectStatus().isOk()
      .expectBody(String.class)
      .isEqualTo("Hello Spring");
  }
}
  • bindToRouterFunction: 함수형 엔드포인트에 대한 테스트
Mono<ServerResponse> handler(ServerRequest request) {
  return ServerResponse.ok().body(Mono.just("hello"), Spring.class);
}

@Test
void routerFunction() {
  ReouterFunction<ServerResponse> route =route(GET("/rf"), this::handler);

  WebTestClient client = WebTestClient.bindToRouterFunction(route).build();
  client.get().uri("/rf")
    .exchange()
    .expectStatus().isOk()
    .expectBody(String.class)
    .isEqualTo("hello");
}
  • bindToController: 특정 컨트롤러/핸들러만으로 테스트 대상 구성. 예를 들어 컨트롤러가 100개 있는 서버를 테스트하고 싶다면, 기존의 테스트 코드를 재사용 할 수 있다.
WebTestClient client = WebTestClient.bindToController(
  new MyController(), new HelloAPi()
).build();

client.get().uri("/hello/{name}", "Spring")
  .exchange()
  .expectStatus().isOk()
  .expectBody(String.class)
  .isEqualTo("Hello Spring");
  • bindToServer: static 메서드를 사용해서 실제 동작하는 서버에 연결해서 테스트할 수 있다.

함수형 엔드포인트 테스트 방법

  • bindToRouterFunction
  • \@WebFLuxTest
  • 함수 단위 테스트
    • 본격적인 함수형 스타일 웹 프로그래밍
    • 조합 가능한 마이크로 프레임워크
    • 작고 가벼운 비동기 논블록킹 웹