Easy Understanding

백엔드 파트만 훑어본 개발 행사 몇 가지 후기(NHN FORWARD, 우아한테크 콘서트) 본문

Dev

백엔드 파트만 훑어본 개발 행사 몇 가지 후기(NHN FORWARD, 우아한테크 콘서트)

appleg1226 2020. 12. 17. 23:13

연말이라 그런지 많은 개발 회사들에서 컨퍼런스들을 개최하고 있습니다.

원래는 네이버 DEVIEW도 당일에 세션을 시청은 했으나, 너무 많아서 나머지 영상들이 아직은 풀리지 않아서 보류!

 

개발 행사들이 뉴스나 커뮤니티나 여기저기에서 소식들이 있어서 즐겁게 탐방을 하러 갔습니다.

 


NHN FORWARD(2020. 12. 14 ~ 15)

 

 

NHN은 메인 키노트 주제부터가 AI였습니다.

대부분의 세션이 AI와 관련된 세션들로 구성되어 있었습니다.

 

그렇지만 당장은 제가 제일 관심이 있는 백엔드와 인프라를 중심으로 세션을 시청했습니다.

그리고 그 중에서 제가 관심있게 본 세션들을 간단하게 정리해보려고 합니다.

 

1) 내가 만든 Webflux가 느렸던 이유

얼마 전에 면접에서 Webflux의 논블로킹을 제대로 설명하지 못해서 당황했던 기억이 있는데,

이 영상을 보고 개념적으로 완벽하게 이해가 되었습니다.

구체적인 테스트 상황에서 Webflux의 성능을 비교해주어 이해가 쉽게 됐습니다.

 

테스트 과정에서 나타난 Webflux를 사용하면서 주의해야할 점 몇 가지는 다음과 같습니다.

- 블로킹 I/O는 성능을 저하시킨다: 특히 log()는 블로킹을 일으킨다. 

- map / flatMap은 확실히 다르다: map은 동기적 작업을 처리하며, flatMap은 비동기적으로 내부를 변경한다.

  map을 너무 많이 사용하면 연산마다 객체를 생성하기 때문에 많은 GC를 일으킨다.

- map 내부에 논블로킹 I/O 메서드를 넣으면 스레드가 블로킹된다. 

- BlockHound: blockhound 라이브러리를 사용하면 Blocking 코드를 탐지할 수 있다.

- Reactor Meltdown: Blocking이 걸리는 I/O 때문에 시스템이 Hang이 걸리기도 하는데 이런 상황을

  meltdown이라고 한다. 이를 위해서 blocking 작업에는 subscribeOn()이나 publishOn()으로 스레드풀을

  따로 분리해주는 방법도 있다.

 

2) 캐시 성능 향상을 위한 시도

이 세션에서 말하는 캐시의 문제는 중간에 캐시의 만료시간이 겹쳤을 때 캐시 데이터를 가져오는 데에 시간이 걸린다는 것과, 밀린 요청으로 인해 중복적으로 캐시 업데이트가 이루어진다는 것이었습니다.

 

이를 위해서 캐시 데이터에 각종 상태값들을 추가하여 해결을 했다고 합니다.

또한 데이터가 만료되기 이전에 업데이트 과정을 추가하는 방법을 사용하기도 했습니다.

 

NHN 벅스에선 이런 캐시 시스템을 만든 노하우를 통해 캐시를 다루는 오픈소스 라이브러리인 Catcher까지도 만들게 되었다고 합니다. 확실히 괜찮은 개발 조직은 보통 이렇게 더 깊은 단계로 나아가는 과정이 있기 때문에 계속해서 발전하는 것이 아닌가 싶습니다.

 

제대로 만들려면 캐시도 여러 가지로 신경을 많이 써줘야 한다는 것을 느끼니, 백엔드 개발자도 참 공부해야 할 것이 많다는 것을 느꼈습니다.

 

3) Kotlin과 Coroutine으로 만들어 보는 Non-Blocking API

코루틴의 개념과 웹플럭스 환경에서 코루틴 시스템을 구성하는 튜토리얼 등을 다루고 있습니다.

개념 설명 위주라서 가볍게 보고 넘겼습니다.

 

