티스토리 뷰

컨퍼런스 및 세미나

우아콘 2023 후기

주디 𝙹𝚞𝚍𝚢 2023. 11. 20. 11:58

 사실 우아콘 참가자 선정 결과는 기대하지 않고 있었다. 떨어져도 아쉽지 않겠다 생각했는데, 참가자 선정 발표날 선정 결과를 확인했고, 선정되었다. 아무래도 올해는 컨퍼런스 운이 많이 따라주나보다. 인프콘도 우아콘도 엄청난 경쟁률을 뚫고 당첨되었으니. 여차저차 바쁘게 시간이 흐르고 15일에 다녀왔다.


 10시에 시작이었는데, 전날 게임하다 늦게 자서 밍기적거리다가 10시에 아슬아슬하게 도착할 것 같아 급하게 에스컬레이터를 탔다. 그런데 앞사람의 실루엣이 익숙했고, 지금 내 눈 앞에 있는 분이 그분이 맞나 한 0.1초 현실감각을 잃었다. 그리고 그분은 정말 인프랩 CTO이신 동욱님(=향로)이셨다. 그래서 중간에 사진 요청드렸는데 흔쾌히 좋다고 하셔서 동행분이 사진까지 찍어주셨다. 당황하셨을수도 있는데 사진 흔쾌히 찍어주시고 정말 감사하다.
그리고 호다닥 등록을 마치고 이름표와 우아콘 가방(가방이라곤 해도 별 거 아니다.)을 받고 10시에 있을 오프닝노트를 기다렸다.


 10시가 되자 이국환 CEO님의 오프닝 노트를 시작으로 송재하 CTO님과 이기호 CPO님의 키노트가 이어졌다. 여기에서 내가 제일 인상깊었던 부분은 배달의 민족이 지금까지 만들어온 배달매커니즘 그 이후를 이야기하신 부분이었다. CEO님은 그 이후는 AI가 큰 역할을 하게 될 것이라고 얘기하셨고(내 기억엔), 그래서 자율 주행 배달 로봇인 ‘딜리’를 잠깐 소개해주셨다. 그런데 내가 우아콘에서 느낀 바로는 내가 생각하는 것보다 우아한 형제들에서 AI가 큰 부분을 차지하고 있다는 것이었다. 사용자에게 추천하는 가게를 노출하기 위해, 배달까지 예상되는 소요시간을 알려주기 위해, 라이더가 좀 더 효율적으로 여러 집을 배달할 수 있기 위해 그 뒤에서 AI가 많은 역할을 하고 있었다.
그리고 요즘 채용 공고들을 살펴보며 ‘AI를 서비스에 직접 접목시켜본 경험’을 우대하는 곳들이 꽤 있었던 것이 생각났다. 미래엔 단순한 웹 개발만 해서는 경쟁력이 없겠다고 판단해서 늦게나마 머신러닝과 딥러닝을 공부하고 있는게 다행인걸까, 하는 생각이 들었다.

바깥쪽에 전시중이었던 무인 배달 로봇 '딜리'
모든 참가자에게 주는 선물과 인재풀 등록으로 받은 개발자 키트


 이후에는 다양한 세션들이 있었는데, 내가 들은 세션들의 내용 위주로 정리해보았다. 내가 들은 내용을 정리한 메모를 바탕으로 작성하는 것이기 때문에 정확하지 않을 수도 있으므로 후에 영상이 올라온다면 꼭 영상을 확인하는 것을 추천한다.


대규모 트랜잭션을 처리하는 배민 주문시스템 규모에 따른 진화

 간단하게 설명하자면, 급속도로 성장하는 배달의 민족의 중심인 주문 시스템을 만들면서 고민한 과정을 공유하는 내용이었다.
