[Conference] SLASH 22 (토스)
1. '왜 은행은 무한스크롤이 안되나요' - 이응준 (Server Developer)
- 은행 앱의 거래내역 조회 : 무한 스크롤을 지원하지 않고, 기간을 설정하여 조회하는 방식으로 운영된다.
- 이유 : 은행 시스템 -- 1. 채널계 : 유저의 요청을 받아 처리하는 영역 (interface 제공) [ 성능 > 신뢰도 ]
2. 계정계 : 실제 유저의 돈을 다룸. 높은 신뢰도 요구. 채널계를 통해 접근 가능 [ 성능 < 신뢰도 ]
채널계에서 요청을 받아 계정계에서 처리, 다시 채널계로 전달 후 사용자에게 결과를 제공해줌
신뢰도가 우선인 계정계의 특성상 광범위한 거래내역 조회를 빠른 응답시간에 적은 부하로 제공해주기 어렵다.
토스에서는 왜 무한스크롤이 가능할까?
계정계에 요청 X, 채널계의 송금 서버가 거래내역을 직접 반환
* 핵심 기술 : 송금서버와 코어뱅킹서버가 항상 정확히 동기화 되어야 함
[기술 시연]
1. 이체할 때마다 그 내역을 송금 DB에 저장 --? 문제점 : 타행 입금 누락
2. 해결) 코어뱅킹 서버가 송금 서버에게 입금 사실 전달 --> Kafka 를 이용
[ 예외 상황에 대한 대처 ]
ex1. 송금 도중 타임아웃으로 송금 서버가 응답을 받지 못하는 경우 == DB 저장 누락
--> 해결 : 과정에서 타임아웃이 발생했더라도,
송금 완료 시 코어뱅킹 서버가 Kafka 토픽을 통해 송금 서버에게 실행 결과를 전달
ex2. 타임아웃으로 인해 유저가 실패한 줄 알고 다시 송금하는 경우 (중복 송금 발생)
--> 해결 : 송금 요청 발생 시, 송금 요청을 DB에 저장, 코어뱅킹 서버로부터 컨슘 미발생시
(완료되지 않은 송금이 존재할 시) 송금 요청 거절. 문제 발생 되지 않은 경우에만 코어뱅킹 서버에 송금 요청
ex3. 송금 무한 지연 문제 (오래된 지연 송금 실패 처리)
--> 해결 : 송금 서버는 주기적으로 코어뱅킹 서버에게 송금 상태를 확인, 코어뱅킹 서버가 '없음'으로 응답
송금 실패 처리 --> 지연된 송금이 삭제되어 송금 가능 상태
ex4. 성공한 거래건에 대해 실패로 처리가 되었을 경우
(ex3의 경우에서 코어뱅킹 서버가 '없음'으로 응답하였는데, 뒤늦게 요청을 받은 코어뱅킹 서버가 요청을 수행한 경우== 실패로 처리가 되었는데 실제 거래가 진행됨)
--> 해결 : 타임아웃 시간을 약속, 타임아웃 시간 보다 오래된 요청은 거절하는 방법으로 해결
ex5. DB 장애로 인해 송금 이력 저장에 실패한 경우
--> 해결 : 재시도 (재컨슘 후 재저장) or 실패한 메시지를 Kafka 토픽 - Consumer DeadLetter에 저장
--> 개발자가 직접 확인 후 재컨슘 후 재저장
ex6. 이력 누락 가능성
--> 해결 : Event가 발생하였다는 Kafka 메세지 수신 시, 송금 서버와 Kafka 메세지의 거래 내역 일련번호를 확인하여 누락 여부 확인 후 동기화 실시 후 정보 제공
** 중간 내용 오류 발생 시 이후 거래 건에 대해서도 정보를 제공해 주지 않음 (잔액이 마이너스(음수)로 표시되는 상황 예방)
ex7. 방금 출금한 거래가 조회되지 않는 문제 해결
--> 해결 : 조회 시 거래 진행 중 상태라면, 즉시 계정계 DB와 거래 내역 동기화 (진행 중인 내역까지 모두 동기화 됨)
ex8. 동기화 지연 문제 (트래픽 과부화)
--> 해결 : Kafka의 메시지 처리 방식 -- 여러 파티션으로 분리 후 여러 컨슈머가 처리가능하게 함
ex9. 늘어난 파티션은 시스템 자원을 차지, 자원 낭비의 문제
--> 해결 : 적당한 수의 파티션을 유지한 상태로, 컨슈머별로 워커 스레드를 충분히 할당하여 처리
** 같은 계좌는 항상 같은 스레드 및 같은 파티션이 처리하여 동기화하도록 설정하여 과부하를 예방
2. '지속 성장 가능한 코드를 만들어가는 방법' - 김재민 (Server Developer)
- 지속 가능한 소프트웨어 == 지속 가능한 코드 기반
- NO 처음부터 최상의 설계 구축 YES 최소 규칙을 지켜 동작하는 소프트웨어 개발 후 관리, 성장
- import 중심의 코드 분석 (Package / Layer / Module) : 문제점 파악 및 개선에 용이함
[토스의 코드 작성 기조]
1) 통제 : 올바른 응집으로 코드 관리, Layer 간의 규칙을 지키며 적절한 Module화로 기술을 격리
--> 변화에 대응 및 제어 가능
2) 지속 성장 : 사업 유지 뿐만 아니라 산업을 이끌어가는 시스템을 구축하고자함
1. Package
현재 사항 점검 및 상황에 맞는 방법을 구축해야 함 (현재 상황에 대한 이해가 중요)
NO 개념적으로 같은 개념에 속하는 class인데도 import. 역할 기준 응집
YES import 양 감소. 개념을 기준으로 가까운 곳에 응집
- 문제 상황 : 한 개념에 존재하는 class가 많은 경우
- 해결 : 개념 세분화 (하위에 새 개념 추가, 구체적인 개념화)ex. Card 개념 --> 세분화 : Card 소유의 개념 새로운 Package로 응집 --> 기존의 Card Package를 import
2. Layer
[Rule 1] Layer는 순방향으로만(위에서 아래로) 참조되어야 한다
[Rule 2] Layer의 참조 방향이 역류되지 않아야 한다 *Rule 1과 유사
[Rule 3] Layer를 건너뛰지 않는다
- Business Layer의 코드 영역에서 Presentation Layer로 접근하는 문제 (역참조)
--> 해결 : Presentation Layer(상위 개념)에서 개념화 된 Class로 변환하여 Business Layer로 전달
** Layer 간의 잘못된 참조 : 코드의 복잡도 증가, 확장을 어렵게 함
3. Module
* 회색 원 : 외부 기능 확장시 새로운 Module을 만들어 가는 영역
NO 단일 모듈로 작업 : 특정 라이브러리에 대한 의존도 상승
YES Module 분리 : 외부 의존을 줄이는 방법
--> 장점 : 기술 격리, 각 module별 테스트 가능, 역할과 경계를 뚜렷하게 정의