이전에 API 요청/응답 로깅 과정에서 민감 정보를 마스킹하는 로직을 적용한 경험이 있습니다.String maskedRequestBody = SensitiveDataMasker.maskSensitiveData( new String(requestBodyBytes, StandardCharsets.UTF_8));내부 API의 경우, 요청 스펙과 데이터 구조에 대한 제어 권한이 전적으로 서비스 내부에 있었기 때문에해당 마스킹 로직을 수정하더라도 영향 범위가 제한적이었고, 유지보수 측면에서도 큰 문제가 되지 않았습니다.하지만 동일한 마스킹 로직을 외부 API 로깅에도 그대로 적용하면서 구조적인 한계가 드러났습니다.외부 API는 요청 필드의 명명 규칙이 통일되어 있지 않으며, 민감 정보가 항상 동일한 키 이름으..
이전에 여러 프로토콜을 공부하면서, 프로토콜은 서로를 대체하기 위해 존재하기보다는 각자가 해결하지 못하는 영역을 보완하는 방향으로 진화해 왔다는 점이 인상 깊었습니다. 즉, 하나의 프로토콜이 모든 문제를 해결하는 구조가 아니라, 역할을 분리하고 그 위에 다른 기술을 결합하는 방식으로 전체 구조가 완성된다는 관점입니다. 이 관점을 웹에 그대로 적용해 보면, 웹 애플리케이션 계층의 중심에는 여전히 HTTP가 존재합니다. 그리고 우리가 흔히 말하는 HTTP/1.1, HTTP/2, HTTP/3는 서로 다른 목적의 별도 프로토콜이 아니라, 동일한 HTTP 모델을 유지한 채 성능과 연결 관리의 한계를 개선해 온 진화 과정에 가깝습니다. 한편 HTTPS는 새로운 프로토콜이 아니라, HTTP 통신 위에 TLS를 결합하..
리트라이 전략에 대해 2개의 포스트를 통해 학습을 진행하였습니다. 외부 API 실패는 어떻게 다뤄야 할까? Retry 전략 설계기외부 API를 사용한다는 것은 내가 통제할 수 없는 환경에 의존한다는 의미입니다. 즉, 외부 API의 상태 변화는 언제든지 우리 서비스의 결과에 직접적인 영향을 줄 수 있습니다. 만약 외부 API 호출b-programmer.tistory.com Retry 전략 - 수치는 어떻게 지정해야 할까Retry 전략을 코드로 직접 구현해 보니, 자연스럽게 몇 가지 숫자들이 눈에 들어오기 시작했습니다. max-attempts, backoff-millis 같은 값들입니다. 처음에는 AI의 도움을 받아 무난한 값으로 설정했지만,b-programmer.tistory.com리트라이 전략에 대해 간..
지금까지 개발을 하면서 REST가 아닌 다른 프로토콜을 접해볼 기회는 거의 없었습니다. 그러다 보니 자연스럽게 REST만 사용해 왔던 것 같습니다. REST의 장점은 사용하기 편하다는 점에 있다고 생각합니다. HTTP 메서드, 헤더, 요청과 응답 구조가 직관적이고 이해하기 쉬워서다른 프로토콜을 굳이 학습해야겠다는 필요성을 느끼지 못했던 것 같습니다. 하지만 API 프로토콜은 생각보다 REST만 존재하는 것이 아니었습니다. 이번 기회를 통해 각 프로토콜의 특징과, 왜 사용되는지에 대해 알아보고자 합니다.들어가기에 앞서올바른 API 프로토콜은 성능, 보안 및 확장성에 매우 중요합니다. 개발자는 다음 요소를 고려해야 합니다gRPC는 REST보다 빠르고 더 많은 설정이 필요합니다.Websockets는 실시간 상..
Retry 전략을 코드로 직접 구현해 보니, 자연스럽게 몇 가지 숫자들이 눈에 들어오기 시작했습니다. max-attempts, backoff-millis 같은 값들입니다. 처음에는 AI의 도움을 받아 무난한 값으로 설정했지만, 구현이 진행될수록 하나의 의문이 생겼습니다. 이 값들이 정말 모든 상황에 동일하게 적용되어도 괜찮을까? 외부 API의 특성은 모두 다릅니다. 어떤 API는 일시적인 네트워크 지연만 견디면 되고, 어떤 API는 장애가 길게 이어질 수도 있습니다. 그럼에도 불구하고 모든 외부 통신에 동일한 retry 횟수와 backoff 시간을 적용하는 것이 과연 효율적인 설계일지 의문이 들었습니다. 물론 테스트와 운영을 거치며 수치를 조정해 나갈 수는 있습니다. 하지만 그 이전에, 어떤 기준으로 이..
개발을 완료한 이후에도, 사용자는 여전히 서비스가 느리다고 느낄 수 있습니다. 이는 절대적인 처리 속도의 문제가 아니라, 지연 시간이 불안정하게 발생하기 때문입니다. 사용자 경험은 단순히 빠르다, 느리다로 결정되지 않습니다. 몇 ms의 지연 차이만으로도 사용자의 이탈률은 유의미하게 변화하며, 실제로 일부 대규모 서비스에서는 1ms의 지연이 수십만 원 단위의 비즈니스 손실로 이어지기도 합니다. 그렇다면 문제는 단순합니다. 속도를 무작정 높이는 것이 아니라, 지연이 어디에서 발생하고 있는지를 구분하고, 그에 맞는 전략을 선택해야 합니다. 이 글에서는 지연 시간을 Network, Server, Client 관점에서 나누어 살펴보고, 지연을 줄이기 위해 선택할 수 있는 설계 전략들을 정리해보려 합니다.Laten..
외부 API를 사용한다는 것은 내가 통제할 수 없는 환경에 의존한다는 의미입니다. 즉, 외부 API의 상태 변화는 언제든지 우리 서비스의 결과에 직접적인 영향을 줄 수 있습니다. 만약 외부 API 호출 과정에서 문제가 발생한다면, 선택지는 크게 두 가지로 나뉩니다. 첫 번째는 아무것도 하지 않는 방법입니다. 외부 API가 실패하면 그대로 실패로 처리하고, 그 결과를 그대로 받아들이는 방식입니다. 이 접근은 겉보기에는 단순해 보이지만, 사실상 외부 API의 안정성을 그대로 우리 서비스의 안정성으로 끌어오는 설계입니다. 이 경우, 외부 API의 일시적인 장애나 네트워크 지연만으로도 요청 스레드가 장시간 점유되거나 처리 지연이 누적되거나 심각한 경우 내부 서비스까지 함께 불안정해질 수 있습니다. 물론 try-..
자바 5에서는 enum, 어노테이션, 제네릭이 도입되었습니다. 이 중에서 처음 자바를 접하는 사람들이 가장 부담 없이 사용하는 기능은 아마 enum일 것입니다. 클래스를 생성하는 것만으로도 왜 필요한지, 어떻게 사용해야 하는지가 비교적 직관적으로 드러나기 때문입니다. 반면 어노테이션과 제네릭은 다릅니다. 문법 자체는 사용할 수 있지만, 사용한다고 해서 코드에 즉각적인 변화가 생긴다고 느끼기는 어렵습니다.그래서 실제로는 사용하고 있음에도 불구하고, 왜 필요한지에 대해서는 깊이 고민하지 않고 넘어가는 경우가 많습니다. 하지만 자바 표준 라이브러리나 스프링 프레임워크 내부를 살펴보면, 어노테이션과 제네릭이 사용되지 않는 영역을 찾기 어려울 정도로 널리 활용되고 있다는 사실을 확인할 수 있습니다. 그만큼 이 두..
가용성이라는 말을 들어보았지만 진지하게 가용성이라는 단어가 어떤 의미를 내포하는지 생각하지 않는거같습니다.가용성이란 시스템, 네트워크, 프로그램 등이 사용자가 필요로 하는 시점에 정상적으로 작동하고 접근 가능한 정도를 말한다고 합니다.그렇다면 고 가용성이라는 말은 도대체 뭘까요? 이미 가용성이라는 단어부터 정상적으로 접근이 가능한것을 나타내고 있는데 그것을 뛰어넘는 무언가일까요?그래서 고가용성이 뭔데?사실 가용성은 이분법적인 관점이 아니라고 합니다. yes or no가 아닌 %라고 합니다. 고가용성은 장애가 발생해도 사용자가 체감할 만큼 서비스가 멈추지 않도록 설계된 상태라고 합니다. 용어는 대략적으로 알았는데 이것을 어떻게 측정할 수 있을까요? 멱등성이나 정합성처럼 했다고 작업하면 그렇게 되어지는 건가..
카프카를 계속 공부해 왔지만, 솔직히 말하면 "왜 이걸 써야 하는지" 스스로 완전히 납득했다고 말하기는 어렵습니다.문서와 강의에서는 늘 대규모 트래픽, 이벤트 스트리밍, 비동기 아키텍처 같은 이야기들이 나오지만, 막상 내 프로젝트와 내 문제를 떠올려 보면 카프카는 항상 거대한 산맥처럼 느껴졌습니다. 너무 크고, 너무 무겁고, 그래서 쉽게 다가가기 어려운 존재였습니다.어쩌면 이 글에는 카프카를 사용하면서 겪은 고생담이나 운영 노하우는 없을지도 모릅니다. 대신, “그래서 우리는 도대체 카프카를 왜 쓰는가?”라는 질문에 대해, 적어도 나 스스로는 납득할 수 있는 답을 찾는 과정을 정리해 보려고 합니다. 이 글은 카프카를 잘 쓰는 방법이 아니라, 카프카를 써야 할 이유를 이해하기 위한 기록입니다.카프카는 어떤 ..
모놀리식으로 개발된 제품을 마이크로서비스 아키텍처(MSA)로 전환한다고 하면,흔히 도메인 단위로 코드를 분리하고, 서비스를 나누는 작업부터 떠올리기 쉽습니다. 실제로 복사·붙여넣기 방식으로도 분리는 가능할 수 있습니다. 하지만 문제는 가능하냐가 아니라 안전하냐 입니다. 이미 운영 중인 서비스를 전제로 한다면, MSA 전환은 단순한 구조 개선이 아니라 서비스를 멈추지 않고 구조를 바꾸는 과정이 됩니다. 이 글에서는 모놀리스에서 MSA로 전환할 때 도메인 설계 이전에 반드시 고민해야 할 전환 전략과, 서비스 중단 없이 점진적으로 구조를 바꿀 수 있는 대표적인 패턴들을 살펴보려 합니다.어째서 모놀리식에서 MSA로 가야 하는가?이야기에 앞서 어째서 모놀리식에서 MSA로 가야하는지 이해를 해야할거 같습니다. 모놀..
지금까지 패턴을 왜 사용하는지에 초점을 맞춰서 얘기를 했다면 이번에는 조금은 다를겁니다. 어쩌면 패턴들중에서 가장 실용적인 패턴이 아닌가 싶습니다. 저는 현재 구독 서비스를 개발중에 있습니다. 구독하는 방식에는 카드, 계좌, 토스페이로 결제하는 방법들이죠. public PaymentTossResult toss(PaymentTossCommand command) {...}public PaymentCardResult card(PaymentCardCommand command) {...}public PaymentBankTransferResult bankTransfer(PaymentBankTransferCommand command) {...}이 코드들은 전부 구독에 대한 결제 부분입니다. 다만 내용물이 조금씩은 다..