전체 글 489

[부하테스트] 재고 API - (1) k6로 테스트 해보기

1. 가설 : 문제점 제기 가설 1 가설 2 2. 어떻게 테스트 해볼 수 있을까? -> 부하테스트 -> k6 테스트 : 왜 k6 ? 코드 구현k6는 크게 두 가지 방식으로 부하를 만들 수 있다. 💡Closed Model (vus / ramping-vus executor)이전 Iteration이 끝나야 다음 Iteration이 시작되는 모델(Iteration : Virtual User(VU)가 default() 함수를 한 번 처음부터 끝까지 실행하는 것을 의미)"The next iteration doesn't start until the previous one finishes."흐름 예시VU 1 -> HTTP 요청 -> 응답 대기 -> 응답 완료 -> 다음 요청 시작새로운 요청 시작 시점이 이전 요청이 ..

Projects/hub-eleven 2026.07.24

[부하테스트] 부하 테스트 란? (feat. k6)

중요한 개념💡 처리량 (Throughput)정의 : 단위 시간당 시스템이 처리하는 요청의 양지표 : 주로 TPS(Transactions Per Second)나 RPS(Requests Per Second)로 측정한다.의미 : 시스템이 얼마나 많은 일을 할 수 있는지 성능의 '양'을 나타낸다.💡 지연 시간 (Latency)정의 : 사용자가 요청을 보낸 시점부터 응답을 받을 때까지 걸리는 시간의미 : 사용자에게 얼마나 빠른 '경험'을 주는지 성능의 '질'을 나타낸다.💡 상관관계부하가 증가해도 일정 수준까지는 처리량이 늘어나지만, 임계치를 넘으면 지연 시간이 급격히 증가하고 처리량은 정체되거나 하락한다.부하 테스트 툴 선정 (k6)💡 K6 란?k6 백엔드 API나 웹 서비스에 가상의 사용자, 즉 Virt..

[동시성 처리] Redisson은 어떻게 Redis Pub/Sub을 이용해 재시도(Retry) 로직을 구현할 수 있을까?

Redis와 RedissonRedis는 메모리 기반 Key-Value NoSQL 데이터베이스이다.데이터를 메모리에 저장하기 때문에 매우 빠른 읽기/쓰기 성능을 제공하며 캐시, 세션 저장소, Pub/Sub, 분산 락 등에 자주 사용된다.Redisson은 Java 환경에서 Redis를 쉽게 사용할 수 있도록 제공하는 Client 라이브러리이다.Client 라이브러리란 애플리케이션과 외부 시스템 사이의 통신을 추상화하여 개발자가 쉽게 사용할 수 있도록 도와주는 라이브러리를 의미한다.예를 들어 개발자는lock.lock();만 호출하지만 실제로는 Redisson이 Redis 명령어를 생성하여 Redis 서버와 통신한다.Java Application ↓ Redisson ↓ Redis Co..

Projects/hub-eleven 2026.06.24

[트러블슈팅] Redisson 분산 락 적용 중 트랜잭션 커밋 순서 문제를 해결한 과정 (2)

추가 해결 사항💡 문제 상황Redisson 분산 락 적용 중 트랜잭션 커밋 순서 문제를 해결하는 과정에서 다수의 동시 요청이 하나의 재고 락에 몰리면서 일부 요청이 tryLock의 대기 시간 안에 락을 획득하지 못하는 상황이 발생했고, 이 요청들이 락 획득 실패 예외로 처리되어 동시성 테스트 통과가 이뤄지지 않는 문제가 발생했다.💡 문제 증상현재 tryLock(WAIT_TIME_SECONDS, LEASE_TIME_SECONDS, TimeUnit.SECONDS)에서 WAIT_TIME_SECONDS 동안 락 획득을 기다리지만, 그 시간 안에 락을 얻지 못하면 false를 반환한다.이를 곧바로 STOCK_LOCK_TIMEOUT 예외로 변환했기 때문에 일부 요청이 재시도 없이 실패 처리되어 동시성 테스트가..

Projects/hub-eleven 2026.06.23

[트러블슈팅] Redisson 분산 락 적용 중 트랜잭션 커밋 순서 문제를 해결한 과정 (1)