고민은 크게 네 가지였다.
 첫번째는 단일장애점이었다. 배달의 민족의 주문 시스템은 점심, 저녁(특정 시간) 주문이 몰리는 특징을 가지고 있는데, 주문시스템에 여러 시스템이 유기적으로 연결되어 있어 주문에 문제가 생길 경우 다른 시스템에도 영향이 가게 되는 문제점을 가지고 있었다고 한다.
 두번째는 일 평균 300만 건의 주문을 저장하고 수년간 데이터를 보관, 관리해야하기 때문에 대용량 데이터로 인한 성능 저하 발생이었다고한다.
 세번째는 위와 같이 순간적으로 몰리는 트래픽에 대해 대규모 트랜잭션을 어떻게 구현할지에 대한 것이었다고 한다.
 네번째는 이벤트 기반으로 통신하는 주문 시스템이 어떻게 이벤트 발행을 일관성을 보장하며 할 수 있을지에 대한 고민이었다고 한다.

 먼저 첫번째 단일장애점에 관해서는 중간에 MQ를 두어 이벤트 기반 통신으로 시스템 간 영향도를 분리했다고 한다.

 두번째, 대용량 데이터에 따른 조회 성능 저하는 정규화된 주문 DB에서 읽기쓰기가 동시에 발생되는 것이 주요원인이었다고 한다. 정규화되어 있다보니 JOIN을 많이 사용해야 했는데 이 부분을 역정규화 싱글테이블로 유지하기로 하고, NoSQL인 몽고디비를 사용하여 필요한 데이터를 미리 만들어 몽고디비에 넣어놓고 사용하도록 했다고 한다. 결국 같은 주문 데이터가 두 번 저장되는 셈인데, 주문이 요청되어 주문 이벤트가 발행되면 RDBMS에도 저장하고 NoSQL에도 저장하여 동기화했다고 한다.

 세번째, 대규모 트랜잭션의 경우 주요 문제는 주문 DB의 분당 쓰기 처리량 한계치 도달이었다고 했다. 주문 DB 1대(쓰기용)과 주문 DB 2대(읽기용)이 있었는데, 결론은 샤딩으로 해결하셨다. AWS Aurora에서는 샤딩을 지원하지 않아서 애플리케이션 샤딩으로 구현하셨다고 했다. 샤딩 전략으로는 키 베이스드 샤딩, 레인지 베이스드 샤딩, 디렉토리 베이스드 샤딩이 있는데 이중에 키 베이스드 샤딩을 선택하셨다고 한다.(배민의 경우, 주문번호를 통해 주문 순번을 알 수 있기 때문에 주문 순번 % 샤드 수로 데이터가 갈 샤드 번호를 결정) 샤딩을 하면 여러 샤드에 있는 데이터들을 주문내역을 보여줄 때 보여줘야 하는데, 이때 위의 대용량 데이터에 따른 조회 성능 저하를 해결하기 위해 사용했던 몽고디비를 활용하셨다고 한다.


 마지막으로, 이벤트 아키텍처에 대해서는 이벤트 주체를 단일화하여 해결하셨다고 한다. 기존 아키텍처에서 현금영수증을 예로 들어주셨는데, 현금영수증은 주문배치 애플리케이션과 이벤트 처리기 애플리케이션 두 개를 바라봐서 이벤트 발행 주체가 명확하지 않고 이벤트 유실이 발생할 경우 재처리가 어렵다는 문제점이 있다고 하셨다. 그래서 내부 이벤트와 외부 이벤트로 나눠서 이벤트 발행 실패와 서비스 실패를 격리하여 유실될 때 아웃박스 엔티티를 이용해서 재발행되도록 했다고 하셨다.

 Transactional Outbox Pattern에 대해서는 https://blog.gangnamunni.com/post/transactional-outbox/를 참고


