# Rate Limit이란?일정 시간 동안 호출될 수 있는 API 횟수를 제한하는 걸 말한다. 예를 들어 파일 업로드는 10분에 최대 3번만 가능 이런 걸 구현할 때 사용하는 개념이다. 자세한 건 아래글 참조https://gngsn.tistory.com/224 Rate Limiter, 제대로 이해하기Rate limiter의 역할과 강단점을 살펴보고, 구현 알고리즘 5가지를 이해하는 것이 해당 포스팅의 목표입니다. 본 포스팅의 모든 그림은 필자가 직접 그린 것으로 무단 사용을 금하며, 사용 시 출처gngsn.tistory.com 이번 글에서는 로컬 캐시 라이브러리로 유명한 Caffeine으로 Rate Limiter 기능을 구현해 볼 것이다. # 왜 Caffeine인가?Spring Cloud Gateway..
JPA 영속성 컨텍스트가 제공하는 기능 중 하나인 '1차 캐싱' 기능을 눈으로 직접 확인해 보자 @Serviceclass FirstService( private val userRepository: UserRepository,) { @Transactional fun callFirst() { var user = userRepository.findById(1).get() println("first call user = $user") user = userRepository.findById(1).get() println("second call user = $user") user = userRepository.findById(1).ge..
서버에서 예외(에러)가 나면 보통 이런 응답이 내려간다. 이 에러메시지 그대로 유저에게 보여주는 건 바람직하지 못하다. 그래서 보통 에러메시지를 유저편의적으로 가공하는데, 이를 '에러메시지 워싱'이라고 표현한다. # 얼마나 구체적인 에러 메시지를 보여줄까?워싱 주체에 대해 논하기 전, 먼저 유저에게 어떤 에러메시지를 보여주는 게 적합할지 생각을 해보자. 정답은 아닐 수도 있지만, 필자는 이렇게 생각한다. 1. 유저 스스로가 다른 액션을 통해 해당 에러를 해소할 수 있는 경우는 최대한 구체적으로 알려준다. ex) 회원가입 시 비밀번호 규칙 중, 특수기호가 포함되어야 하는데 빠진 경우추상적인 경우: 비밀번호 규칙에 올바르지 않습니다.구체적인 경우: 특수기호가 빠졌어요. 비밀번호에는 적어도 1개 이상의 특수..
# != 연산에 인덱스 태우기where 절의 not equal(!=) 연산은 인덱스를 걸어놔도 효과를 볼 수 없다. 이런 경우 해당 칼럼이 순차적인 코드값으로 되어있는 경우는 인덱스를 태우도록 꼼수(?)를 부릴 수 있다. * 디비는 오라클 기준 예를 들어, my_table이 존재하고 my_column이 이런 분포를 가진다고 해보자. 1000 : 32만 rows2000 : 10만 rows3000 : 5만 rows4000 : 22만 rows5000 : 1만 rows6000 : 43만 rows 그리고 my_column이 1000이 아닌 rows를 select 한다고 가정해보자. 인덱스를 걸어놔도, select * from my_table where my_column != '1000' 으로 하면 full sca..
build.gradle이나 build.gradle.kts의 dependencies를 정의하는 부분에 이런 식의 코드를 본 적 있을 것이다. dependencies { implementation("mysql:mysql-connector-java") api("org.springframework.boot:spring-boot-starter-data-jpa")} 이때 두 선언 모두 의존성 설정이 되는데, 어떤 차이가 있는지 알아보자. # 멀티모듈 의존성다음과 같은 멀티모듈 환경에서 api, core 모듈 모두 동일한 의존성이 필요하다고 해보자 api모듈의 dto에 bean validation을, core 모듈의 dto에도 bean validation을 걸고 싶은 상황이고, validation 의존..
@Transactional로 감싸진 블록은 RuntimeException을 상속받는 예외를 맞이하면 자동적으로 롤백을 해준다. 그런데 간혹, 여러 데이터를 저장할 때 일부는 실패하더라도 트랜잭션이 성공했으면 바라는 경우가 있다. 그럴 때 Transaction silently rolled back because it has been marked as rollback-only라고 에러가 발생하면서 전체 롤백이 되는 경우가 있다. 왜 이런지 구체적으로 알아보도록 하자. # 예시 상황총 5명의 User의 포인트를 1씩 증가시켜가며 저장할 것이다.이때 포인트가 2이면 예외를 발생시킨다.예외가 발생하더라도 다른 User는 저장에 성공해야 한다.@Serviceclass UserTestService( priva..
필자가 회사에서 다루는 데이터는 주로 고객 데이터로, 1000만 건 정도 된다. 무거운 로직을 전체고객에 대해서 수행하거나, 주기적으로 수행되는 배치의 성능을 개선하기 위해서 시도했던 것들과 적용하는 노하우 몇 가지를 정리한다. # 배치 프로그램에서 챙겨야 할 것들일반적으로 필자가 배치 프로그램을 만들 때 중요하게 고려하는 건 다음과 같다. 1. 모수의 사이즈2. 수행 시간이 얼마나 걸리는지3. 멱등성과 실패 시 재처리 방법 모수의 사이즈모수의 사이즈는 배치 수행시간과 직접적으로 연결되므로 매우 중요하게 고려해야 한다. 또한 트랜잭션을 너무 오래 물고 있지 않도록 고려해야 하므로 모수 측정은 반드시 선행되어야 한다. 수행 시간이 얼마나 걸리는지필자 기준 1시간이 넘어가면 오래 걸린다고 판단하여 성능..
일반적으로 API를 설계할 땐, REST 원칙을 적용하여 설계하곤 한다. 이번 글에서는 내가 생각하는 실무적인 RESTful 한 API와 그 과정에서의 trade-off 몇 가지를 공유하고자 한다. 생성, 수정, 삭제 API의 응답에 관하여 게시글을 생성, 수정, 삭제하는 API를 설계한다고 해보자. REST 원칙에 의거하면 다음과 엔드포인트는 같이 설계할 수 있을 것이다. POST /boards PUT /boards/{boardId} DELETE /boards/{boardId} 이때 종종 각 API의 응답 필드에 대한 고민을 할 때가 많다. 응답은 생성/수정/삭제된 boardId만 리턴할 것인가? 아니면 내용 전체를 리턴할 것인가? 엄격하게 RESTful 하게 설계한다면, 각 API의 응답은 board..