티스토리 뷰

 

 

이 책은 2025년 4월 28일에 출간된 따끈따끈한 신간이다. 배드민턴에서 땀을 나눈 파트너에게 추천을 받기도 했고, 팀장님의 블로그에서 이 책에 대한 언급을 보며 자연스럽게 관심을 갖게 되었다.


내용은 주니어 개발자가 반드시 알아야 할 핵심 주제들을 여러 카테고리로 나누어 정리한 구성이다. 만약 내가 신입 개발자였더라면, 아는 것보다 모르는 게 훨씬 많았을 것이고, 책을 이해하는 데도 훨씬 더 많은 시간이 걸렸을 것 같다.


만 3년 차가 된 지금 읽어보니, 알고 있던 내용은 복습처럼 다시 머릿속에 정리되었고, 몰랐던 부분은 새롭게 배울 수 있었다. 실제로 읽다가 “이건 처음 듣는 개념인데?” 싶었던 부분도 몇 군데 있었다.


아래에는 내가 읽으며 도움이 되었던 내용, 이전에는 몰랐던 내용, 나중에 다시 꺼내 읽고 싶었던 부분들을 정리해두었다.

 

 


DB 커넥션 풀 크기

서버는 DB와의 통신을 지속적으로 수행하기 때문에, DB 커넥션 풀 설정이 성능에 큰 영향을 미친다. 스프링 부트에서는 기본적으로 HikariCP를 사용하며, 최소 및 최대 커넥션 수는 기본값으로 10개로 설정되어 있다. 트래픽은 서비스 유형에 따라 시간대별로 달라진다.


예를 들어 금융 서비스는 낮 시간대, 게임 서비스는 저녁 시간대에 트래픽이 집중되는 경우가 많다. 이에 따라 커넥션 풀도 유동적으로 조절할 필요가 있다. 트래픽이 급증하는 패턴이라면 최소 크기를 최대 크기 수준으로 맞춰두는 것이 성능 저하를 방지하는 데 도움이 된다.


물론 커넥션 풀을 무조건 크게 잡는 것은 바람직하지 않다. DB의 상태를 고려해야 하며, CPU 사용률이 이미 높은 상태에서 커넥션을 더 열면 오히려 쿼리 처리 시간이 증가할 수 있다.



 

DB 커넥션 대기 시간

HikariCP의 기본 커넥션 대기 시간은 30초로 설정되어 있다. 하지만 일반적으로는 서비스 특성에 따라 0.5초에서 3초 이내로 설정하는 것이 권장된다. 대기 시간을 짧게 설정하면 커넥션 풀이 모두 사용 중일 때 사용자에게 "일시적 오류"를 반환하게 된다.


이는 부정적으로 보일 수 있으나, 오랜 시간 응답이 없는 것보다는 낫다. 짧은 대기 시간은 서버의 과도한 부하를 막고, 전체 시스템을 보다 안정적으로 유지하는 데 기여할 수 있다.




 

스트림을 활용하라

파일 다운로드 기능을 구현할 때, 파일 전체를 한꺼번에 메모리에 로딩해서 응답하는 방식은 지양해야 한다. 파일 크기나 동시 사용자 수에 따라 메모리 사용량이 급증할 수 있으며, 이는 Java 환경에서는 OutOfMemoryError를 유발할 수 있다.


스트림을 활용하면 파일을 부분적으로 읽고 처리할 수 있어 메모리 부담을 줄일 수 있다. 따라서 대용량 파일을 다루는 상황에서는 스트림 기반 처리 방식이 보다 안정적이다.

 



정적 자원과 CDN

브라우저 캐시는 각 사용자 단위로 동작하기 때문에, 많은 사용자가 동시에 접속할 경우 js, css 등 정적 파일이 대량으로 전송되며
네트워크가 급격히 포화될 수 있다. 이는 4차선 도로에 갑자기 수십 대의 차량이 몰려들어 교통 체증이 발생하는 것과 비슷하다.


