목차
인증 토큰 조회 부하를 줄인 네 단계 개선 (2023-06)
원문 정보
- 원문: 쏘카의 대규모 인증토큰 트래픽 대응 : 개발기
- 매체 · 게시일: 쏘카 기술 블로그 · 2023-06-27
- 저자: 올리 (어카운트 버킷)
- 원문 내용을 바탕으로 재구성한 요약입니다.
쓰기 DB 하나에 몰린 인증 검증
쏘카의 모든 요청은 인증 토큰 검증을 거칩니다. 트래픽이 낮을 때는 쓰기 DB 하나로 충분했지만 트래픽이 늘면서 부하가 급격히 커졌습니다. 여러 시스템이 편의상 DB에 직접 접근하고 있어 성능 문제에 더해 DB 종속 문제도 있었습니다. 팀은 쓰기 DB 부하를 나눠 응답 속도를 개선하는 것을 목표로 잡았지만, 기존 서비스에 영향을 주지 않고 변경을 최소화하면서 달성할 수 있을지는 확신하지 못했다고 합니다. 작업 순서는 아래 네 단계입니다.
인증 검증 전용 서비스로 모으기
인증 토큰을 처리하는 메인 서비스와 PHP 레거시 서비스 3개, 그 밖의 레거시 서비스가 모두 DB에 접근했습니다. 같은 기능이 여러 프로젝트에 흩어져 있어 DB 연결 설정 하나를 바꾸려 해도 관련 프로젝트를 모두 찾아 반복 수정해야 했고, 하나라도 빠뜨리면 장애가 날 수 있었습니다. 그래서 DB 접근을 계정 서비스 한 곳이 맡고 다른 서비스는 요청만 보내도록 바꿨습니다.
읽기 요청을 읽기 전용 DB로 보내기
쓰기 DB와 읽기 전용 DB가 따로 있었지만 호출하는 서비스가 쓰기 DB로만 요청을 보내, 단순 조회 부하까지 쓰기 DB에 몰렸습니다. 쓰기 DB를 scale up하면 일시적인 서비스 중단을 피할 수 없고 이미 고사양 장비라서 scale out을 택했습니다.
분산 방법으로 두 가지를 비교했습니다. 하나는 LazyConnectionDataSourceProxy를 상속해 읽기 전용 트랜잭션이면 읽기 DB 커넥션을 쓰는 방식입니다. 다른 하나는 MariaDB connector 2.7이 지원하는 aurora protocol로, 쓰기와 읽기 클러스터 endpoint를 JDBC URL에 나란히 적으면 드라이버가 분산하고 failover도 지원합니다. 일정이 짧아 코드 변경을 줄여야 했고, 새로 만든 계정 서비스가 해당 버전을 쓰고 있어 후자를 골랐습니다. 이 방식은 connector 3.x 이후에는 지원되지 않습니다. 적용 뒤 조회 요청이 읽기 DB로 옮겨 간 것을 요청 수 그래프로 확인했습니다.
만료된 토큰 분리 보관
토큰 테이블에는 만료된 토큰까지 남아 약 2800만 건이 쌓여 있었습니다. 인덱스 재구성 비용이 커지고 쓰기 락 경합 때문에 조회도 기다리는 상태였습니다. 부하 분산은 임시 해결일 뿐이고, 삭제는 고객센터가 인증 이력으로 쓰고 영향 범위 파악에 시간이 걸린다는 이유로 제외했습니다. 만료 토큰 테이블을 따로 만들어 옮기는 방식을 택했습니다.
작업은 두 단계 배치입니다. 먼저 1회성 배치로 기존 만료 토큰을 옮기고 지우되, DB CPU 부하를 피하려 5일에 걸쳐 회당 450개로 제한했습니다. 이후에는 1시간 단위 배치가 계속 옮깁니다. 첫 배치가 끝난 뒤 테이블 행은 약 86% 줄어 2백만 개가 됐습니다.
Redis 캐시 계층
읽기 DB로 나눠도 총 조회 수는 그대로여서 캐시를 넣었습니다. 조회는 토큰 값으로 하는 경우와 회원 ID로 하는 경우가 있어 캐시 키가 둘이고, 쓰기 때마다 캐시를 고치면 데이터 불일치가 생길 수 있습니다. 조회가 쓰기보다 압도적으로 많은 특성을 감안해 쓰기 DB 요청을 줄이기보다 불일치 해소를 우선했습니다. 전략은 Look Aside에 Write Around를 합친 것이고, 쓰기 시에는 캐시를 수정하지 않고 삭제해 다음 조회 때 다시 채웁니다. 결과로 읽기 DB 부하와 계정 서비스 latency가 줄었다고 합니다.
일정은 당초 2개월에서 1개월 남짓으로 줄었습니다. 이 압축 과정은 /external/socar/blog/12-auth-token-traffic-planning/에 있습니다.
수치와 설정 정리
| 항목 | 값 |
|---|---|
| 만료 토큰 포함 시 토큰 테이블 규모 | 약 2800만 건 |
| 분리 후 토큰 테이블 규모 | 약 2백만 건(약 86% 감소) |
| 1회성 이관 배치 | 5일, 회당 450개 |
| 이후 이관 배치 주기 | 1시간 |
| 읽기 분산 방식 | MariaDB connector 2.7의 aurora protocol(3.x 이후 미지원) |
| 캐시 전략 | Look Aside + Write Around, 쓰기 시 캐시 삭제 |
| 개발 기간 | 계획 2개월에서 1개월 남짓으로 단축 |