우아한형제들 주관 테크컨퍼런스인 WOOWACON 2023에 참여했다!
정말 인기가 많았고 경쟁이 치열했다고 알고 있는 우아콘 2023.
확실히 사람들이 정말 많았다.
그리고 우테코, 우형 사람들이 정말 많았다...ㅋㅋ
이번 우아콘은 오프라인으로 열린다는 소식을 듣고 기대에 부푼 마음으로 참여해보았다.
사내에서 주최되는 행사이기도 하고, 사내 정책에 따라 컨퍼런스 참여는 근무시간으로 인정받을 수 있어서 팀원분이랑 함께 세션을 들으러 갔다.
굉장히 많은 세션들이 있었고, 나는 아래와 같이 세션을 들었다.
11:00 ~ 11:40 A-대규모 트랜잭션을 처리하는 배민 주문시스템 규모에 따른 진화
11:55 ~ 12:30 A-모놀리식에서 점진적 서비스 분리: 사업과제와 병행하여 시스템 개선하기
14:00 ~ 14:40 A-대용량 트래픽을 받는 모놀리식 서비스에 Woowa하게 RPC 적용하기
14:55 ~ 15:35 A-배민스토어에 최신 기술 한방에 때려넣기: Kotlin, Spring WebFlux, EDA
15:50 ~ 16:15 A-낯선 서드파티와의 동행: 믿을 만한 배민커넥트 서버 구축하기
16:35 ~ 17:15 A-Kafka를 활용한 이벤트 기반 아키텍처 구축
17:30 ~ 18:10 G-ElastiCache 운영을 위한 우아한 가이드: 초고속 메모리 분석 툴 개발기와 레디스 운영 노하우 소개
재밌는 세션들도 있었고, 나에게 어려운 세션들도 있었다.
한번 하나하나 후기를 남겨보도록 하겠다.
(추가로 맨 마지막에 일기같은 내용이 있다.
개발얘기 보기 싫으면 맨마지막 - 마치며 쪽으로 쭉 내리면 된다 ㅋㅋ)
대규모 트랜잭션을 처리하는 배민 주문시스템 규모에 따른 진화
주문팀에 계신 분께서 발표해주신 세션이다.
몰랐는데, 배민은 일 평균 300만건에 달하는 주문이 들어온다고 한다. 2018년에는 일 평균 100만건도 꿈의 숫자라고 했는데, 2023년에는 훨씬 많이 늘었다고.
이에 따라, 아래와 같은 문제점들이 발생했다고 한다.
- 단일 장애포인트
- 대용량 데이터 RDBMS 조인
- 대규모 트랜잭션 쓰기 처리량 한계
- 규칙 없는 이벤트 발행으로 인한 서비스 복잡도 증가
그래서 기존의 RUBY 단일 포인트에 집중됐던 방식에서, 주문을 따로 분리하는 식으로 진행했다고 한다.
그리고 각 서비스끼리는 MQ를 이용해서 약결합으로 바꾸어, 타 서비스에 영향을 크게 미치지 않고 일부 서비스만 장애에 영향받도록 변경했다고 한다. 메시지큐에 이벤트는 쌓여있으므로, 복구되면 다시 이벤트를 보내고.
우아콘 2020에서 나왔던, 영한님 발표의 `배달의민족 마이크로서비스 여행기`(https://www.youtube.com/watch?v=BnS6343GTkY&themeRefresh=1)와 비슷하다는 생각도 들었다.
위 내용보다 나는 샤딩 관련한 내용이 더 흥미로웠다.
실제로 나는 샤딩 관련 경험이 없었고, 이론적으로만 샤딩을 알고 있었기 때문이다.
Aurora DB에서는 샤딩을 지원해주지 않아 애플리케이션 단에서 샤딩을 구현시켰다고 한다. 이 때, range based 샤딩이나 directory based sharding 방식이 아닌, key-based sharding 방식을 이용했다고 한다.
range based 샤딩 방식은 균등하게 분배되지 않을 수 있어 Hotspot 현상이 발생할 수 있고, directory based 샤딩 방식은 룩업테이블을 이용하는데 사실상 룩업테이블이 단일 포인트가 될 수 있다는 점 때문이라 한다.
key-based sharding 방식을 사용했을 때, 데이터가 너무 많아 추가로 DB를 증설해야되면 어떡하지? 싶었는데, 같이 참여한 팀원분께서 리밸런싱을 하게 된다고 알려주셨다.
발표 끝나고 점심시간에 팀원분께 관련해서 얘기를 추가로 들었는데, 꽤나 고민할 것도 많았고 어려웠다. 팀원분께서 샤딩 구현은 정말 트래픽이 많은 환경이 아니면 잘 모르는게 정상이라고 해주셨다.
그리고 마지막에는 이벤트 분리 및 Transactional Outbox 패턴에 대해 소개해주셨다.
내부이벤트와 외부이벤트를 분리하여 주문API -> SQS -> 이벤트 처리기 -> SQS Event 방식으로 내부/외부에 따라 이벤트를 나누어서 관리하도록 했다고 한다. 이렇게 해서 이벤트 발행 주체가 한 곳으로 집중되도록 하고 관리를 편하게 했다고 한다.
문제는 유실 관련 이슈였는데, 이벤트가 실패했을 때 트랜잭션이 이미 끝난 상태라면? 트랜잭션 롤백을 어떻게 할까? 이를 개선하기 위해 소개된 게 Transactional Outbox 패턴이었다. 우테코 4기 크루였던 아키가 예전에 이 내용에 대해 알려줘서 어느정도 알고는 있었는데, 여기서 이 패턴을 들을줄이야ㅋㅋ
모놀리식에서 점진적 서비스 분리: 사업과제와 병행하여 시스템 개선하기
배민상회에는 수많은 사업과제가 존재한다. 그런데, 이 과제들을 진행하면서 점진적으로 모듈 또는 서비스를 분리하기란 쉽지 않았다고 한다. 그래서 이 과정에 대해 소개하는 세션을 마련했다고 한다.
여담으로 발표자 분중 한 분이 우테코 3기였다. (나는 우테코 4기)
벌써 우아콘이라는 큰 행사에서 발표를 하시다니, 새삼 멋지고 대단하게 느껴졌다.
배민상회에는 수많은 모듈이 존재하지만 발표에서는 간단하게 주문, 회원, 상품으로 압축해서 설명해주셨다.
모놀로식으로 합쳐져있던 서비스 및 로직을 어떻게 별도 모듈로 분리할 수 있었을까?
회원 모듈에 해당되는 로직만 모듈로 쏙 빼냈다고 하자.
원래는 하나의 덩어리처럼 로직들이 섞여있었으니, 회원모듈 뿐 아니라 기존 한덩어리(?) 에도 회원 관련 로직이 일부 찌꺼기처럼 존재했을 것이다. 이러한 의존성이 없는게 베스트이지만, 있더라도 양방향만큼은 무조건 피해야 한다!
이럴 때 나오는 것이 바로 추상화. 인터페이스를 만들어서 의존하게끔 하면 된다.
그런데, 이렇게 만든 인터페이스를 기존 모듈에 둘지, 새로 만들은 회원 모듈에 둘지 고민이 될 수 있다.
어디에 넣든 간에, 특정 모듈이 다른 모듈을 import 또는 의존할 수 있게 된다. 이렇게 되면 모듈에 새로운 service class가 생길 때, 이로 인한 인터페이스를 생성하게 되고, 반복되면 불필요하게 많은 인터페이스들이 생겨난다. 잘못하면 양방향 의존성이 생겨버릴수도. 그래서 아예 인터페이스 모듈을 새로 만들었다고 한다.
모듈 분리에서 더 나아가 서비스 분리를 한 내용에 대해서도 소개해주셨는데, 분리하려는 서비스 모듈을 복사한 후 엔드포인트를 생성하고 예전꺼를 제거하는 방식으로 하셨다고 한다.
아마 스트랭글러 패턴(참고: https://learn.microsoft.com/ko-kr/azure/architecture/patterns/strangler-fig) 처럼 개선하신 게 아닐까 싶다.
그리고 배포 시에 빠르게 롤백하기 위해 feature flag를 활용하셨다고 한다.
추상화 및 인터페이스는 신이고, 개발자는 무적이다
대용량 트래픽을 받는 모놀리식 서비스에 Woowa하게 RPC 적용하기
개인적으로 정말 어려웠던 세션.
RPC에 대해 1도 모르고 있어서 그런지, 이 세션은 정말 어려웠다ㅋㅋㅋ
여담으로 발표자분이 내 우테코 때 리뷰어셨다.
그땐 몰랐는데 알고보니 초고수 분이셨다. 허허..
발표자분께서 RPC를 도입하기 전에는, library로 제공하거나 REST API 방식도 고려했다고 한다.
하지만 라이브러리 제공 방식은 결국 사용자가 해당 라이브러리 코드를 언젠가는 뜯어보게 될 것이고 이에 따른 부담이 따르지 않을까 걱정했다고 한다. 또, 애플리케이션 러닝타임 비용도 증가할 수 있다고.
RPC는 http가 아닌 tcp, http2와 같은 통신 프로토콜을 자유롭게 사용 가능하고, 직렬/역직렬화 효율이 좋은 포맷을 사용가능하다는 점으로 인해 REST API보다 더 빠르다고 한다.
이에 따라 RPC를 도입했는데, 목표는 아래와 같았다고 한다.
- Thrift든 gRPC든 구현체 상관없이 RPC를 사용할 수 있도록
- RPC 허들을 낮추고 스프링 사용성과 유사하도록
즉, 사용자가 RPC에 대해 몰라도 이를 스프링 환경에서 편하게 이용할 수 있도록 하는 것이 목적이라고 하셨다.
실제로 @WoowaBootController 어노테이션을 붙여주기만 하면 remote server와 연결해서 해당 로직을 호출할 수 있도록 구현하신 듯.
그리고 RPC server는 한대가 아닌 여러대인데, 이를 위해 DNS, VIP, IP로 매핑하는 방식을 이용했다가 zookeeper에 등록하여 편리하게 이용했다..고 들었는데 이거 맞나?? 아니 어려워서 이쯤부터 집중력이 흩어졌다ㅋㅋㅋ
근데 RPC가 비용 절감 효과가 좋긴 한가보다.
근데 높은 생산성과 러닝커브, 기존 REST API로도 충분히 대처가능하다는 점 때문에 잘 안쓰는듯.
약간 Spring Webflux 같은 존재인건가 허허
나중에 언젠가 나도 RPC를 다룰 일이 있을까? 그때 나는 뭐하고 있을지도 궁금하다.
배민스토어에 최신 기술 한방에 때려넣기: Kotlin, Spring WebFlux, EDA
배민스토어개발팀 중에서도 전시 도메인 쪽에서 Spring WebFlux, EDA (Event-Driven Architecture)를 활용한 내용에 대해 소개하는 세션이다.
여담으로 발표자분 중 한 분이 나랑 클라이밍 같이하시는 분이었고, 학교 선배님의 지인이셨다.
참고로, 먼저 인사해주셨을 때, 머리스타일이 확 바뀌셔서.. 사실 순간 못알아봤다. 나 진짜 안면인식장애인가?
나중에 바로 알아채서 직접 인사드렸다 ㅎㅎ.. 담에 클라이밍 같이 하면 음료수 쏘겠습니다 ㅜㅜㅜ
Kotlin, EDA 관련 얘기보다는 Spring Webflux 관련 얘기를 흥미롭게 들었다.
이벤트 관련 내용은 워낙 다른 세션에서 많이 소개가 되기도 했고, 사내에서도 꽤나 빈번하게 들었던 내용이니.
Webflux의 project reactor. 이놈의 엄청난 러닝커브를 과연 어떻게 극복했을까?
전시도메인 쪽이다보니 CRUD 중에서 Read를 굉장히 많이 하며, 동시에 많은 데이터 요청 시 각각 시스템에 따른 응답시간으로 인해.. 러닝커브는 높지만 기술적으로 도입해보자! 싶어서 도입하셨다고 한다.
flux/mono에 대한 코드 러닝 커브가 좀 있었고, 기존 계획에 비해 webflux 관련 코드가 좀 많아졌다고 한다.
하지만, 데이터를 비동기-논블라킹으로 처리하기 때문에 확실히 성능상 장점이 충분히 있었으며 의미있는 시간이었다고 한다.
발표를 들으면서 팀원분과 webflux에 대한 얘기를 많이 나눴다.
webflux도 위에 얘기나온 RPC처럼.. 성능상으로 장점이 있지만 MVC로도 웬만한 트래픽은 충분히 대처가 되며, 러닝커브가 존재하고, 예상치못한 상황이 닥쳤을 때 대처가 어렵다는 단점이 존재한다는 점. 그래서 많이 안쓰는게 아닐까 싶다.
언젠가 내가 webflux를 다룰 일이 올까? (기술적 욕심이 아닌, 필요성에 의해 개발하게 되는 그런 날.)
발표를 들으면서 별별 생각을 다한듯 ㅋㅋ
낯선 서드파티와의 동행: 믿을 만한 배민커넥트 서버 구축하기
약 20분간 진행됐던 세션.
배민커넥트를 하기 위해선 운전면허 검증을 해야된다고 한다. (와 그러네... 생각해보니까 당연한데, 이땐 전혀 생각못했다.)
운전면허 검증은 도로교통공단, 경찰청 측과 API 통신을 한다고 한다.
이 때, 외부 API 통신이 트랜잭션 안에 묶여있다면? 공단 쪽에서 서버가 다운됐을 때 long transaction으로 인해 커넥션이 고갈될 것이다. 이로 인해 사용자는 불편함을 겪게 된다.
따라서 timeout 값을 설정해주고, 트랜잭션 밖으로 분리해주었다고 한다.
여담으로, 공단 서버가 점검중인 것을 이미 확인했다면 매번 공단쪽으로 API 통신을 할 필요가 없다.
그래서 회로차단기 패턴을 이용하여 반개방 상태에서 공단서버가 괜찮은지 체크 후, 안괜찮으면 공단쪽으로 API를 보내지 않도록 했다고 한다.
20분이라 그런지, 그리고 내용이 어렵지 않아서 그런지 재밌게 들었다.
Kafka를 활용한 이벤트 기반 아키텍처 구축
딜리버리서비스, 배차시스템 쪽에서 발표해주신 세션.
팀원분이랑 주제만 보고 내용이 뭘지 추측해봤는데, 그 내용이 꽤 일치했었던 세션이다ㅋㅋㅋ
EDA니까 kafka, AWS SQS+SNS 관련 얘기가 나올 것이고, 이벤트로 어떻게 보내줄 것인지. 유실 이슈를 어떻게 처리할 것인지에 대한 얘기가 나오지 않을까? 했는데 해당 얘기가 나왔다.
SQS+SNS 대신 kafka를 선택한 이유에 대해 얘기해주셨는데, 아래 네가지 이유가 있었다고 한다.
- 순서보장
- 고성능/고가용성
- 통합도구
- 전담팀 지원 이유
실제로 사내에 카프카를 전담하는 파트에 있는 능력자분들이 계신다.
세션 발표에서도 전담팀이 지원해주고 관리해줄 수 있다는 점이 kafka를 선택하는 데에 가장 크게 작용했다고 한다.
유실 문제에 대해선, 맨첫번째 세션에서도 얘기 나왔던 Transactional Outbox Pattern으로 해결했다고 한다.
EBS 볼륨 이슈, 네트워크 이슈, Zookeeper 통신 이슈 등 다양한 원인이 있겠지만, 결국 이벤트 재발행 및 실패와 순서보장이 안되는 이슈로 인해 해당 패턴을 사용했다고 한다.
근데 그러면 해당 세션은 잘 이해했겠네? 라고 묻는다면 그것도 아니다!
debezium부터는 으악~어려워~ 하면서 들었기 때문.
카프카 측에서 만든 CDC Connector인 Debezium을 활용하여 이벤트 실패 및 순서보장이 안되는 이슈를 보완했다고.
카프카를 다뤄본적이 없고, 그냥 이벤트를 쏘기만 했던 나에게... 여기서부턴 좀 어려웠다.
근데 아직 우리팀에서 카프카 이벤트를 관리하는 포인트가 직접적으로 요구되진 않아서, 필요해지면 공부해볼듯?
ElastiCache 운영을 위한 우아한 가이드: 초고속 메모리 분석 툴 개발기와 레디스 운영 노하우 소개
아래 책 저자분께서 발표해주신 세션!
https://www.yes24.com/Product/Goods/123182350
그리고 NHN forward 21에서 레디스 관련 주제로 발표(https://www.youtube.com/watch?v=92NizoBL4uA)해주신 분이기도 하다.
가상 이슈 사례를 들면서 대처방법을 소개해주셨다.
CPU 점유율이 지나치게 높은 경우이자, 네트워크와 command 양상이 비정상적인 경우에는 어떻게 할까?
언제부터, 어떻게 커맨드 양상이 변했는지 체크를 해야 한다고 하셨다.
어떤 커맨드가 느린지 실제로 확인이 불가능하여 사내 redis exporter를 추가하여 확인한 얘기를 들려주셨다. 그리고 slow log를 확인하여 mget이 지나치게 느린 원인이었다는 가상 사례를 소개해주셨다.
추가로, 실제 이슈가 존재하더라도 slow log에는 잡히지 않을 수가 있다고. 레디스는 싱글스레드 기반이기 때문에, 실제 처리는 1초만에 걸렸더라도 대기시간이 N초였다면 사용자는 N+1초 후에 응답을 받는 셈. 이런 경우에는 slow log에 찍히지 않을 수 있다.
응답 지연이 온 경우는?
그리고 심지어 CPU, 메모리, 커넥션이 다 괜찮았다면?
네트워크 이슈가 존재해 확인해보니, aws 네트워크 i/o 크레딧 매커니즘으로 인해 대역폭을 초과하여 네트워크를 사용할 수도 있었다고 한다. 일정 대역폭을 넘기면 사용이 불가능한 것이 아닌, 크레딧 버킷에 남아있는 양을 끌어서 사용하는 알고리즘이라고 한다.
하지만 짧은 요청을 빈번하게 처리하는 레디스 특성 상, 버스트 대역폭은 사용 가능해야 한다.
따라서 네트워크 성능 부족을 의심하고 스케일업, 스케일아웃을 고려하는 것이 맞다고 한다.
메모리가 지나치게 증가한 경우는?
레디스는 NoSQL 특성을 가진다. 따라서 비정형 데이터들이라 파악이 한눈에 어렵다는 단점이 존재한다.
그리고 싱글스레드 기반이어서 데이터를 쭉 가져와서 메모리에 어떻게 담겨있는지 확인하기엔, 성능적으로 우려되는 점이 존재한다.
그래서.. 가림님께서 아래 오픈소스를 만들었다고 한다! (ㅋㅋㅋ 빌드업이었다고 함)
https://github.com/woowabros/redis-keys-statistics
관심있으신 분들은 확인해보고 이용해봐도 좋을 듯하다.
추가로, 루아스크립트로 커맨드 성능향상시킨 사례도 들려주셨는데... 집중력 저하 이슈로 인해 놓쳤다.
죄송합니다 ㅜㅜㅜ
마치며
뒤로 갈수록 집중력이 저하돼서 포스팅 기록도, 그리고 세션 집중도 덜한 느낌이다.
특히 4시쯤부터는 진짜 집중력이 많이 저하됐다. 장소의 문제인가? ㅋㅋ
이번 우아콘 2023에 우리 팀은 나 포함 2명이 참석했다! 덕분에 둘이서 커피챗처럼 대화를 많이 나눌 수 있었다.
점심시간에 팀원분께 정말 많은 도움이 되는 말들을 들었다. 기술적 내용뿐 아니라, 개발자로서 알아두면 좋을만한 점들에 대해 쭉 얘기해주셨다. 팀원분께서 나보다 경력이 훨씬 많으셔서 이런 얘기들을 들으며 커피챗을 하고 싶었는데 많은 조언들을 해주셔서 정말 감사할 따름이었다.
물론 사담도 나눴다. 듀얼모니터면 생산성이 어쩌고, 요즘 하는 게임이 어쩌고 등등. 정말 재밌었다ㅋㅋㅋ
저녁은 같은 회사분들이랑 먹었다.
회사분들을 만나면서 느낀것이, 다들 정말 열심히 산다는 것이다.
업무가 끝나고 개인적으로 스터디를 하시는 분들도 있고, 추가로 무언가를 깊게 파는 분도 있고. 우아콘이 끝나고 근무를 이어서 하시는 분도 있고.
나는 요즘 클라이밍이나 자전거타기, 음악듣기에 심취(?)해 있는 상황이다.
그래서 그런지 예전보다 개발에 대한 열정은 살짝 식고, 취미에 대한 열정이 좀 올라가있는 상황이다. 그와 덩달아 조금 걱정도 됐다. 앞으로 이러다가 개발자 적성에 안맞게 되면 어떡하지? 하는 마음도 살짝 들었고... 요즘 약간 번아웃은 아닌데, 뭔가 생각이 많긴 하다.
업무에서 배울 점이 있긴 하지만, 반복적인 업무가 닥칠 때에는 개인공부의 필요성을 절실히 느끼고 있다. 예전에는 업무만으로 공부가 팍팍 되는 느낌이라면, 요즘은 진짜 개인공부시간이 필요하겠다는 생각? 이다.
고민이 부쩍 많아졌지만... 그래도 행복한 건 지금이 더 행복한 듯하다. 클라이밍이라는 좋은 취미를 찾았고, 좋은 사람들과 함께 취미활동을 즐기고 있으니. 예전에는 취미활동이라 할만한게 크게 없었는데, 지금은 취미활동이 있으니 좋은 듯하다 ㅎㅎ
기술적 성장에 관한 부분은 이렇게 생각한다.
걱정이 없진 않고 생각거리도 많긴 하지만... 일단 내가 내 자신을 볼땐, 아주 잘하고 있는진 모르겠지만 못하고 있지도 않다고 생각한다. 열정도 아직 남아있고, 입사하고 4개월을 돌아다보면 그래도 정말 많이 공부하고 배운 내용들도 있기 때문! 지금처럼 쭉 잘해나가면 된다고 생각한다.
요즘 스트레스 원탑은 학교과제! 학교 빨리 졸업해야겠다..
'JAVA > JAVA | Spring 학습기록' 카테고리의 다른 글
[Spring] @Transactional(readOnly=true)에서 write 시 예외 좀 더 살펴보기 (13) | 2024.01.22 |
---|---|
[Spring] Amazon SNS, SQS 이벤트 순서 역전 및 유실에 대처해보자 (8) | 2023.12.02 |
[231023] 흔한 백엔드 개발자 모임 컨퍼런스 후기 (29) | 2023.10.26 |
[Spring] @async 로직 실패 일대기, ThreadPoolTaskExecutor의 awaitTerminate와 Async (44) | 2023.09.23 |
[Spring] Apache POI 엑셀 다운 vs opencsv CSV 다운 로직 및 성능 비교하기 (feat. parallelStream) (2) | 2023.09.19 |