이러한 상황에서는 CDN을 사용하는 것이 효과적이다. CDN은 클라이언트가 콘텐츠를 요청하면 가까운 CDN 서버에서 파일을 제공하고, 없는 경우에는 원본 서버에서 가져와 캐시에 저장한다. 이후에는 동일한 요청이 있을 때 캐시에서 바로 응답하게 된다. 이를 통해 원본 서버가 처리해야 할 트래픽이 크게 줄어들어, 전반적인 응답 속도와 안정성이 향상된다.



 

선착순, 예매 같은 대기 처리

공연 예매처럼 짧은 시간에 수많은 사용자가 몰리는 상황에서는, 서버와 DB 모두 큰 부하를 겪게 된다. 첫 번째 해결 방법은 트래픽 예측에 기반하여 서버와 DB를 미리 증설하는 것이다. 하지만 특히 DB는 증설 후 다시 줄이는 것이 어렵고 비용도 많이 든다.


전체 서비스 시간 중 극히 짧은 순간을 위해 고정된 비용을 계속 부담하는 셈이다. 두 번째 방법은 일정 수준의 트래픽만 수용하고 나머지는 대기 처리하는 방식이다. KTX 예매 서비스처럼, 일정 인원까지만 페이지에 접근을 허용하고, 그 외의 사용자는 대기열에 두는 것이다.


이 방식은 서버를 증설하지 않더라도 트래픽 폭주를 효과적으로 제어할 수 있고, 무한 새로고침으로 인한 불필요한 부하를 방지할 수 있다. 사용자가 대기하는 것이 불편하긴 해도, 서비스가 아예 접속 불가능한 것보다는 낫기 때문에 합리적인 선택이 될 수 있다.



 

미리 집계하기 (반정규화)

count나 sum 같은 집계 쿼리는 데이터가 적을 때는 문제가 없지만, 데이터가 많아질수록 성능 저하가 심해진다. 실제로 로그 데이터가 100만 건이 넘는 상황에서 count 쿼리 하나에 4초 이상 소요되는 사례도 있었다.


이럴 경우 첫 번째 방법은 집계 데이터 자체를 UI에서 제거하거나, 담당자와 협의하여 표시하지 않도록 조정하는 것이다. 두 번째 방법은 미리 집계한 결과를 별도의 칼럼에 저장해두는 방식이다. 이를 통해 실시간 집계 연산 없이도 빠르게 데이터를 제공할 수 있으며, 성능 문제도 동시에 해결할 수 있다.

 



상태 변경 기능은 복제 DB에서 조회하지 않기

복제 DB를 사용할 경우, 보통 조회는 복제 DB, 쓰기 작업은 주 DB를 통해 처리하게 된다. 그런데 이 구조를 오해하여 모든 조회 쿼리를 복제 DB에서 실행하게 되면 문제가 발생할 수 있다. 복제 DB는 주 DB의 데이터를 네트워크를 통해 복제받는 구조이기 때문에 일정한 지연이 존재한다.


이 지연 동안 복제 DB와 주 DB 사이에 데이터 불일치가 발생할 수 있다. 따라서 회원가입, 상태 변경, 삭제 등 변경이 발생하는 시점에 데이터를 조회해야 한다면 반드시 주 DB를 사용해야 한다. 그래야 변경 직후의 정확한 데이터를 기반으로 처리를 할 수 있으며, 복제 지연으로 인한 오류도 방지할 수 있다.

 



메시지 소비 측에서 고려해야 할 중복 처리

메시지를 소비하는 쪽에서는 동일한 메시지를 중복으로 처리하는 상황이 발생할 수 있다. 그 이유는 크게 두 가지다. 첫 번째는 메시지 생산자가 동일한 데이터를 가진 메시지를 두 번 보냈을 경우다. 이런 경우 수신자는 메시지를 구분할 수 있는 고유 ID를 기준으로 이미 처리한 메시지인지 확인하고, 중복 처리를 방지할 수 있다.


두 번째는 메시지 처리 중 오류가 발생했을 때다. 예를 들어 외부 API 호출 중 읽기 타임아웃이 발생하면 소비자는 실패했다고 판단해 메시지를 다시 수신하여 재처리할 수 있다. 하지만 실제로는 API 호출이 성공했을 수도 있기 때문에 이 부분이 문제가 될 수 있다.


