Bucket4j로 중복 요청을 방지
·
spring
사용자가 기존 데이터를 읽어 새로운 버전을 복사 생성하는 기능에서, 동일 사용자가 너무 빠르게 버튼을 눌러 동일한 데이터가 두 개 생성되는 문제가 발생했다. 이로 인해 불필요한 중복 요청과 함께 동일한 데이터가 공존하는 문제가 있었다. 기존 해결 방법 - DB Lock 사용초기에 이 문제를 해결하기 위해 데이터베이스에서 해당 Row에 Lock을 설정하여, 새로운 데이터가 커밋되기 전까지 동일한 데이터가 생성되지 않도록 조치했다.하지만 이 방법에는 단점이 있었다Lock 해제: 빠른 커밋이 발생하는 상황에서는 따닥 현상 해결을 보장하지 않음비정상적인 사용 패턴: 동일한 사용자가 짧은 시간내에 같은 CUD API를 여러 번 호출하는 것은 정상 요청이라고 보기 어려움새로운 데이터를 생성하는 요청에서는 Lock..
S3 파일 업로드 CPU 부하 개선
·
spring
사내에서 파일 업로드 기능을 두 가지 방식으로 제공하고 있습니다.서버에서 파일을 받고 S3에 업로드Presigned URL을 발급하고 클라이언트에서 Presigned URL로 직접 S3에 업로드문제첫 번째 방식은 구현이 간편하지만, 다음과 같은 CPU 사용 이슈가 있었습니다.속도 저하: 25MB PDF 파일 업로드 시 평균 4~6초 소요CPU 사용량 급등: 최대 80%, 평균 50%이를 해결하기 위해 Presigned URL 방식을 도입해 우회적으로 성능은 개선했지만, 또 다른 두 가지 문제가 발생했습니다.클라이언트 복잡성 증가: Presigned URL 관련 Flow 이해필요레거시 코드 호환성 문제: 기존 API를 사용하는 클라이언트 코드 수정의 불편함과 어려움현재 쿠버네티스 자원을 알뜰하고 사용하고 ..
Spring Data Envers로 이력 관리 자동화하기
·
spring
데이터의 변경사항마다 이력을 관리하는 것은 반복적이고 지루한 작업이다.이를 해결해 줄 수 있는 강력한 라이브러리인 Envers가 있다. JPA를 사용하는 환경에서는 이력 관리를 손쉽게 자동화할 수 있게 지원하고 있다.이번 글에서는 Spring Data Envers를 실무에 적용하면서 겪었던 경험과 문제 해결 방안을 공유하고자 한다.Spring Data Envers란?소개Hibernate Envers의 확장으로, Spring Data와 통합된 감사 라이브러리데이터 변경 이력을 자동으로 관리하는 기능 제공주요 특징엔터티의 Create, Update, Delete 이력 관리간단한 설정으로 엔티티 버전 관리 활성화이력 조회 API 제공(이전 상태와 비교 가능)기본 아키텍처이력 대상 _AUD 테이블 생성 (엔티티..
Kotlin DSL로 테스트 코드와 함께 API 문서화하기
·
spring/테스트
Spring 진영에서 API 문서화에 관심이 있다면 Swagger와 RestDocs를 한번쯤은 사용해봤거나 들어는 봤을 것이다.이번 문서에서는 Swagger, RestDocs 이 두가지의 장점만을 모아 Kotlin DSL로 리팩토링한 과정에 대해서 소개합니다. 커스텀 DSL 미리보기Swagger 라이브러리 문제점Swagger 사용법에 대해 검색해 보면, 컨트롤러나 사용하는 요청DTO, 응답DTO에 애너테이션을 선언하는 방식을 주로 설명하는 것을 확인할 수 있었다.이 방법은 간단하지만, 경험상 몇가지 문제가 있다는 것을 느낄 수 있었다.컨트롤러나 DTO를 봤을 때, 수 많은 애너테이션으로 인해 가독성 저하가 발생한다.수기 작성이다 보니 문서화에 필요한 타입이나 값들이 검증되지 않은 상태로 등록될 수 있다...
Spring Batch Partitioner를 이용한 최적화
·
spring
단일 스레드 방식의 한계점외부 서버 API로부터 데이터를 받아와 DB에 적재를 해야한다고 하자API 서버에 데이터를 요청할 때 모든 데이터가 아닌 page 단위로 요청해야하는 상황이라면 단건씩 요청을 해야한다.만약 페이지 수가 1000개라면, 단일 스레드에서 1000개 페이지에 데이터를 요청하고, 데이터베이스에 적재해야한다.위 작업을 단일 스레드에서 실행하면 모든 작업을 순차적으로 처리하기 때문에 페이지가 많을 수록 대기시간이 오래걸린다. 이를 해결해 줄 수 있는 방법은 Partitioner를 사용하여 멀티 스레드로 처리하는 것이다.구조파티셔너는 Step이 각 스레드에 배정되어 실행될 수 있도록 분배하는 역할이다.구체적인 분배 방법은 Partitioner 인터페이스를 구현하여 정의할 수 있다.방법파티셔너..
SpringBoot S3 Presigned URL 적용
·
spring
일반적인 파일 업로드/다운로드 방식우리 서비스는 파일을 업로드할 때 API 서버를 거쳐 S3에 저장된다.파일 다운로드도 마찬가지로 다운로드 요청을 받으면 S3로 부터 파일을 가져오고 서버에서 파일을 스트림으로 응답한다.이렇게 API 서버를 거치는 방식은 파일을 API 서버가 직접 처리할 수 있다는 것이다. 직접 처리할 수 있다는 의미는 특정 저장소에 직접 접근하여 저장할 수 있고, 바이너리 파일 검사(파일 포맷, 사이즈 등등), 인코딩 같은 전처리 작업을 수행할 수 있다는 것을 뜻한다.장점이 있듯이 단점도 존재하는데, 파일 처리를 직접 하므로 API 서버 자원을 그만큼 사용한다.문제 상황 Pinpoint APM 모니터링 중 CPU가 한번씩 튀는 현상을 발견했다.CPU가 튀는 시점을 종합했을 때 거의 대부..
복잡한 읽기 정책을 쉽게 풀어보자
·
spring
개요특정 사용자가 어떤 데이터를 읽을 때 이 사용자가 데이터 읽을 수 있는지 판별하는 비즈니스 요구사항이 있을 수 있다.대표적으로 사용자의 권한, 데이터 값에 따라 읽기 정책이 정해지는 두가지 방식이 있는데, 차이가 존재한다.사용자의 권한은 데이터 값에 상관없는 정책이다.만약 사용자의 권한이 부족하다면, 데이터를 읽을 필요도 없이 필터 단에서 요청을 거절하면되기 때문에 단순하다고 볼 수 있다.반면 데이터 값에 따라 읽기 정책이 정해진다면 데이터를 읽어봐야만 이 사용자가 읽을 수 있는 데이터인지 알 수 있다.이러면 읽기 비즈니스가 복잡할 때 여러 테이블과 조인하거나 외부 상태를 체크하는 등 로직이 복잡해질 수 있고,정책이 추가될 때 기존 로직을 분석하거나 기능 구현 중 실수로 이전 정책 로직들이 변경될 수..
JPA 상태 패턴 적용하기
·
spring
상황 결재 시스템에 필요한 상태를 아주 간략하게 표현했다.사용자가 결재를 저장하고 상신요청을 하게되면 결재 라인을 타게되어 결재자가 기안문서를 볼 수 있다.이후 결재 라인에 결재자 A, B, C 가 존재한다고 가정하고 정상적인 시나리오만 작성해 본다.모두 승인하는 케이스사용자가 기안을 올리면 상태는 저장에서 상신요청으로 변경된다.A가 결재를 승인하면 결재 상태는 상신 요청에서 진행중으로 변경된다.B가 결재를 승인하면 결재 상태는 그대로 진행중이다.C가 결재를 승인하면 결재 상태는 진행중에서 완료로 종결된다.한명이라도 반려하는 케이스A가 결재를 승인하면 결재 상태는 상신 요청에서 진행중으로 변경된다.B가 결재를 반려하면 결재 상태는 반려로 종결된다.문제점위 상태 흐름대로 해피 케이스만 실행되면 좋지만 항상..
Spring Security DSL 권한 계층 설정하기
·
spring
권한 계층이 필요한 이유쉽게 생각해 볼 수 있는 권한 체계는 계층이 있는 권한이다.간단하게 게시판 서비스에 권한이 3개 존재한다고 가정해 보자.일반 사용자: 게시글 조회만 가능VIP: 글 작성 가능관리자: 삭제/수정 관리 가능이때 VIP 권한에 일반 사용자 권한이 가지고 있는 게시글 조회 권한이 없다는 것은 상식상 이해할 수 없다.마찬가지 관리자가 게시글 조회 및 작성 권한을 가지는 것이 당연해 보인다. 스프링 시큐리티에서는 기본적으로 권한마다 허용 가능한 API를 별도로 설정해야 하는데,이러면 공통 허용 API가 추가될 때 마다 공통 권한을 만들고 공통 권한을 부여해야한다. 이런 문제를 해결하고자 스프링 시큐리티에서는 RoleHierarchy를 제공한다.스프링부트 3.2.3 기준으로 작성되어 있습니다...
헥사고날 기반 아키텍처
·
spring
회사 프로젝트의 기존 레이어드 아키텍처에서 DIP 원칙을 지켜 설계했지만,애매한 부분들이 있었고 이런 문제로 헥사고날 기반의 아키텍처를 적용해 봤습니다.헥사고날 아키텍처(포트와 어댑터)란?구글, 유튜브에 검색하면 질 좋은 글이나 영상이 많이 있어 이 글에서는 생략하도록 하겠습니다.구성 레이어헥사고날 아키텍처에서 레이어는 다음과 같이 구분됩니다.Inbound adapterUse caseDomainOutbound adapter각 레이어가 어떤 역할을 하는지 하나씩 알아보겠습니다.Inbound adapter(ui)사용자의 요청을 처리하는 영역입니다.외부에서 요청해야 동작한다고 하여 Driving Side Adapter 또는 Primary Adapter 로 불립니다.e.g.HTTP API (RestControl..
noose
'spring' 카테고리의 글 목록