모놀리식에서 점진적 서비스 분리: 사업과제와 병행하여 시스템 개선하기


 이 세션은 사업과제와 병행하면서 어떻게 모놀리식에서 점진적으로 서비스를 분리했는가하는 이야기였다. 우선 왜 모놀리식에서 변화해야겠다고 생각했는지 말씀해주셨는데, 빌드속도의 문제였다. 그래서 빌드/개발단위를 작게 만들어 도메인간 결합을 낮추는 것이 목표였다. 그래서 컴포넌트 분리를 하는데, 회원 서비스와 주문 서비스 등의 의존 방향이 일관되지 않고 섞여 있어서 중간에 인터페이스를 추가해서 의존성 방향이 한쪽으로 흐르도록 했다고 하셨다. 컴포넌트 분리는 그렇게 해결했지만 빌드에 대한 의존성은 해결되지 않아서 아까 중간에 추가한 인터페이스를 위한 모듈을 만들어 멤버 모듈이 빌드될 때 인터페이스모듈까지만 빌드되면 되고, 주문과 상품모듈이 빌드될 때 인터페이스모듈만 빌드되면 되도록 수정했다고 하셨다.


대용량 트래픽을 받는 모놀리식 서비스에 Woowa하게 RPC 적용하기

 이 세션은 서비스 분리를 하면서 RPC를 적용했던 내용에 대한 이야기였다. 우선 여러 서비스를 잘게 쪼개면서 공통으로 사용하는 코드를 어떻게 사용하게 할지에 대한 고민은 1차적으로 공통된 코드를 lib로 제공하는 방식이 있겠지만, 이 문제는 언젠가 각 서비스의 개발자들이 전체 코드를 다 봐야하고, 애플리케이션 러닝타임이 길어지고, 저장소에 접근하기 위한 커넥션이나 저장장소가 명확하지 않은 단점이 있다.
 그래서 Rest API 방식으로 데이터 서버를 따로 두고 통신하는 방법을 생각했는데, 통신 레이어의 증가로 레이턴시가 증가하여 대용량 트래픽을 받는 서버에서 위험한 요소라고 생각했다고 한다. 그리고 데이터를 받아가기 위한 클라이언트 코드들이 각 서비스에서 독립적으로 작성되어야 하는 문제도 있고, 버전관리가 명확하지 않는 문제점도 있었다고 한다.
 그래서 RPC방식으로 데이터를 제공하는 방법을 생각했다고 한다.
 사전지식으로 알려주신 게 있는데 RPC방식으로 할 경우 idl파일로 명세 작성 후 각 프로그래밍 언어로 서버를 구현한다고 한다.
 RPC를 적용하려고 보니 thrift, gRPC 등 다양한 구현체가 있고, 다른 RPC 구현을 사용하려면 또 다른 idl 파일을 사용해야했다고 한다. 그래서 결국 구현에 상관없는 RPC를 제공하는 것이 목표가 되었고, 이것의 요구사항은 아래와 같았다고 한다.

1. 유지보수 편하게
2. 구현체 선택 가능
3. 스프링의 사용성과 크게 차이없도록


 그렇게 해서 만들어진 것이 WoowaBoot라고 한다. 이후 오픈소스로 하실 예정이라고 했는데 그때 꼭 구경해봐야겠다.


여기, 주문하신 ‘예측’ 나왔습니다: 추천/ML에서 ‘예측’을 서빙한다는 것에 대하여

 이건 내가 세션 시간표를 미리 보면서 정말 듣고 싶었던 세션이었다. 머신러닝, 딥러닝을 배우면서 추천은 어떻게 구현하고 서비스하는 것일까 궁금했는데 이 세션이 그 궁금증들을 해결해주었다. 주요 발표 내용은 아래 이미지와 같았다.

 본 발표에서 다룬 것은 주로 모델 사용(모델 배포 > 추론결과 생성)의 내용이었다.

 추론에는 배치추론과 실시간추론이 있는데, 배치추론은 이미 주어진 정보들로 추론을 해놓았다가 서비스만 하는 방식이고, 실시간추론은 사용자에게 요청받은 그때 주어진 정보들로 추론을 하는 것이라고 말씀하셨다. 이외에도 배치에서 추천결과를 생성하지 못했을 경우 실시간추론을 거치는 방법과 배치추론에 따라 생성된 추천결과를 실시간추론으로 피드백을 거쳐 결과를 최적화하는 하이브리드가 있어서 아래와 같이 네 가지 경우의 사례를 들어주셨다.

  배치추론 실시간추론 배치+실시간 하이브리드