이럴 때는 외부 API 자체가 멱등성을 갖도록 설계하는 것이 좋다. 멱등성(idempotency)을 갖추면 같은 요청을 여러 번 해도 결과가 동일하므로, 중복 요청에 대한 부작용을 줄일 수 있다.

 



궁극적 일관성

분산 시스템이나 비동기 연동에서 자주 등장하는 개념이 궁극적 일관성(Eventual Consistency)이다. 두 저장소 간에 데이터의 일관성은 보장되지만, 실시간으로 즉시 일치하지는 않고 일정 시간이 지난 뒤에 맞춰지는 방식이다.


한때 함께 일했던 팀장님이 “배송 완료 알림톡 받고 나서 다시 취소됐다는 알림이 온 적 없느냐”고 했던 말이 떠오른다. 실제로 쇼핑몰에서 알림 메시지를 보낸 뒤 상태가 번복되어 다시 알림이 오는 경우가 있는데, 이런 현상은 시스템 간 동기화가 완전히 되기 전에 발생하는 데이터 불일치 때문이다. 비동기 방식에서는 이처럼 일시적인 불일치를 감안해야 한다.

 



비동기로 돌아가는 세상

모든 시스템 연동이 반드시 동기 방식일 필요는 없다. 오히려 비동기로 구현해도 전혀 문제가 없는 경우도 많다. 물론 비동기 방식은 구조가 더 복잡해지고, 시스템 간 데이터 불일치가 발생할 가능성도 있어서 고려할 부분이 많아진다.


하지만 성능이나 확장성, 자율성 측면에서는 오히려 더 유리할 수 있다. 그래서 비동기 방식은 단순히 기술적인 선택이 아니라, 복잡도 증가 대비 얻을 수 있는 이점이 더 크다면 충분히 고려해볼 가치가 있다.

 



HMAC을 이용한 데이터 검증

API 통신에서 클라이언트가 서버로 데이터를 전송할 때, 중간에 누군가가 데이터를 위변조하면 실제 지급해야 하는 포인트보다 더 많은 포인트가 지급되는 등 문제가 발생할 수 있다. 이를 방지하려면 메시지가 위변조되지 않았다는 것을 확인할 수 있는 방법이 필요하다.


이럴 때 주로 사용하는 기술이 HMAC이다. HMAC은 Hash-based Message Authentication Code의 약자로, 메시지의 무결성과 인증을 보장하는 암호화 방식이다. 메시지 발신자와 수신자가 공유하는 비밀 키를 기반으로 메시지를 암호화하고 검증할 수 있다.


예전에 shopline이라는 쇼핑몰 서비스에서 HMAC을 사용하는 사례를 접한 적이 있다. 클라이언트가 request body와 함께 HMAC 값을 보내주면, 서버 측에서 동일한 방식으로 생성된 값을 비교하여 메시지가 위변조되지 않았는지 확인할 수 있다. 이런 방식으로 API 보안을 강화할 수 있다.

 



QUIC 프로토콜

TCP는 안정적이지만 느리고, UDP는 빠르지만 신뢰성이 부족하다. 이 두 프로토콜의 장점을 결합한 것이 바로 QUIC이다. QUIC은 UDP를 기반으로 하면서도 TCP처럼 연결을 관리할 수 있도록 설계되었다.


예를 들어 연결 ID를 통해 두 노드 간의 세션을 유지하고, 혼잡 제어나 패킷 유실 복구 기능도 QUIC에서 직접 제공한다. 또 하나의 큰 특징은 TLS와의 통합이다. 기존 HTTPS는 TCP 연결을 위한 3-way 핸드셰이크와 TLS 핸드셰이크를 별도로 진행해야 했는데, QUIC은 이 과정을 하나로 통합함으로써 연결 수립 시간을 단축시킨다.


현재 QUIC은 HTTP/3의 기반이 되며, 크롬·엣지·사파리 등 주요 브라우저가 이미 이를 지원하고 있다. 구글, 페이스북 등 대규모 트래픽을 처리하는 기업들도 QUIC 기반의 HTTP/3를 채택하고 있다. 빠르면서도 안정성을 갖춘 통신이 필요한 상황에서는 QUIC이 점점 더 주목받고 있다.



'∙도서' 카테고리의 다른 글

소프트 스킬  (5) 2025.01.02