티스토리 뷰
나는 응모하기 기능의 중복 호출을 막기 위해 api 수정이 필요했다.
1. nest.js의 throttler
nestjs의 throttler는 ip 기반으로 api rate limit을 체크하고 있다.
하지만 우리는 웹사이트가 아니고 앱 기반이었고 wifi, 모바일 데이터 사용 여부에 따라 변경될 수 있기 때문에 이 방법은 적절하지 않았다.
2. redis로 중복 호출 막기
api를 호출할 때 유저 고유 번호도 파라미터로 받는다.
그 값을 key로 받고 저장시킨후 로직 마지막에 레디스 키를 삭제시키는 과정을 거쳤다.
// 레디스 조회/생성 같이 하기
async setLock(redisKey: string, ttl: number = 3) {
const result = await this.cache.setnx(redisKey, 1);
if (result) {
await this.cache.expire(redisKey, ttl);
}
return result;
}
// 레디스 키 삭제
async releaseLock(redisKey: string) {
return await this.cache.del(redisKey);
}
코드 설명:
setnx는 지정된 키가 존재하지 않을 때만 값을 설정한다.
만약 redisKey가 이미 존재한다면 0을 반환하고 return 0을 반환
만약 키가 존재한다면 즉, 키를 성공적으로 설정한 경우 key에 대한 만료 시간을 설정한다.
주의할 점은 redis key를 찾는 부분과 저장하는 부분을 같이 하지 않으면 중복 생성이 되었다.
동시에 여러 요청이 들어오면, 각 요청은 Redis에 데이터가 존재하는지 확인 후 없다면 새로운 데이터를 생성하려고 한다. 이 과정에서 데이터 존재 여부를 확인한 후 실제 데이터를 생성하는 사이의 짧은 시간 동안 다른 요청이 동일한 데이터 존재 여부를 확인할 수 있다. 만약 첫 번째 요청이 데이터를 생성하기 전에 두 번째 요청이 데이터 존재 여부를 확인한다면, 두 번째 요청은 데이터가 없다고 판단하고 중복으로 데이터를 생성하려고 할 수 있다.
실제로 db에 테스트 해본 결과 위에서 조회 후 저장하는 부분을 따로 따로 한 경우 중복되어 응모가 되었고(중복되어 데이터 생성)
위에처럼 조회/생성을 같이한 경우에는 중복생성이 되지 않았다.
아래는 조회/생성을 따로한 코드이다.
// 잘못된 코드
async applyRaffle(userSeq: number, raffleSeq: number) {
const requestKey = `applyRaffle:user:${userSeq}`
// 조회
const existsRaffleUser = await this.redisClient.getRaffleApplyCacheByUser(requestKey);
if(existsRaffleUser) {
throw new BadRequestException("이미 래플 요청함!");
}
// 저장
await this.redisClient.setRaffleApplyCacheByUser(userSeq, raffleSeq);
}
왜 이런 일이 발생하는지 검색해보니
redis가 기본적으로 단일 스레드로 동작하여 각 명령을 순차적으로 처리하지만, 여러 클라이언트가 동시에 같은 데이터를 생성하려고 할 때 그 사이의 시간 간격에서 발생하는 경합 조건 때문이라고 한다.
*경합 조건(Race Condition)
두 명렁어가 동시에 같은 기억 장소를 액세스할 때 그들 사이의 경쟁에 의해 수행 결과를 예측할 수 없게 되는 것
테스트 방법
postman의 runner를 이용하여 테스트 하였다


'프로그래밍 > 백엔드' 카테고리의 다른 글
| DTO의 역할에 대해 알아보자 (0) | 2026.10.03 |
|---|---|
| typeorm repository api where like query undefined로 들어올 때 조회되는 이슈 (0) | 2026.10.02 |
| [Nest.js] api 응답 객체 포맷 만들기 response format (0) | 2022.12.01 |
| [Nest.js] forRoot, forFeature 정의와 사용 예시 (0) | 2022.11.25 |
| [Nest.js] main.ts에서 swagger 파일 분리하기 (0) | 2022.11.24 |
- Total
- Today
- Yesterday
- 자바
- ORACLE 단일테이블
- jdk1.7 다운
- ORACLE MERGE INTO 동일테이블
- merge into using
- 단일쿼리문
- 개발자
- npm init
- merge into
- merge into 단일테이블
- merge into 같은 테이블
- 신입사원
- Java
- merge into using dual
- package.json
- jdk 이전버전 다운
- 알고리즘
- 초보개발자
- npm이란
- 인스턴스
- 백준알고리즘
- ORACLE MERGE INTO USING DUAL
- java1.7 다운
- 신입개발자퇴사
- 백준
- 신입사원개발자
- C++
- 개발자퇴사
- 파이썬
- ORACLE MERGE INTO 같은테이블
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
