목록Architecture/Application (8)
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..

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 라이브러리를 사용할 수 있다. 스프링 프레임워크에서 기본적으로..
그런 REST API로 괜찮은가지금껏 RESTful 한 API를 설계하고 있는 줄 알았다. 'REST API 설계 가이드'를 구글링하고 다른 블로그 들에서 소개하는 REST API 형식에 따라 적절한 요청 메소드와 URL, 에러 코드와 응답 내용만 맞추면 그게 RESTful 하다고 생각하고 있었다. 이응준님의 그런 REST API로 괜찮은가 세미나를 보고, 그 생각이 완전히 부서졌다. 지금 내 설계를 REST API라는 단어로 표현하면, REST API를 처음 소개하고 제안한 로이 필딩이 노하실 것이다. 그래서 왜 Rest API라고 불리우는 인터페이스들이 로이 필딩이 제안한 RESTful이 아닌 건지, 그럼 진짜 REST API는 어떻게 만드는 건지 정리하고자 한다. "I am getting fru..