1. 개요운영 환경으로 넘어가면서 Redis 3대를 띄워 운영하기로 했다. 개발 중인 시스템에서 Redis는 단순 캐시가 아니라 세션, 토큰, 진행 중인 작업 상태를 담는 원본 저장소이고, 모든 인증 요청이 Redis를 거친다. 즉 Redis가 멈추면 서비스 전체가 멈춘다. 한 대로 운영한다는 건 서비스 한복판에 단일 장애점(SPOF)을 두는 셈이었다. 처음엔 "3대면 클러스터로 묶으면 되겠지?" 라고 생각했다. 내 머릿속의 클러스터는 "여러 대를 하나로 묶어서, 한 대가 죽어도 나머지가 계속 서비스하는 것"이었다. 그런데 막상 구성 방법을 찾아보니 전혀 다른 이야기가 나왔다. Redis에서 말하는 클러스터(Cluster)는 내가 생각한 그 클러스터가 아니었다. Redis Cluster의 본업은 여러 대..
1. 개요온프렘 우분투 서버 여러 대에 Spring Boot 마이크로서비스를 컨테이너로 배포해야 하는 일이 생겼다. 서버가 1대 => N대가 되면 어떻게 될까?N대에 각각 SSH로 들어가서 같은 작업을 반복해야 한다서버마다 올라가는 서비스가 다르다 → 어디에 뭘 올렸는지 기억에 의존하게 된다설정 파일(.env)이 서버마다 조금씩 다른데, 손으로 고치다 보면 반드시 어긋난다새 서버를 추가하면 위 과정을 처음부터 다시 한다 가장 큰 문제는 "반복"이 아니라 "현재 상태를 아무도 모른다"는 것이다. 서버에 실제로 뭐가 떠 있는지가 사람 기억에만 있으면, 시간이 지날수록 문서와 실제가 벌어진다. 왜 셸 스크립트로는 부족한가?지금까진 웬만한 자동화는 AI로 셸 스크립트를 만들어 간단하게 사용했다. 하지만..
1. 개요Cascading FailureMSA 환경에서 서비스 A가 서비스 B를 호출한다고 하자. B가 죽어버리면 A는 어떻게 될까? 직관적으로는 "B 호출하는 API만 실패하겠지"라고 생각하지만, 실제로는 그렇지 않다. [정상] A 서비스 (스레드 200개) ──▶ B 서비스 (정상, 50ms 응답) ㄴ 평소엔 동시 호출 10~20개 정도 [B가 응답 지연 시작 — 죽은 게 아니라 "느려진" 상황] A 서비스 (스레드 200개) ──▶ B 서비스 (30초 후 타임아웃) ㄴ 호출이 30초씩 잡혀 있으니 스레드가 안 풀림 ㄴ 새 요청이 들어와도 가용 스레드가 없음 ㄴ A의 다른 API (B와 전혀 무관한 것까지) 응답 못함 B 하나가 느려졌을 뿐인데 A 전체가 마비된다. 이게 Ca..
1. 개요Access Token, Refresh Token은 면접 단골 질문이다. Q. "Refresh Token을 왜 사용하나요?" A. "Access Token의 TTL을 길게 발급하면 탈취됐을 때 위험이 크니까, Access는 짧게 두고 Refresh Token으로 갱신받는 식으로 보안과 UX를 챙기기 위해서…" 틀린 말은 아니지만, 다만 이 답에서 멈추면 곧바로 따라붙을 수 있다. - "그럼 길게 사는 Refresh Token은 왜 안전한가요?" - "어차피 둘 다 클라이언트에 있는데, 결국 같은 위험 아닌가요?" - "Refresh가 탈취되면 그게 오히려 더 큰 손해 아닌가요?" 막상 깊게 들어가 보면 단순 암기로는 안 되는, 여러 trade-off가 얽힌 설계 문제다. Access..
개요사내에서 모니터링 제품을 개발하는 팀이 있고, 전사적으로 해당 제품을 표준으로 사용하기로 결정되었다. 하지만 그 제품이 도입되기 전에 담당 서비스의 모니터링이 급해졌고, 직접 PLG Stack을 구성했다.분산 추적을 위한 Tempo, 메트릭 수집을 위한 Prometheus, 로그 수집을 위한 Loki를 도입해 Grafana에서 대시보드를 넘나들며 모니터링할 수 있는 환경을 만들었다. AI 덕분에 구성 자체는 손쉽게 마쳤지만, 각 컴포넌트가 어떻게 동작하는지, 왜 가볍다고 하는지, 운영에서 신경 써야 할 부분은 무엇인지 짚어보려 한다. 로그 수집 시스템을 도입할 때 가장 먼저 떠오르는 선택지는 ELK(Elasticsearch + Logstash + Kibana)다. 사실상 업계 표준이었고, 검증된 스..
1. 개요사내에서 Spring AOP를 활용한 FeatureFlag 도입을 맡게 되었다. 커스텀 어노테이션과 Spring AOP를 조합해 메서드 단위로 기능을 ON/OFF하거나 분기 처리할 수 있는 구조를 설계했다. 사용 방식은 간단하다. @FeatureFlag 어노테이션이 붙은 메서드가 호출될 때 AOP가 개입하여, 설정값에 따라 해당 메서드를 실행할지, 아니면 대체 메서드로 분기할지를 결정한다. 그런데 사용 중 한 가지 문제를 발견했다. private 메서드에는 AOP가 동작하지 않는 것이다. 처음엔 구현 실수인가 싶었지만, 조사해보니 이건 Spring AOP의 근본적인 동작 방식에서 비롯된 제약이었다. 이번 글에서는 이 현상의 원인을 파헤치며, Spring AOP의 내부 동작 원리를 깊이 있게 살펴..