사용영역 배달 카테고리 개인화 추천 배달 예상 시간/고객 안내 시간
장바구니 추천
배달홈 개인화 추천 홈화면 추천
방법 - 예상 추론 결과를 분산처리 배치로 미리 생성하고 빠르게 조회가능한 저장소에 적재
- 요청이 들어오면 이미 생성해둔 결과 응답
1. 배달 예상 시간/고객 안내 시간
 - 피쳐를 조회하고 API 입력과 피쳐를 모델 입력으로 전처리
 - 결과 얻고 필요하면 후처리
 - 모델 결과 실사용값으로 변환

2. 장바구니 추천
 - 사전에 추천 candidate 생성되어 있음
 - runtime에 주어진 정보를 토대로 추천 candidate 랭킹 조정 필요
 - 피쳐, candidate 조회하고 API 입력과 피쳐를 모델 입력으로 전처리
 - candidate의 랭킹 조정
 - 비즈니스 로직 적용, 최종 랭킹 결정
 - 실시간추론을 위해 카테고리 선호도 피쳐와 스코어링 쿼리 스크립트 준비
 - 요청이 들어오면 배치 결과 확인하고 없을 경우 실시간 결과 계산하여 응답
 - 사용자의 피드백 기반으로 미리 생성한 추천결과를 조정해가며 최적결과 찾음
 - Kafka로 사용자의 피드백을 빠르게 수집 가능한 파이프라인을 구축
 - 사용자 피드백을 수집하고 슬롯별 추천 결과 배치를 만들고 어떤 슬롯을 내보낼지 결정하는 과정 반복
 - 요청이 들어오면 사용자의 클러스터를 조회하여 추천 결과(슬롯)을 조회
 - 일부 비즈니스 로직을 거쳐 최종 추천 결정
장점 - 빠른 응답시간
- 대규모 트래픽에 가장 유리
- 실시간 정보가 반영된 fresh한 결과
 - 공간 효율적
 - 배치케이스 커버 범위 외에도 예측 결과 제공 가능
 - 배치/실시간 비율 조정으로 배치 추론 공간 비효율성 개선
 - 각각 다른 모델을 사용하여 사용자 니즈, 예측 목적 달성 가능
 - 사용자의 반응에 대응한 최적의 결과
 - 모델 갱신주기보다 추천 결과 빠르게 갱신 가능
단점  - 모든 케이스 생성 = 많은 저장공간 필요(비효율적일수도)
- 관심사 변경 대응 어려움
 - 추론에 필요한 정보가 runtime에만 주어진다면 사용 불가
 - CPU, 계산 heavy case로 I/O 대비 최적화 성능 개선 난이도 높음
 - 대규모 트래픽에 필요 리소스 상대적으로 많음
 - 관리 포인트, 시스템 복잡성 증가
 - 여러 모델 개발 필요할 수도 있음, 응답시간의 손해 발생
 - 실시간 피드백 파이프라인 구축/운영 난이도가 있음
 - 테스트가 어려움
 - 모델이 수렴할 때까지의 지표 손실

 추론 결과인 추천 결과물을 사용자에게 전달하기 위해서는 아래와 같은 요구사항이 있다고 하셨다.

 그 중 아래 슬라이드는 왜 python+FastAPI를 사용하였는지에 대한 답이었다.