4) RabbitMQ and Cloud Messaging Platform

해당 발표는 Toast 클라우드 팀에서 클라우드 메시징 플랫폼을 개발한 경험을 공유한 것입니다.

자사 서비스에 RabbitMQ를 도입하게 된 이유에 대하여 설명하였고, 그 차이는 다음과 같습니다.

 

- RabbitMQ vs Kafka

1. Rabbit은 큐의 개념, Kafka는 로그가 쌓이는 개념에 가깝다

2. Rabbit은 Broker가 smart한 반면, Kafka는 Consumer가 smart하다.(할 일이 많다)

3. 그렇기 때문에 Rabbit보다 Kafka가 결합도가 높다

4. 애초에 Kafka는 metric, log, event sourcing 등 특별한 용도로 사용하는 경우가 많다.  

 

- Cloud Messaging Platform에서의 문제 상황 해결

Rabbit에 트래픽이 몰려서 특정 서비스가 독점을 할 우려가 있기 때문에,

동적으로 사용자로 Queue를 할당하여 Fairness 문제를 해결하고 합니다.

 

5) MSA 환경에서 API 문서 관리하기: 생성부터 배포까지

기존 환경이 아닌 MSA 환경에서는 API 문서를 어떻게 작성하고 관리할까에 대한 고민이 담긴 발표입니다.

 

발표에서는 기존의 Swagger 중심의 시스템에서 Spring java docs로 문서작성 시스템을 변경했습니다.

또한 만들어진 파일을 OpenAPI spec으로 변경합니다.

그리고 배포 과정에 Jenkins pipeline과 Ansible을 이용해서

Swagger UI 서버로 모아서 API 문서를 관리하게 되었다고 합니다.

 

6) 읽기 좋은 Kotlin 가이드

코틀린을 사용하면서 약간의 팁 같은 것들이 들어있는 세션이었습니다.

몇 가지만 설명하자면 확장함수의 사용, 적절한 프로퍼티의 사용, 연산자 오버로딩 등이 있었습니다.

가벼운 kotlin 팁들이지만 유용하게 쓸 수 있을 것 같습니다.


우아한테크콘서트(2020. 12. 16 ~ 18)

 

배민에서는 이번 우아한테크콘서트가 처음 이루어지는 기술 컨퍼런스라고 합니다.

모든 세션을 들으면 쿠폰이 발행되고 이것들을 전부 모으면 스타벅스 기프티콘을 준다고 합니다.

(그렇지만 귀찮아서 패스)

 

대체로 세션들의 내용은 이전 레거시 시스템에서 현재 시스템으로의 변화 과정을 전반적으로 다루는 것 같습니다. 

아무래도 서비스가 몇 년 간 급격하게 커지면서 여러 어려움들이 있었고 그것들을 어떻게 해결했는지에 대해서

자료들이 많이 쌓여있던 것 같습니다. 

 

1) 배달의 민족 마이크로서비스 여행기

인프런에서 강의도 하시고, JPA 책으로 유명하신 김영한님께서 진행하신 세션입니다.

배달의 민족이 기존 IDC에서 운영하던 시스템들을 전부 AWS로 올린 것과,

Monolothic한 시스템을 MSA 환경으로까지 어떤 과정을 거쳐서 변화시켰는지의 과정을

전체적으로 확인할 수 있었습니다.

 

제가 기억해둬야겠다고 메모해 놓은 내용은 다음의 내용들입니다.

 

- API에서 이벤트 기반의 메시징으로

기존에 API를 통해서 요청을 처리했고, 사실 이건 굉장히 보편적인 방식입니다. 

하지만 API의 호출을 요청한 부분에서는 그 응답을 기다리는 동안 blocking이 될 수도 있고, error 처리가 이루어질 수도 있기 때문에, 약간의 의존성이 존재합니다.

그렇지만 이런 것들을 AWS의 SNS, SQS를 이용하여 이벤트를 보내는 식으로 해결을 했다고 합니다.

그렇게 되면 기존 호출 시스템에서는 이벤트만 발행해 놓고 이후에는 문제의 책임을 분산시킬 수가 있게 됩니다.

