JSCODE Logo
프로그래밍 과외블로그후기멘토진
회사명 : JSCODE대표 : 박재성사업자 등록번호 : 244-22-01557통신판매업 : 제 2023-인천미추홀-0381 호
학원 명칭 : 제이에스코드(JSCODE)원격학원학원설립ㆍ운영 등록번호 : 제6063호

서울특별시 구로구 경인로 20가길 11(오류동, 아델리아)

Copyright ⓒ 2025 JSCODE - 최상위 현업 개발자들의 프로그래밍 교육 All rights reserved.

이용약관개인정보처리방침
← 블로그 목록으로 돌아가기

[실습] 재고를 차감할 때 동시성 이슈로 인한 오차가 발생하지 않도록 만들기 - 3

JSCODE 박재성
JSCODE 박재성
2026-01-12
author
JSCODE 박재성
category
Redis
createdAt
Jan 12, 2026
series
비전공자도 이해할 수 있는 Redis 중급/실전
slug
prevent-concurrency-issues-in-stock-deduction-part-3
type
post
updatedAt
Jan 12, 2026 12:17 AM
👨🏻‍🏫
이번 강의에서는 Redis로 Lock을 구현해 동시성 이슈를 해결해보자.

✅ 문제 해결

  1. 코드 작성하기
    1. StockLockService
      @Component @RequiredArgsConstructor public class StockLockService { private final RedisTemplate<String, String> redisTemplate; private final StockService stockService; public void decrease(Long id) throws InterruptedException { // Redis 명령어에서 'SET [key] [value] NX EX [seconds]'와 동일 // key : stock_lock:{id} // value : lock // timeout : 3초 (락을 획득하고 3초 뒤에는 자동으로 소멸 -> 데드락 방지) String key = "stock_lock:" + id; // 락 획득 시도 (락 획득에 실패하면 100ms 대기 후 재시도) while (!tryLock(key)) { Thread.sleep(100); } try { stockService.decrease(id); } finally { // 락 해제 redisTemplate.delete(key); } } // 락 획득 시도 (성공시 true, 실패시 false를 return) // (Redis 명령어에서 'SET [key] [value] NX EX [seconds]'와 동일) // (key : stock_lock:{id}) // (value : lock) // (timeout : 3초 => 락을 획득하고 3초 뒤에는 자동으로 소멸함으로써 데드락 방지) private boolean tryLock(String key) { return redisTemplate .opsForValue() .setIfAbsent(key, "lock", Duration.ofMillis(3_000)); } }
       
      StockController
      @RestController @RequestMapping("/stocks") @RequiredArgsConstructor public class StockController { private final StockService stockService; private final StockLockService stockLockService; ... @PostMapping("/{id}/decrease/redis") public void decreaseWithRedis( @PathVariable Long id ) throws InterruptedException { stockLockService.decrease(id); } }
       
  1. 서버 실행시키기
    1. notion image
       
  1. 테스트를 위해 DB에 데이터 넣어주기
    1. notion image
       
  1. 부하 테스트 스크립트 살펴보기
    1. scripts/script_2-2.js
      import http from 'k6/http'; import { check, sleep } from 'k6'; export const options = { // 가상 유저(VUs) 100명으로 설정 vus: 100, // 테스트를 10초 동안 진행 duration: '10s', }; export default function () { // 재고 차감 API const url = 'http://localhost:8080/stocks/1/decrease/redis'; const params = { headers: { 'Content-Type': 'application/json', }, }; // POST 요청 전송 const res = http.post(url, null, params); // 1초 간격으로 요청 발송 sleep(1); // 응답 상태 코드 확인 (200 OK가 왔는 지 체크) check(res, { 'status is 200': (r) => r.status === 200, }); }
       
  1. 부하테스트 진행하기
    1. $ k6 run scripts/script_2-2.js
      notion image
      notion image
      들어오는 요청을 병렬적으로 처리하던 걸 Redis의 Lock을 활용해 순서대로 차례차례 처리하게 만들어서 기존에 성능보다 TPS가 떨어지긴 했다. 하지만 재고 차감 요청의 횟수(636회)에 맞게 오차 없이 정확하게 재고가 차감됐다. 즉, Redis로 Lock을 구현해 동시성 이슈를 해결했다.
 
author
category
Redis
createdAt
Jan 12, 2026
series
비전공자도 이해할 수 있는 Redis 중급/실전
slug
type
series-footer
updatedAt
Jan 12, 2026 12:26 AM
📎
이 글은 비전공자도 이해할 수 있는 Redis 중급/실전 강의의 수업 자료 중 일부입니다.