들어가기현재 진행중인 프로젝트인 'AmorGakCo(아모르각코)'는 사용자들이 모각코 모임을 개설하고 사용자의 위치를 기반으로 모각코 모임을 조회하는 서비스입니다.서비스 기능의 핵심에는 사용자 현 위치를 기반으로 주변 모각코 모임을 조회하는 일입니다.어떤 데이터베이스를 선택하고 어떤 설계를 가져가야할 지 고민한 내용을 정리했습니다. 데이터 특성모각코 모임 데이터 특징은 아래와 같이 가정했습니다.데이터 생명주기는 짧게는 반나절 길게는 하루~이틀 예상종료된 모각코는 위치조회 대상에서 제외(비영구적)가장 활발히 모각코가 진행될 때 최대 5만건 정도로 가정 (한국 개발자 현황 약 80만명)한 모임에 4-5명인 모각코 모임을 최대 5만건으로 예상하면 참여자는 20만명이 넘기 때문에 충분한 가정이라 생각합니다.또한..
들어가기지난번 포스팅에선 스프링의 힘을 빌려 @Async로 API Latency를 개선했습니다. 하지만 비동기 처리 중 네트워크 문제나 AWS의 문제로 S3 폴더 이동에 제약이 생겨 실패한다면 식별,복구하기가 매우 어렵습니다. 안전한 비동기 처리를 위한 방법들을 알아보겠습니다. Redis Pub/SubRedis의 Pub/Sub은 Publisher가 Channel(Topic)에 이벤트를 발생시키면 Channel을 구독하던 Subscriber(Consumer)가 이벤트를 받아 처리하는 구조입니다. 현재 프로젝트에 대입해보자면 1. 사용자의 게시글 등록 요청2. 이미지 정보 DB에 저장3. S3 tmp 폴더에서 original폴더로 이동시키는 이벤트 발행4. 사용자에게 성공 응답5. Subscriber가 이벤..
들어가기비동기 작업을 이용하려면 스레드 풀을 이용해야 합니다. 요청마다 스레드를 생성하게 되면 생성 비용, 메모리 부족, 콘텍스트 스위칭 비용 등 여러 문제가 발생한다. 따라서 적정 수준의 스레드 수를 선택하는 방법을 알아보려합니다. CorePoolSize, WorkQueueSize, MaximumPoolSize, KeepAliveTime스레드 풀은 스레드를 미리 생성해 놓고 요청이 발생하면 스레드를 할당한 뒤에 응답이 완료되면 해당 스레드는 제거되지 않고 스레드 풀에 반환됩니다. CorePoolSize : WorkQueue가 꽉 차지 않으면 스레드는 CorePoolSize 만큼 생성돼 존재합니다. CorePoolSize를 넘어서는 요청은 WorkQueue에 대기합니다. MaximumPoolSize : ..
들어가기 게시글과 이미지 등록 API 분리로 API Latency 개선기 1들어가기게시글을 등록하는 API와 S3에 이미지를 업로드하는 API를 한 곳에서 처리하다 보면 응답 대기시간이 이미지 개수에 비례해 증가하게 됩니다. 컨트롤러에서 게시글 데이터와 이미지 데curiosity-s.tistory.com 지난번 개선기 1에서 API 분리를 통해 응답시간을 개선해보려 했습니다. 결과는 개선되지 못했고 이번 포스팅에서 그 이유와 해결책을 찾아보도록 하겠습니다. 게시글 등록 요청 시 S3에 폴더 이동 API를 사용 중게시글과 이미지 등록을 분리 시킬 경우 사용자가 중간에 이미지를 등록하고 중간에 게시글 작성 페이지를 이탈하는 경우 S3의 이미지 객체는 고아객체가 됩니다. 해당 문제를 해결하기 위해서 S3에..
들어가기게시글을 등록하는 API와 S3에 이미지를 업로드하는 API를 한 곳에서 처리하다 보면 응답 대기시간이 이미지 개수에 비례해 증가하게 됩니다. 컨트롤러에서 게시글 데이터와 이미지 데이터를 한꺼번에 받아서 처리중인 코드입니다. 게시글을 저장한 뒤에 파일들을 S3에 저장하는 서비스 코드입니다. 위 컨트롤러를 포스트맨으로 테스트 해보겠습니다. 테스트는 간단한 게시글의 제목과 내용 그리고 이미지 7장을 서버에 전송했습니다. 933ms 소요됐습니다. 거의 1초라고 봐도 무방합니다. 이 수치는 이미지의 수가 늘어날 수록 증가하게됩니다. 이번엔 이미지 파일을 3장 추가해서 총 10장을 서버에게 요청해 보겠습니다. 응답대기 시간은 약 1370ms로 이미지 개수 증가에 따라 응답시간이 46%로 크게 증..
들어가기 우아한 객체지향을 듣고 느낀점만 많아서는 안되겠다는 생각이 들어 진행중인 프로젝트의 도메인 객체와 서비스 레이어를 유심히 살펴봤습니다. 도메인이 의존해서는 안될 코드를 하나 발견했고 이를 정리해보려 합니다. 도메인이 암호화를 책임지는 코드 아래는 회원을 관리하는 엔티티다. 도메인 객체에 passwordEncode 라는 메서드로 비밀번호를 암호화 하고있는데 처음엔 자신의 상태(password)는 자신이 변화시켜야한다고 생각했기에 도메인 내부에서 처리하고 있었습니다. @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User { @Id @GeneratedValue(strategy = GenerationTyp..
스프링을 사용하다 보면 @Value를 통해. yml 또는. properties에 정의된 속성을 가져오곤 합니다. 현재 진행중인 프로젝트에서도 @Value를 통해 jwt 설정을 가져와 사용 중입니다. public class JwtService { private static final String USER_UNIQUE_CLAIM = "user_unique_id"; private static final String ACCESS_TOKEN_SUBJECT = "AccessToken"; private static final String REFRESH_TOKEN_SUBJECT = "RefreshToken"; private static final String TOKEN_TYPE = "Bearer "; @Value("$..
들어가기 밑에서 설명하겠지만 스프링 빈들은 Spring Container에서 관리되기때문에 Spring Container 바깥에서는 자유롭게 접근할 수 없다. 대표적으로 Servlet Container(필터가 존재하는 곳)는 Spring Container에 접근할 수 없는데,,, 왜 굳이 불편하게 접근이 어려운 곳에서 인증과 인가를 처리하는 지 의문이였다. 학습 후 내가 내린 결론은 불편하긴 하지만 서버 깊숙히 들어오기 전(필터 단에서) 모든 인증 인가 처리를 하기위해서라고 생각된다. Servlet Container 흔히 볼 수 있는 클라이언트와 서버간의 통신을 요약해 놓은 그림이다. 스프링부트는 톰캣(WAS)를 내장하고 있기 때문에 스프링을 실행시키면 자동으로 톰캣이 실행된다. 톰캣은 요청을 사용하기 ..