낯선 서드파티와의 동행: 믿을 만한 배민커넥트 서버 구축하기

 이 세션은 처음엔 그닥 흥미롭지 않았는데, 막상 듣고 보니 유익했다. 발표하신 분은 우아한형제들의 라이더플랫폼팀분들이셨는데, 라이더의 운전면허 검증에 관련된 이야기였다. 제목에서 말하는 서드파티는 배민커텍트 서버에서 사용하는 것으로, 실명확인, 본인인증, 보험, 운전면허 검증, 계좌 검증이었다.

 법적인 제한으로 배민은 올해초까지 라이더의 운전면허 검증을 수기로 진행하다가 이제 API가 제공되어 그걸 사용하는 방식으로 변경했다고 한다. 그래서 이후 아래와 같이 구조가 변경되었다고 한다.

 그런데 배민커넥트서버 <-> 도로교통공단 <-> 경찰청으로 API 조회가 이루어지다보니 문제가 생기는 지점이 어디인지 파악하기 어려운 단점이 있었다. 그리고 점검 등으로 이미 연결이 안될 것을 알고 있는 경우, 연결이 안될 것을 이미 알고 있는데 계속 연결을 하려고 하는 게 맞을까 라는 생각이 드셨다고 한다. 그래서 이 문제를 해결하기 위하여 회로차단기 패턴을 적용하여 도로교통공단, 경찰청 서버에 문제가 생기면 주기적으로 검증이 되도록 스프링배치를 이용하도록 했다고 하셨다. 회로차단기란 일반적으로 회로가 닫혀있어서 전원이 켜지면 연결된 전구에 불이 들어오지만, 전구에 문제가 생겨서 계속해서 전류가 흐르면 위험할 때 자동으로 회로를 열어 전류가 흐르지 않도록 해서 위험한 상황을 방지해주는 것이다.
 실제로 찾아보니 이런 디자인패턴이 있어서 더 공부를 해봐야겠다.

 회로차단기 패턴에 관해서는 https://mangkyu.tistory.com/261를 참고


Kafka를 활용한 이벤트 기반 아키텍처 구축

 이 세션은 제목만 봤을 때 내용이 어느 정도 짐작가능해서 안 들을까 했는데, 그래도 Kafka에 관한 내용이니 들어두면 좋을 것 같아 들었다. 배달 시스템이 점점 복잡해지는 문제를 해결하고자 이벤트 기반 아키텍처를 적용한 경험을 공유하는 세션이었다.
 배달의 민족의 경우, 배달 상황에 변경됨에 따라 알림을 보내주는 단순한 구조였지만 점점 배달시간, 통계, 쿠폰 관련 기능이 추가되며 복잡해졌다고 한다. 그래서 배달과 배달이 아닌 기능을 분리하고자 했고, 배달이 변경됨에 따라 동시에 혹은 준실시간성으로 반영되어야 하는 기능들이 이벤트로 표현 가능하다고 생각해서 이벤트 기반 아키텍처를 적용하도록 했다고 하셨다.
 이벤트를 "행위의 정보"라고 정의하셨고, 구성 요소를 정의했는데 "대상, 행동, 정보, 시간"이라고 정의하셨다. 결국 "배달에서 발생한 행위를 알려 주고 싶어"가 이벤트가 되는 것이다.

  • 대상: 어떤 배달이 변경되었는지
  • 행동: 도메인에 일어난 모든 사건을 나타냄
  • 정보: 행위와 관련된 값. 라이더라는 정보는 배차되었다라는 행위와 밀접한 관련. 필요하다면 그외의 정보도 추가 가능한데, 배달이지만 주문번호를 궁금해할 수 있으니 주문번호를 같이 보내주는 것 등.
  • 시간: 행위가 발생한 시간. 배달이 라이더에게 "11시"에 배차되었다.

 이벤트 기반 아키텍처를 적용하니 좋았던 점은 요구사항이 추가되더라도 배달 시스템의 복잡도에는 영향이 없다는 것이었다고 한다. 그리고 데이터분석 측면에서 도메인 히스토리 파악이 용이해졌고, 분석정보로 활용이 가능해졌다고 한다.

 덧붙여 이벤트 기반 아키텍처를 적용할 때 주의사항을 몇 가지 말씀해주셨다.

  • 이벤트에 데이터를 무분별하게 추가하지 말 것
    - 소비처가 여러 데이터의 추가를 요청할 수 있는데 발행처가 이를 무조건적으로 수용하면 안됨. 왜냐하면 그렇게 되면 그 소비처와의 결합도가 높아지기 때문.
  • 이벤트의 순서 굉장히 중요
    - 일정한 비즈니스 순서가 있고, 이 순서에 맞춰서 코딩을 할텐데 이벤트 순서가 꼬이는 경우가 있었음. 주문 취소 이후 주문 생성 이벤트가 들어왔다면 배달 생성하면 안됨.

 2번 이벤트의 순서 보장에 관해 이벤트를 어떻게 보낼 것인가에 대한 발표가 이어졌다. 이벤트 파이프라인으로 어떤 메시지 브로커를 사용할지 고민이 있었고, SNS, SQS, Kafka 중 고민이었는데 Kafka를 선택하셨다고 한다. 이유는 아래와 같다.

  • 순서 보장: 토픽의 파티션을 통해 key별로 순서 보장
  • 고성능 고가용성: 실시간 이벤트를 처리할 고성능 고가용성 제공
  • 통합도구: Kafka Streams, Kafka Connect 등 다양한 통합도구 제공으로 시스템 개선이나 확장이 필요할 때 이것들을 사용할 수 있음
  • 전담팀 지원: 배달의 민족내에 카프카팀이 존재하여 카프카 클러스터 관리, 모니터링 및 지원도구 제공

 이렇게 카프카를 도입했는데 발생한 문제들이 있었다. 순단이 없는 것은 아니어서 네트워크 이슈, 서버 통신 이슈 등으로 이벤트 순서가 변경되는 등의 문제가 발생했고, 결국 시스템 장애로 확산되었다. 이를 해결하기 위해 Transactional Outbox Pattern의 룩업테이블을 사용하셨다고 한다.
