웹 페이지에 접속하면 가장 먼저 보이게 되는 첫 페이지는 거의 모든 사용자가 보게 된다. 이런 페이지는 자연스럽게 트래픽이 집중되고, 서비스 성능과 비용 효율성에 있어서 중요한 설계 포인트가 될 수 있다.
1페이지 캐싱이 필요한 이유를 이해하려면 먼저 캐시와 DB 통신 비용의 본질적인 차이를 이해해야 한다.
서비스에서 데이터를 불러오는 방식은 크게 두 가지로 나뉜다.
DB 조회
요청이 들어올 때마다 DB에서 직접 데이터를 가져온다. 이 과정에서 네트워크 I/O, 디스크 I/O가 모두 발생해서 요청량이 많아질수록 속도 저하와 부하가 생긴다.
메모리 캐시 조회
Redis
나 Memcached
와 같은 인메모리 캐시를 활용하여 자주 요청되는 데이터를 캐싱된 메모리에서 빠르게 제공한다. 캐시는 CPU에 가까운 고속 자원이기 때문에 DB에 비해 수십에서 수벡 배 빠른 응답이 가능하다.
이러한 차이를 이해하면 자주 조회되는 데이터를 캐시에 올려두는 것만으로도 성능 최적화와 비용 절감을 동시에 달성할 수 있다는 사실을 알 수 있다.
데이터의 변동성에 따라 갱신 주기를 설정해서 캐시 정책을 수립하기도 하는데 캐시도 결국 정확성과 신선도 사이의 Trade-off 문제이기 때문에 어떤 것에 더 중점을 두냐에 따라 방향이 조금 달라질 수 있다.
너무 자주 생신하면 DB 접근이 많아져 캐시의 의미가 없고, 너무 오래된 데이터를 유지하면 사용자에게 잘못된 정보가 전달될 수 있다.
캐싱 구조에 대해 배우면서 데이터 접근 방식 자체가 서비스 아키텍처와 얼마나 긴밀하게 연결되어 있는지 새삼 깨달았다. 캐시는 단순한 성능 도구를 넘어서 전체 시스템의 효율성을 좌우하는 핵심 설계 요소가 될 수 있다. 데이터 접근에도 전략이 필요하다!!!!
웹 서비스에서 로그인 인증방식을 결정하는데 '사용자의 인증 상태를 어디에 저장할 것인가'와 '이 상태를 어떻게 확장 가능한 구조로 유지할 것인가'가 중요한 화두이다. 이에 따라 진화해온 인증 방식을 간단히 알아보자
초기에는 사용자가 로그인을 하면 서버 내부 세션 저장소에 사용자 상태를 저장해두고, 클라이언트는 세션ID를 쿠리로 보유하나다. 이후 사용자의 요청에는 세션ID를 통해 상태를 식별하는 방식이 일반적이었다.
하지만 스케일 아웃이 필요한 상황에서는 문제가 발생한다. 로드밸런서를 통해 여러 서버 인스턴스에 요청이 분산되면 세션을 생성한 서버가 아닌 다른 서버로 요청이 전달 될 수 있기 때문이다. 다른 서버로 요청이 전달되면 인증 정보가 없으므로 오류가 발생한다.
위 문제를 해결하기 위해 스티키 세션(sticky session)
이라는 방식이 등장했다. 로드밸런서가 사용자의 요청을 항상 세션이 존재하는 동일한 서버로 전달하도록 고정해주는 방식이다.
하지만 이것도 문제점이 있다. 특정 서버로 트래필이 몰릴 수 있어서 로드밸런싱 효과가 제한되고 서버가 재시작되거나 장애가 발생하면 세션이 유실될 수 있다. 이 또한 무상태(stateless) 상태가 아니기 때문에 확장성이 부족하다.
위의 문제점들을 해결하기 위해 JWT
가 등장했다. JWT는 사용자의 인증 정보를 토큰에 암호화하여 클라이언트가 직접 보관하고, 이후 요청마다 서버로 이 토큰을 전달한다. 서버는 토큰의 유효성만 검증하면 되기 때문에 어느 서버로 요청이 전달되든 상관없이 인증처리가 가능하다. 완전 무상태 인증이 가능해진 것이다.
하지만 JWT에도 한계점은 있다. 탈취된 토큰은 재사용 가능성이 있고, 토큰 크기가 부담될 수도 있다.
그래서 AWS 같은 시스템에서는 JWT조차 사용하지 않고 AWS Signatur v4
방식같은 진짜 무상태 인증 방식을 사용하기도 한다.
데이터 관점에서도 인증구조가 무상태인지 상태 저장 기반인지에 따라 API의 사용 패턴이 달라지고, 로그 분석 등의 방식이 달라지기 때문에 전체적인 인증 로직을 이해할 필요가 있다.
기본 CRUD로 좋아요 기능을 구현하고 테스트를 진행했다. 초기에 제공된 프로젝트 패키지는 JPA + MySQL을 DB로 사용하는 구조, Eureka Server를 통한 서비스 등록 구조였다. 하지만 내가 맡은 서비스는 MongoDB를 사용하는 구조여서 별도로 MongoDB 연결 설정을 하고 테스트를 진행해야 했다. 이 과정에서 환경설정에 익숙하지 않다 보니 여러 번 에러가 발생했는데 그 덕분에 프로젝트 구조와 설정파일을 공부하고 이해하는 시간을 가질 수 있었다.
Spring Boot를 실행하면 콘솔에 임시 아이디와 비밀번호가 자동 출력되는데, 이 정보를 인증에 사용하지 않으면 테스트가 제대로 되지 않는지 몰라서 한참 헤맸다. 테스트는 Postman
으로 진행했는데 Basic Auth
설정에 아이디와 비밀번호를 입력해야 테스트가 정상 작동하는 것였다. 이전에는 터미널에서 Curl로만 테스트를 해봤기 때문에 Postman은 이번에 처음 써봤는데 생각보다 훨씬 편하고 직관적인 도구였다.
나는 VSCode로 코딩해서 Thunder Client
도 사용해봤는데 작동 방법은 Postman과 유사하지만 VSCode에서 바로 실행 가능하다는 점에서 아주 편하다.
이제 간단한 구현 하나는 끝났으니 2단계를 대비하기 위해 공부를 해야할 것 같다. 이런저런 생각은 하고 있는데 사실 구체화가 아직 덜 되기도 했고 특히 광고 관련해서는 처음해보는 작업이라서 감이 잘 잡히지 않는다. 하지만 지금처럼 하나씩 시도하고 익히면 한달 반 뒤에는 프로젝트가 완성되어 있겠지.
다음주와 2단계 작업들을 위해서 이번 주말은 정말 자알 보내보자🥹🥹🥹🥹