Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
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
Archives
Today
Total
관리 메뉴

밤빵's 개발일지

[TIL]20241218 멱등성 처리 설계 초안 본문

개발Article

[TIL]20241218 멱등성 처리 설계 초안

최밤빵 2024. 12. 18. 02:08

PUBG 프로젝트에서 API를 여러 번 호출하거나 데이터를 저장하는 과정에서 중복 처리를 방지해야 할 필요가 있었다. API 호출이 실패하거나 여러 번 요청되면 중복 데이터가 저장되거나 시스템의 데이터 정합성이 깨질 수 있기 때문에, 해결하기 위해 Redis의 SETNX 명령어를 활용한 멱등성(Idempotency) 구조를 설계했다. 아직 Redis를 적용하지는 않았지만, 나중에 도입할 때를 대비해 중복 처리 방안과 구현 가능성을 구상했다.


1. 멱등성이란?

멱등성은 같은 요청을 여러 번 수행하더라도 결과가 변하지 않는 성질을 의미한다.
동일한 matchId로 PUBG 매치 데이터를 여러 번 요청하더라도 결과적으로 하나의 데이터만 저장되어야 한다.


2. 멱등성이 필요한 이유

API 재시도 처리
네트워크 지연이나 서버 오류로 동일한 요청이 여러 번 발생할 수 있다.
데이터 중복 저장 방지
중복 데이터가 저장되면 리소스 낭비와 데이터 불일치 문제가 발생할 수 있다.
시스템 신뢰성 확보
중복 처리를 방지하면 데이터 정합성과 시스템 안정성을 보장할 수 있다.

3. Redis를 활용한 중복 처리 설계

3-1. 설계 방향

중복 요청을 방지하기 위해 Redis의 SETNX(SET if Not eXists) 명령어를 활용하기로 구상했다.

  • matchId를 Redis의 키로 사용한다.
  • Redis에 해당 키가 존재하지 않을 때만 값을 저장한다.
  • TTL을 설정해 오래된 중복 처리 상태를 방지한다.

이 방식을 통해 동일한 matchId에 대한 중복 처리를 최소화할 수 있다고 판단했다.


3-2. 구상한 구현 예시

import org.springframework.data.redis.core.ReactiveRedisTemplate;
import reactor.core.publisher.Mono;
import java.time.Duration;

@Service
public class MatchesService {

    private final ReactiveRedisTemplate<String, String> redisTemplate;
    private final WebClient webClient;

    public MatchesService(ReactiveRedisTemplate<String, String> redisTemplate, WebClient.Builder webClientBuilder) {
        this.redisTemplate = redisTemplate;
        this.webClient = webClientBuilder.baseUrl("https://api.pubg.com/shards/").build();
    }

    public Mono<String> processMatchData(String platform, String matchId) {
        String redisKey = "match:processing:" + matchId;

        // [Redis의 SETNX 명령어를 활용하는 구조 구상]
        return redisTemplate.opsForValue()
                .setIfAbsent(redisKey, "processing", Duration.ofMinutes(5))
                .flatMap(success -> {
                    if (Boolean.TRUE.equals(success)) {
                        // [중복 처리가 방지된 경우 API 호출 및 데이터 처리]
                        return fetchAndSaveMatchData(platform, matchId)
                                .doFinally(signal -> redisTemplate.delete(redisKey).subscribe());
                    } else {
                        // [이미 처리 중인 데이터일 경우 에러 반환]
                        return Mono.error(new IllegalStateException("이미 처리 중인 요청입니다: " + matchId));
                    }
                });
    }

    private Mono<String> fetchAndSaveMatchData(String platform, String matchId) {
        return webClient.get()
                .uri("/{platform}/matches/{matchId}", platform, matchId)
                .header("Authorization", "Bearer YOUR_API_KEY")
                .retrieve()
                .bodyToMono(String.class)
                .doOnNext(data -> {
                    System.out.println("매치 데이터 저장: " + matchId);
                    // [DB 저장 로직을 여기에 추가할 예정]
                });
    }
}

4. 설계 과정에서의 고민

Redis의 SETNX 사용 이유
Redis의 SETNX 명령어는 키가 존재하지 않을 때만 값을 설정하기 때문에 간단하게 중복 처리를 방지할 수 있다.
API 호출이 여러 번 발생해도 중복 데이터 저장을 방지할 수 있다고 판단했다.
TTL 설정의 중요성
Redis에 TTL을 설정하지 않으면 장애로 인해 키가 삭제되지 않을 수 있다. 이를 방지하기 위해 TTL을 5분으로 설정해 오래된 중복 상태를 자동으로 정리할 수 있도록 했다.
아직 Redis 미적용 상태
실제로 Redis를 적용하지는 않았기 때문에 코드 레벨에서만 구현을 구상한 상태다. Redis 적용 시 이 구조를 빠르게 도입할 수 있을 것이라 예상중...!

5. 배운 점과 느낀 점

멱등성 설계의 중요성
중복 요청을 방지하고 데이터 정합성을 유지하기 위해 멱등성을 보장하는 구조가 필요하다는 것을 배웠다.
Redis 활용 가능성
Redis의 SETNX와 TTL 기능을 활용하면 중복 처리를 간단하게 구현할 수 있다는 점이 인상적이었다.
확장성을 고려한 설계
멱등성 구조를 미리 설계하면서 서비스가 확장되더라도 중복 처리 문제를 예방할 수 있다는 자신감을 얻었다.

중복 처리를 방지하고 데이터 정합성을 보장하기 위해 Redis를 활용한 멱등성 처리 구조를 설계했다. 아직 Redis를 적용하지는 않았지만, 이번 설계를 통해 미래에 빠르게 도입하고 확장할 수 있을 것이라 기대한다. Redis를 적용하고 테스트를 진행하면서 실제 상황에 맞게 추가적인 개선을 진행할 계획이다.