이런 메시지 기반의 시스템은 장애가 연쇄되지 않기 때문에 편리한 개발 환경을 구축할 수 있습니다.

그리고 메시지를 보낼 때 데이터들을 전부 보내는 방식도 있지만, 이렇게 하면 중간에 데이터 정합성 문제가 생길 수 있기 때문에, 이런 것들을 위해서 Zero payload, 즉 id만 보내는 식으로 하고, 메시지를 받은 뒤에 다시 API 요청을 하는 식으로 시스템을 구성하였다고 합니다.

 

- CQRS(Command and Query Responsibility Segregation) 아키텍처의 적용

CQRS는 사실 저도 처음 들어본 개념입니다.

MSA 환경에서는 업데이트가 많이 필요한 시스템이 있고, 반면 조회가 주를 이루는 시스템이 있는데 이를 분리하여

관리하는 것을 말하는 것 같습니다.

특정 도메인에선 이 아키텍쳐를 구성하여 서로 의존성이 줄어 장애에 견고한 시스템을 만들고자 했습니다.

그래서 위의 메시징을 사용하여 업데이트 결과를 메시지로 발행해주고, 

조회 시스템에서는 그 이벤트들을 활용하여 각자 필요한대로 업데이트하고 데이터를 받아오는 식으로 구성을 했습니다.

 

- 마지막으로

마이크로서비스는 시스템 규모, 트래픽, 사람 이라는 조건이 충족되어야 변환의 가치가 있다고 합니다.

실제로 간단하게 조인 하나면 이루어지는 것이 여러 시스템 간의 조율이라는 거대한 흐름으로 바뀌기 때문에,

MSA에 대해서 오랜만에 다시 생각하게 되는 말씀이었습니다.

 

2) 배민 프론트서버의 사실과 오해

프론트서버는 프론트엔드와는 다소 다른 개념입니다.

프론트엔드나 앱에서 데이터를 받아오기 위해 거치는 앞단의 서버구나라고 생각하시면 됩니다.

MSA 환경에서는 여러 API의 호출이 필요하지만 이것을 사용자 단에서 직접 전부 호출하는 것보다는,

프론트서버에 호출을 하면, 프론트서버에서 데이터들을 호출하여 모아서 알맞게 전달해주게 됩니다.

 

1.

우선 배민 프론트서버에서는 Spring Webflux를 사용한다고 합니다.

왜냐하면 배민은 보통 15000TPS의 요청을 다룬다고 합니다.

그리고 한 번의 요청으로 호출해야 하는 내부 API의 갯수는 약 14개라고 합니다.

그렇다면 이러한 트래픽을 동시에 받는다면 15000 * 14 = 210,000 개의 스레드를 만들어야 하는데 이렇게 만드는 것은 시간이나 관리 측면에서 복잡해질 수밖에 없습니다.

 

위의 다른 세션 설명에서도 말씀드렸다시피, Webflux는 자체 이벤트루프를 통해 적은 갯수의 스레드로 여러 요청들을 처리할 수 있기 때문에, 이런 많은 요청을 다룬다면 굉장히 빠른 성능 향상을 경험할 수 있습니다.

 

2.

또한 프론트서버는 용도에 따라서 여러 DB를 사용한다고 합니다. 앞단에는 Redis, 데이터 저장에는 Reactive를 지원하는 MongoDB, 이벤트 저장에는 DynamoDB, 자체 시스템을 위한 데이터의 저장에는 RDS를 이용한다고 합니다. 

 

3. 

그리고 내부 시스템을 도메인 주도 설계의 방식으로 바꾸어 더 깨끗하고 안정적인 코드의 모습을 가지게 되었다고 합니다.

 


아마도 얼추 대부분의 개발 컨퍼런스는 들은 것 같습니다.

기업들이 이렇게 무료로 좋은 지식들을 나누어주어서 저는 정말 감사합니다.

혼자서는 경험할 수 없는 개발 관련된 지식들을 배울 수 있어서 너무 좋았습니다.

 

매년 이런 컨퍼런스를 참여하는 것을 목표로 앞으로 개발 공부를 해나가려고 합니다.

내년에는 코로나가 종식되고 직접 참여할 수도 있기를 바래봅니다.

(물론 그 전에 취업부터...)