목록Architecture/Application (9)
ecsimsw
배경 : 회원 가입이 실패되는 것이 옳을까?Picup 프로젝트에서 회원 가입이 요청되면 Member 서버에서 가입 내용을 기록하고, Storage 서버로 유저 타입과 함께 스토리지 생성을 요청한다. 기존에는 쉽게 가입을 실패시켰다. Storage 서버에서 처리에 실패하면 회원가입은 실패되었다. 외부 API 호출과 원자성, 서버 간 정합성이라는 키워드에만 집착해 기술로만 풀이하려고 했던 것 같다, 나라면 회원가입 폼을 열심히 작성했는데, 마지막 최종 제출에서 가입에 실패하면 그 서비스 안 쓸 것 같다. 가입 실패를 최소화하기 위해 외부 API 가 포함된 신규 가입 로직에서 필수적인 이벤트와 그렇지 않은 이벤트 분리를 고민했다. 그리고 각각의 이벤트 처리에서 발생할 수 있는 문제와 해결을 위한 고민을 정리..
두번의 갱신 분실 문제 발생유저가 파일을 업로드하면 사용 가능 공간을 확인하고 현재 사용 중인 공간을 업데이트한다. 업로드 동시 요청이 발생하는 경우, 마지막에 수행되는 커밋의 결과만 반영되어 의도하지 않은 값이 저장된다. 이렇게 여러 트랜잭션에서 동일한 데이터를 동시에 수정하려할 때, 마지막으로 수행한 수정만 반영되는 경우를 두번의 갱신 분실 문제라고 한다. # 두개의 스레드에서, 동시에 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 수를 조회하게 된다는 것이다. InnoD..
만약 DB 서버가 다운된다면? 이전 글 에서 DB 데이터 백업과 부하분산을 목적으로 DB replication 을 적용하고 Transactional readOnly 여부에 따라 DataSource 를 분기했다. 이 글에선 Master, Replica 중 하나라도 Connection 에 문제가 생기는 상황을 고민한다. DB 서버를 단순히 쿼리가 readOnly 인지 여부만으로 분기한다면 둘 중 하나라도 문제가 생길 경우 서비스의 읽기가 안되거나 쓰기가 안 되는 심각한 문제가 발생할 것이다. 다른 Stand by Master node 를 만들어두고 Master 가 다운 되었을 때 교체하는 방식, Master 가 죽었을 때 Slave 를 Master 로 승격시키는 방식 등 여러 정책을 고민했다. 그중에서도 아..
0. AS IS 기존에는 이 메인 / 백업 스토리지 업로드를 동기로 처리했다. 400KB의 이미지를 업로드할 때 main 33ms, backup 1680ms 정도가 필요했고, 사용자 응답은 이 둘을 더한 값 + ⍺ 가 될 것이다. 이미지 업로드 시에 각 스토리지 업로드를 비동기로 처리하되 모든 업로드가 정상일 경우에만 사용자에게 정상으로 응답하고자 한다. 그리고 동시에 비동기식 업로드 과정에서 생길 수 있는 더미 파일을 사용자 흐름에 포함하지 않고 처리하고자 한다. 이 글에선 위 요구 사항을 만족하기 위한 작업 과정을 소개한다. 목차는 다음과 같다. 1. 단순 비동기 처리 2. Future로 비동기 / 블록킹 방식으로 처리하는 경우, 그 문제점 3. CompletableFuture으로 쉽게 구현하는 다양..
캐시로 조회 성능 개선 Pic-up 은 앨범 기반 사진 스토리지이다. Picup 은 페이지네이션이 적용되어 있고, 서비스 특성상 사용자는 앨범을 조회 시 항상 첫 페이지의 사진들부터 확인한다. 전체 앨범 조회에도 마찬가지다. 사용자의 앨범 목록을 조회할 때도 항상 첫 페이지의 사진들부터 조회한다. 그리고 그 앨범, 사진들은 수정될 여지가 적다. 일반 게시물과는 다르게 사진을 앨범으로 한번 만들어두면 그 이후로는 사진을 삭제하거나 수정하는 요청보다는 단순 조회가 다수일 것이다. 그래서 조회 성능을 개선하고 DB에 접근하는 네트워크 비용을 아끼고자 캐시를 도입하게 되었다. 이 글에선 어떤 전략으로 캐시를 사용했고, Spring 에서의 설정 방법을 소개한다. 어떤 캐시를 사용할까 1 : 지역 캐시와 전역 캐시..
도메인 이벤트로 의존성 분리? 우아한테크코스 지원 플랫폼 개발을 하면서 제이슨한테 배운 개념이다. 그 당시에는 '오 멋진걸~, 이렇게도 할 수 있구나 🤩' 정도였도로 지나쳤었다. 패키지간의 의존, 리팩토링을 위한 분리를 고민하기 시작하면서 이제는 좀 더 와닿아서 이렇게 대박 기술인 양 정리하게 되었다. 문제와 요구 사항 커머스 서버를 만드는 프로젝트를 발전시키는 중이었다. 기존에는 없었던 명세였는데, 각 상품별 주문 횟수를 기록할 수 있다는 요구 사항이 추가되었다. 1. 사용자가 주문(Order)을 생성하게 되면, 그 장바구니에 포함된 각 제품(Product)에 orderedCount를 증가시킨다. 이 이전까지는 OrderService는 Product 관련 도메인을 분리해둔 상황이었다. 이번 요구 사항을..
스케줄러 정기적으로 실행해야 하는 테스크가 있을 수 있다. 일정 시간 간격으로 로직을 실행하거나, 일정 스케줄러는 그런 테스크를 처리하기에 유용하게 사용할 수 있다. 예를 들면 10초마다 한 번씩 혹은 매월 1일마다 한 번씩 지정한 로직을 수행하도록 하는 것이다. 이번 프로젝트에서 매일 한번씩 정산하는 로직을 수행해야 한다. 처음에는 아래처럼 단순히 요청 처리를 위한 스레드와 별도의 스레드를 생성하고 그 안에서 무한정 시간을 비교하는 로직을 수행하려 했으나, 스프링의 스케줄러를 사용하면 직접 스레드를 관리하지 않아도 되고, 시간 비교를 효율적으로 할 수 있을 것이라는 생각에 스프링 스케줄러를 사용하게 되었다. 스프링 프레임워크에서 Quartz 라이브러리를 사용할 수 있다. 스프링 프레임워크에서 기본적으로..