목록 분류 전체보기 (299)
유닛테스트와 통합테스트나는 가급적 Test를 위한 Application context 를 지양했다. 유닛 테스트로 테스트 환경을 구성하는 시간을 줄이고 각 테스트를 짧게 하려고 노력했던 것 같다. 예를 들면 Controller는 standalone mock mvc로 api 의 요청, 응답 형태만 확인했고, Service Unit test는 테스트 외의 Service를 Mocking 하여 의도한 흐름대로 메서드가 호출되는지 정도만 확인했다. 통합테스트를 최대한 지양했지만 역설적으로 가장 크게 안정감을 얻고 있는 테스트는 통합테스트였다. 특히 트랜잭션 처리가 의도한대로 동작하는지, 예외 처리 끝에 데이터가 어떻게 남는지 확인하는 등 가장 헷갈리고 놓치기 쉬운 포인트는 결국 통합테스트에서 확인하게 되는 것 ..
배경WAS 전면에 Nginx 를 두고 TLS, HTTP2.0, RateLimit, 정적 자원 호스팅 등 요청을 전처리하고 있다. 이 Nginx 의 메트릭을 모니터링하려고 한다. WAS 의 응답 시간, 요청 수뿐만 아니라, Nginx가 전면에서 처리하는 응답 시간, 요청 수, 리다이렉트 수가 궁금했다. nginxlog-exporter처음에는 Nginx가 기본적으로 제공하는 exporter 를 사용했었다. nginxinc/prometheus-exporter 에서 알 수 있듯, 해당 exporter 에서 제공하는 메트릭은 충분하지 않았고, 응답 시간을 포함한 원했던 메트릭은 대부분 Nginx plus 에서만 제공했다. nginx 의 액세스 로그에 응답 시간을 남기는 설정이 있음을 미리 알고 있었다. 그래서 ..
배경슬슬 담당하는 프로젝트의 기능 개발이 마무리되고 있다.보안 확인, API 성능 테스트, 운영을 위한 모니터링 / 로깅 환경 구성..작은 팀이라 사람당 한 두개의 키워드를 맡아, 점검하고 있고,나는 DB 조회 성능 확인을 맡았다. DB에 데이터가 쌓였을 때도 조회 성능에 문제가 없을지, 커넥션 부족으로 이어지진 않는지를 검토했다.가장 중요한 로직의, 주요 데이터를 천만개까지 늘려 테스트했다.데이터를 만드는 방법부터 인덱스나 쿼리 수정 고민 과정을 적어볼 생각이다. 튜닝 키워드는 아래와 같다.1. 더미 데이터를 추가하고 쿼리 조회 성능을 확인한다.2. 인덱스/커버링 인덱스를 적용한다.3. 실행 계획으로 인덱스 튜닝 결과를 확인한다.4. OFFSET 기반 페이지네이션의 문제를 확인하고 개선한다. 더미데이터..
배경사용자로부터 이미지를 수신, 이를 3D 변환 애플리케이션에서 읽을 수 있도록 이미지를 전달하는 API 서비스를 운영하고 있다.처음 이 서비스는 특정 고객사 내부망에 납품된 형태로 시작했다. 폐쇄된 환경이다 보니 디스크 저장 밖에 선택지가 없었고, 외부 접근을 걱정할 일도 없었으니 별도 보안도 신경 쓰지 않았던 것 같다.팀의 목표는 이 서비스를 살려 SaaS로 전환, 클라우드에 배포하고 외부 사용자가 접근할 수 있도록 하는 것이었다. 파일 저장소가 S3로 바뀌었고, 보안을 신경 써야 했다.사용자의 사용 패턴을 명확하게 알고 있던 기존보다, 더 다양한 사용 케이스와 이에 따른 사용성을 고민해야 했다. 여러 개선 포인트가 있었고, 나는 그중에서도 이미지 업로드, 파일 관리 서비스를 메인으로 담당했다.이 글..
두 번의 갱신 분실 문제 발생유저가 파일을 업로드하면 사용 가능 공간을 확인하고 현재 사용 중인 공간을 업데이트한다. 업로드 동시 요청이 발생하는 경우, 마지막에 수행되는 커밋의 결과만 반영되어 의도하지 않은 값이 저장된다. 이렇게 여러 트랜잭션에서 동일한 데이터를 동시에 수정하려할 때, 마지막으로 수행한 수정만 반영되는 경우를 두 번의 갱신 분실 문제라고 한다.# 두개의 스레드에서, 동시에 5MB 파일을 업로드할 때Thread 1 - 현재 스토리지 사용량 조회 0MBThread 2 - 현재 스토리지 사용량 조회 0MBThread 1 - 스토리지 사용량 기록 5MBThread 2 - 스토리지 사용량 기록 5MB 낙관적 락낙관적 락은 조회와 수정에 버전을 함께 확인하여 충돌 여부를 파악한다. 엔티티 버전을..
Mysql InnoDB 의 RepeatableRead Mysql 의 기본 Transaction isolate 수준은 RepeatableRead 이다. RepeatableRead 는 트랜잭션이 시작된 시점 이후로 여러 번 Select Row 를 확인해도 동일한 값을 갖는다는 것이다. Mysql 은 SnapShot을 사용해서 이를 보장한다. 트랜잭션마다 별도의 스냅샷을 기록하여 다른 트랜잭션이 값을 변경하고 Commit 해도 이 스냅샷을 이용해서 동일한 값을 읽게 되는 것이다. Phantom read 문제Repeatable Read 는 데이터의 추가, 삭제의 변경은 막지 못해 Phantom read 문제가 발생한다. 한 트랜잭션 내에서 전과 다른 조회 결과 row 수를 조회하게 된다는 것이다. InnoDB..
GC와 Stop the world JVM의 가비지컬렉터는 힙 영역의 메모리에서 더 이상 사용되지 않는 자원을 정리하는 역할을 한다. 이때 사용되지 않는다란 다른 지역 변수, static 변수, 파라미터, JNI의 객체, 다른 힙 영역의 객체 등에서 더 이상 참조되지 않는 것을 말한다. 아래 그림에서 빨간색으로 표시된 Unreachable objects는 GC의 대상이 된다. 이때 자원을 정리하는 과정에서 새로운 객체가 할당되거나 객체 간 연결이 생길 경우를 방지하기 위해, GC를 위한 스레드를 제외한 모든 스레드의 작업이 중단된다. 이런 GC를 위한 애플리케이션 전체 중단 시간을 Stop the world라고 한다. ( 보다 자세한 STW가 필요한 이유 ) 두가지 GC와 처리 영역들 Stop the wo..
0. AS IS 기존에는 이 메인 / 백업 스토리지 업로드를 동기로 처리했다. 400KB의 이미지를 업로드할 때 main 33ms, backup 1680ms 정도가 필요했고, 사용자 응답은 이 둘을 더한 값 + ⍺ 가 될 것이다. 이미지 업로드 시에 각 스토리지 업로드를 비동기로 처리하되 모든 업로드가 정상일 경우에만 사용자에게 정상으로 응답하고자 한다. 그리고 동시에 비동기식 업로드 과정에서 생길 수 있는 더미 파일을 사용자 흐름에 포함하지 않고 처리하고자 한다. 이 글에선 위 요구 사항을 만족하기 위한 작업 과정을 소개한다. 목차는 다음과 같다. 1. 단순 비동기 처리 2. Future로 비동기 / 블록킹 방식으로 처리하는 경우, 그 문제점 3. CompletableFuture으로 쉽게 구현하는 다양..