인프런 커뮤니티 질문&답변

LEE-YOONSEON님의 프로필 이미지

작성한 질문수

실습으로 배우는 선착순 이벤트 시스템

문제점 해결하기

레디스 적용 시 여러번응모 테스트에서 에러가 발생합니다.

작성

·

627

·

수정됨

0

@SpringBootTest
class ApplyServiceTest {
	@Autowired
	private ApplyService applyService;

	@Autowired
	private CouponRepository couponRepository;

	@Test
	public void 한번만응모() {
		applyService.apply(1L);

		long count = couponRepository.count();

		assertThat(count).isEqualTo(1);
	}

	@Test
	public void 여러번응모() throws InterruptedException {
		int threadCount = 1000;

		//ExecutorService : 병렬 작업을 간단하게 할 수 있게 도와주는 Java API
		ExecutorService executorService = Executors.newFixedThreadPool(32);
		// CountDownLatch : 다른 Thread에서 수행하는 작업을 기다리도록 도와주는 클래스
		CountDownLatch latch = new CountDownLatch(threadCount);

		for (int i=0; i<threadCount; i++) {
			long userId = i;
			executorService.submit(() -> {
				try {
					applyService.apply(userId);
				} finally {
					latch.countDown();
				}
			});
		}

		latch.await();

		long count = couponRepository.count();

		assertThat(count).isEqualTo(100);
	}
}
@Service
public class ApplyService {
	private final CouponRepository couponRepository;
	private final CouponCountRepository couponCountRepository;

	public ApplyService(CouponRepository couponRepository, CouponCountRepository couponCountRepository) {
		this.couponRepository = couponRepository;
		this.couponCountRepository = couponCountRepository;
	}

	public void apply(Long userId) {
		Long count = couponCountRepository.increment();
		System.out.println("count : "+count);
		// long count = couponRepository.count();

		if (count > 100) {
			return;
		}

		Coupon save = couponRepository.save(new Coupon(userId));
		System.out.println("save! : "+save.getId());
	}
}
@Repository
public class CouponCountRepository {
	private final RedisTemplate<String, String> redisTemplate;