진행 환경💡진행 환경Java 17Spring Boot 3.5.7MySQL 8.0.44Gradle문제 상황💡 문제 상황 💡 문제 증상Redisson 분산락을 적용했지만, 100개의 동시 요청을 보냈을 때 재고가 기대값처럼 정확히 차감되지 않았다.테스트 기대값은 다음과 같다.초기 재고 : 100요청 수 : 100개요청당 차감 수량 : 1기대 결과 : 최종 재고 0실제 결과 : 최종 재고가 0이 아니거나, 일부 요청이 실패하는 동시성 문제가 발생원인 분석💡 원인 1 : 락 해제가 트랜잭션 커밋보다 먼저 일어난다. ❗️StockServiceImpl.java@Transactionalpublic StockResult decreaseStock(StockRequests.Decrease request) { ..

Projects/hub-eleven 2026.06.22

[동시성 처리] 재고 감소 락 추상화 및 Redisson 락 구현 (아키텍처 구조 보완 필요)

아키텍처 구조💡현재 프로젝트 구조 💡인터페이스 구현 구조application service ↓application port(interface) ↑infrastructure adapter(implementation)Redisson에 대한 직접 의존을 application service에서 분리하기 위해, application 계층에 port 인터페이스를 두고 infrastructure 계층에서 구현하도록 설계했다.(왜 인터페이스는 application 계층에 두고, 구현체는 infrastructure 에 두는 걸까?)아 어렵넹Lock 추상화 인터페이스 StockLockManager 구현 💡StockLockManager.javapackage com.hubEleven.stock.applicat..

Projects/hub-eleven 2026.06.02

[동시성 처리] RedissonClient Bean 설정 클래스 추가 (2) (리소스 보완 필요)

RedissonClient 리소스 💡RedissonClient 리소스 란?RedissonClient 리소스는 그 주소를 바탕으로 실제 통신을 처리하기 위해 내부에서 관리하는 것들을 말한다.공식 문서 기준으로 보면 RedissonClient는 Redisson 객체들에 접근하는 메인 인터페이스이다. (RedissonClient Javadoc)즉, RLock, RMap, RAtomicLong 같은 Redis 기반 객체를 가져오는 중심 진입점이다. 어려웡 💡대표 리소스 1. Redis 연결 풀 Redisson 설정 문서에는 connection pool 관련 설정이 있다. (Redisson Configuration - connection pool settings)connectionMinimumIdleSizec..

Projects/hub-eleven 2026.05.28

[동시성 처리] RedissonClient Bean 설정 클래스 추가 (1)

RedissonClient💡RedissonClient 란?Spring Boot 애플리케이션 ---> Redis 서버Java 애플리케이션에서 Redis/Valkey를 사용할 수 있게 해주는 Redisson의 핵심 클라이언트 객체즉, Java 코드와 Redis 중간에서 통신을 도와주는 객체✅ Redisson 의 핵심 '클라이언트' 객체 ?요청을 받는 쪽 = 서버요청을 보내는 쪽 = 클라이언트 💡예시Redis 서버→ 락 정보, 캐시 데이터 등을 저장하고 요청을 처리하는 쪽Spring Boot 애플리케이션→ Redis에 "락 잡아줘", "값 저장해줘", "값 조회해줘"라고 요청하는 쪽Spring Boot 안에서 Redis에 요청을 보내는 객체를 Redis client라고 부른다.RedissonClient..

Projects/hub-eleven 2026.05.27

[동시성 처리] 동시성 문제 (Race Conditon) 해결하기

동시성 문제 (Race Conditon) 발생💡StockCurrencyTest.java@ActiveProfiles("test")@SpringBootTestpublic class StockCurrencyTest { @Autowired private StockServiceImpl stockServiceImpl; @Autowired private JpaStockRepository jpaStockRepository; @Autowired private JpaProductRepository jpaProductRepository; private Product product; @BeforeEach void setUp() { product = ProductFixture.createDefault(); jpaProdu..

Projects/hub-eleven 2026.05.11

Codex Chat 삭제하는 방법 (MacOS)

Codex 저장 구조Codex는 로컬에 세션 파일을 저장한다.해당 파일을 앱 UI 내에서 삭제하는 기능은 아직 제공되지 않고 있기 때문에 로컬에 저장된 파일 경로로 직접 삭제해야한다.macOS 기본 경로는 다음과 같다.~/.codex/sessions~/.codex/archived_sessions해결 방법 : archived chat 직접 삭제하기💡Finder 로 삭제하기 1. Codex 앱에서 삭제할 chat을 Archive Chat 으로 옮긴다.2. Finder 를 연다.3. ⌘ + Shift + G를 누른다.4. 아래 경로로 이동한다.~/.codex/archived_sessions/ 5. 삭제할 archived session 파일을 휴지통으로 이동한다. 💡Terminal 로 삭제하기 1. Code..

Tips ✨ 2026.05.06