그리고 메시지 릴레이를 구현해야 했는데 저비용, 안전성, 처리량을 고려해야 했고, 그래서 오픈소스 플랫폼인 디비지움을 사용했다고 하셨다.(DB에 일어나는 변경을 감지하고 전송하는 시스템) 디비지움은 아래와 같은 특징이 있다.

  • 설정을 통해 커넥트 등록/실행 및 모니터링 제공
  • 안정성: 바이너리로그를 통한 순서 보장 및 오프셋을 활용한 발행 보장. 발행이 실패한 오프셋부터 다시 읽어서 순서 보장
  • 처리량: 아웃박스 테이블 파티셔닝을 통한 처리량 증대
  • MySQL은 디비지움 태스크 수가 1개로 고정되어 있는 문제 -> 아웃박스 테이블 파티셔닝을 통하여 처리량을 늘림

 그래서 이벤트 스트림은 배달 생성 -> 배차완료 -> 픽업완료 -> 배달완료가 되었고, 이벤트 스트림으로CQRS를 적용했다고 하셨다.(이 부분은 공부가 더 필요하겠다...)
 이벤트 스트림으로 스트림즈 애플리케이션 구현했는데, 특정 시간, 특정 지역에 배달하는 라이더가 몇명이 있는지와 같은 정보를 찾아야했다고 하셨다. 예전에는 집계를 했는데 실시간 데이터 반영이 어렵고 부하가 되어 부담이었는데, Kafka Streams를 활용하여 집계 처리를 해서 다양한 집계의 니즈를 해결하고 실시간 데이터 반영이 가능했다고 하셨다.


 세션을 들으며 느낀 것은 소위 네카라쿠배의 '배'로 좋은 개발자들이 모이는 회사로만 생각하고 있었는데, 배달의 민족이 주문부터  배달까지 잘, 편하게 하기 위해서 어떠한 노력을 하고 있는지 자세하게 알 수 있어서 좋았다는 것이다. 그리고 하나의 목표를 위해 함께 고민하고 문제를 해결해나가는 환경이 부러웠다.

 기대는 안 했는데 너무나도 의미있었던 시간이었다. 내년 우아콘도 선발이 된다면 기쁜 마음으로 올 것 같다.

300x250

'컨퍼런스 및 세미나' 카테고리의 다른 글

파이콘 2023 뒤늦은 후기  (0) 2023.10.01
인프콘 2023 후기  (0) 2023.08.15
스프링캠프 2023 후기  (1) 2023.04.24
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함