	public CouponCountRepository(RedisTemplate<String, String> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public Long increment() {
		try {
			return redisTemplate
				.opsForValue()
				.increment("coupon_count");
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}
}


여러번응모 테스트 케이스 실행

CouponCountRepository.java의 increment 메서드에서
다음과 같은 에러가 발생하고 있습니다.

제일 처음에 나는 에러메시지는 다음과 같습니다.

Caused by: io.lettuce.core.RedisCommandExecutionException: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.


쿠폰도 정상적으로 등록되지 않아 아에 0개로 출력되고 있습니다.

구글링을 해봤지만 도저히 원인을 찾을 수가 없어요 ..

++

추가로, 도커에서 레디스 컨테이너와 이미지를 삭제한 후 실행해도 동일한 결과가 나타나는 것을 확인됩니다.
강의에서 나온 그대로 도커 명령어를 사용해서 레디스를 pull 하였는데 왜 컨테이너와 이미지를 삭제해도 동일한 오류가 발생하는 걸까요?

도커에서 레디스 컨테이너와 이미지를 삭제하고 ApiApplication을 실행하면 정상적으로 실행됩니다...

++

 

정리 드리자면,
1. 강의를 그대로 따라했는데 RedisCommandExecutionException가 발생하면서 테스트 케이스를 실행할 수 없는 이유
2. 강의에서 나온 그대로 도커 명령어를 사용해서 레디스를 pull 하였는데 왜 컨테이너와 이미지를 삭제해도 동일한 오류가 발생하는 이유
3. 도커에서 레디스 컨테이너와 이미지를 모두 삭제하고 ApiApplication를 실행했을 때 정상적으로 실행되는 이유

답변 부탁드립니다.

답변 2

1

최상용님의 프로필 이미지
최상용
지식공유자

yoonseon12님 안녕하세요.
제가 해당오류를 겪어보지는 않았지만 구글링을 해보니 https://velog.io/@guswns3371/Redis-MISCONF-Redis-is-configured-to-save-RDB-snapshots-but-it-is-currently-not-able-to-persist-on-disk 이러한 게시글을 찾았습니다.

위 게시글에서 말한대로 config set stop-writes-on-bgsave-error no 를 해보셔도 오류가 발생하나요 ?

LEE-YOONSEON님의 프로필 이미지
LEE-YOONSEON
질문자

강사님 해결했습니다 감사합니다.

저도 같은 내용을 구글링을 통해 확인했었는데

config set stop-writes-on-bgsave-error no

명령어 실행만 했었을 때는 적용이 되지 않았으나,

PC 재부팅 및 레디스 서버 restart를 진행해야 적용이 되는 것 같네요 ㅎㅎ

답변 감사합니다.

추가 질문으로

3. 도커에서 레디스 컨테이너와 이미지를 모두 삭제하고 ApiApplication를 실행했을 때 정상적으로 실행되는 이유

가 궁금합니다!

0

안녕하세요, 인프런 AI 인턴입니다.

yoonseon12님, Redis 관련 에러가 발생했을 때, 해결 방안에 대해 질문 주셨군요.

에러 메시지에 따르면 Redis 서버가 RDB 스냅샷을 디스크에 저장하는 데 실패했고, stop-writes-on-bgsave-error 옵션이 활성화되어 있어서 데이터 변경 명령어를 실행할 수 없는 상태입니다. 이 설정은 백그라운드에서 RDB 스냅샷 생성에 실패했을 때, 데이터 변경이 일어나지 않도록 보호하는 역할을 합니다.

해결 방법은 아래와 같습니다:

  1. Redis 서버의 로그를 확인해서 RDB 스냅샷이 디스크에 저장되지 못하는 구체적인 원인을 파악하세요.

  2. Redis 구성 파일(redis.conf)에서 stop-writes-on-bgsave-error 옵션 값을 no로 설정할 수 있습니다. 하지만 이 방법은 임시적인 해결책일 뿐, 실제로 원인을 해결하지는 않기 때문에 추천하지 않습니다.

  3. 디스크 공간이 충분한지, 디스크 쓰기 권한 등이 있는지 확인하세요.

  4. Docker 컨테이너를 사용할 경우, 컨테이너의 볼륨(영속화된 데이터 저장 공간)이 올바르게 설정되어 있는지 확인합니다.

또한, RedisContainer가 올바르게 제거되었는지 여부와 관련하여, Docker를 사용할 경우 컨테이너를 삭제해도 사용된 이미지가 캐싱되어 있어 같은 문제를 계속 겪을 수 있습니다. 이 경우 다음 단계를 따라 문제를 해결하세요:

  1. Docker 컨테이너를 완전히 정지 및 삭제합니다.
docker stop <container_id_or_name>
docker rm <container_id_or_name>
  1. 관련된 Docker 이미지를 삭제합니다.
docker rmi <image_id_or_name>
  1. 도커 볼륨을 체크하여 문제가 되는 볼륨이 있다면 삭제합니다.
docker volume ls
docker volume rm <volume_name>
  1. 필요한 경우 Docker 시스템을 정리하여 미사용 데이터를 제거합니다. (주의: 사용중인 데이터도 삭제될 수 있습니다.)
docker system prune

Application이 정상적으로 실행되는 경우, 로컬 환경에서의 설정 문제일 수 있습니다. 예를 들어, 로컬 Redis 서버가 돌아가고 있지 않거나, 올바르게 설정되지 않은 경우 어플리케이션은 내장된 H2 같은 메모리 데이터베이스를 사용하게 될 수 있습니다.

구체적인 설정과 상황을 다시 한 번 확인해 보시고, 여전히 문제가 해결되지 않는 경우 추가적인 로그 정보나 상황에 대한 설명을 주시면 더 도움을 드릴 수 있을 것 같습니다.

도움이 필요하시면 언제든지 추가 질문해주세요.