| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- MVC
- string
- 디스크i/o
- 이벤트핸들러this
- 공통기술
- springsecurity
- 커뮤니티서버
- index
- 문제선택근거
- Ajax
- SpringLegacy
- Transaction
- DDD
- SEQUENCE
- 냄새라도
- 클린아키텍처
- model
- AOP
- 사면초가
- JDBC
- TDD
- OOP
- 설정세팅
- 공통규약
- 이벤트핸들러등록
- MVC요청플로우
- 전전긍긍
- 단위테스트
- JPA
- 로그백
- Today
- Total
개발이군고구마
[Redis/Kafka 이용한 대용량 트래픽 예약 및 쿠폰 발급 서비스] 2.대용량 트래픽을 견디기 위한 방법 고민 본문
[Redis/Kafka 이용한 대용량 트래픽 예약 및 쿠폰 발급 서비스] 2.대용량 트래픽을 견디기 위한 방법 고민
김구황 2025. 3. 24. 07:41[Redis/Kafka 이용한 대용량 트래픽 예약 및 쿠폰 발급 서비스] 2.대용량 트래픽을 견디기 위한 방법
🥑 카프카를 사용하는 이유 [성능]
medium.com
서울 우먼 잇츠 스터디 3기 연구자료
🥑 카프카를 사용하는 이유 [성능]
1. 문제 상황
- 예약이 완료된 이후 비동기 처리 작업이 상당 수 존재함
- 해당 비동기 작업들은 클라이언트에게 바로 응답 불필요
- 비동기 처리 작업들에서 오류가 생기면, 같은 트랜잭션에 묶인 메인 로직에 영향을 미쳐, 정작 중요한 핵심 프로세스가 수행이 되지 않음
2. 어떤 해결 방법들이 있을까
✔️ RabbitMQ : AMQP 프로토콜 구현 메시지 브로커
- Exchange의 과정이 존재
- 브로커 중심적인 설계 (= 수신인에게 메세지를 확인, 라우팅, 저장 배달 역할 초점)
- Consumer가 메세지를 소비하면 메세지를 삭제함
✔️ ActiveMQ : 자바로 만든 오픈 소스 메시지 브로커
- 적은 수준의 메세지만 처리
- 신뢰성 거래성 확보, 즉시 ETL 작업
✔️ Kafka
- 분산 메세징 시스템
- 메세지를 파일 시스템에 저장하여 영속성 보장
- Consumer가 broker로부터 ‘직접’ 메세지를 가지고 옴 pull
- Producer 중심 형태로 ‘많은 양’의 데이터를 파티셔닝 하는데 초점
- Consumer가 전달 상태를 기억
❔ 브로커란?
- Publisher로 부터 전달 받은 메세지를 Subscriber로 전달해주는 중간 역할.
- 'Message Queue' : 메세지가 적재되는 공간
- 'Topic' : 메세지의 그룹
❔ MQ의 장점?
- 비동기 : QUEUE 라는 임시 저장소가 있어 나중에 처리가 가능
- 낮은 결합도
- 확장성 : PRODUCDER/CONSUMER 서비스를 원하는대로 확장 가능
- 탄력성 : CONSUMER가 다운되도 어플리케이션이 중단되지 않으며, 메세지는 MQ에 존재
- 보장성 : MQ 에 들어가는 모든 메세지는 CONSUMER 에게 전달

3. 그 중 왜 카프카인가
✔️내가 구현한 시스템을 살펴보자
- 들어온 예약 데이터는 중요한 데이터이므로, consumer가 소비를 실패했다고 해서 삭제되면 안됨
- 데이터의 ETL은 크게 필요 없음
- ‘비동기’의 초점을 맞추고 있으며, 대용량 트래픽을 대비해야 함
4. 카프카 원리
✔️ 카프카 동작 원리

- publisher는 전달하고자 하는 메세지를 topic을 통해 카테고리화 함
- consumer는 원하는 topic을 ‘구독’ 함으로써 메세지를 읽어옴
- publisher와 consumer는 오로지 topic 정보만 알 뿐, 서로의 정보를 모름
- consumer 추가 제거시 consumer들의 partition 재분배가 발생
- kafka는 broker들이 하나의 클러스터로 구성되어 동작
- zookeeper가 분산 처리를 담당함
✔️ 용어
- 주키퍼 : 분산 시스템의 메타 정보를 관리. 분산 어플리케이션을 분산 조율, 조정하는 서비스
- 토픽과 파티션 : 토픽은 발행된 메세지의 카테고리 명. 토픽은 partition이라는 단위로 쪼개어져 클러스터의 각 서버들에 분산 저장되어 있음.

- pub/sub 모델 : topic을 구독하는 모든 consumer에게 메세지를 브로드캐스팅 하는 방식
✔️ 장점
- 분산 시스템 & 실시간 로그 처리 : TPS 가 매우 우수함. 분산 및 복제 구성 쉽게 할 수 있음
- TCP 기반 프로토콜 & 메세지 전달 방식 개선 : 다수의 메세지를 ‘배치’ 형태로 broker에게 ‘한번에’ 전달할 수 있어, TCP/IP 라운드 트립 횟수를 줄일 수 있음
- 메세지 파일 시스템 저장 방식 : 메세지를 메모리에 저장하는 시스템과 달리 ‘파일’ 시스템에 저장. 데이터의 영속성이 보장됨. Consumer 에 의해 처리된 메세지가 바로 삭제되지 않고, 파일 시스템에 ‘그대로’ 두었다가 수명이 지나면 삭제함
- 메세지 pull 방식 : consumer가 직접 broker로부터 메세지를 pull하여 최적의 성능 보장
5. 카프카 기업 사용 예시
🥑레디스를 사용하는 이유 [DISK I/O]
1. 문제 상황
- 예약 요청 건 별로 호스트에 대한 예약 재고를 확인해야함
- 트래픽이 몰리는 경우, 계속된 디스크 I/O를 통해 병목 현상이 발생할 수 있음
- 데이터 서버의 CPU 과부화가 예상되기도 함
2. 어떤 해결 방법들이 있을까
✔️ 인메모리 캐싱
- @Caheable : Spring 에서 사용하며, 메소드의 결과가 캐싱됨. Id 값으로 구별
- EhCache : Spring에서 제공하는 자바 기반 오픈소스 캐시 라이브러리.

✔️ 네트워크 캐싱
- CDN : 네트워크의 엣지에서 정적 에셋 파일을 캐싱하여 엔드 유저에게 빠르게 도달시키는 방법. 콘텐츠 전송 시 서버 로드를 줄여줌

✔️ 분산 캐싱 (여러 서버에 걸쳐 데이터를 메모리에 저장하는 방식)
- Redis : 다양한 데이터 구조를 지원 (리스트, 해시, 집합 등). 데이터의 영속성을 제공하며 Pub/Sub 및 트랜잭션 지원 (=메세지 브로커 역할 가능). 싱글 스레드 기반이며 메모리 사용량이 상대적으로 높음
- Memcached : 문자열 기반 키-값 저장소로 데이터 베이스 부하를 줄일 수 있음. 멀티스레드 지원. 빠르고 단순한 캐싱
✔️ 리버스 프록시 캐싱
- 클라이언트로부터 전달 받은 요청을 인터셉트하여 서버에 보내고, 리턴한 값을 저장함. 대표적인 예로는 Ngnix 웹서버
✔️ 클라이언트 캐싱
- 브라우저 캐시 : Etag, Cache-Control의 속성을 활용하여 이전에 한번 불러왔던 데이터들을 브라우저 내에 저장시키는 방법
3. 그 중 왜 레디스인가
✔️내가 구현한 시스템을 살펴보자
- 인 메모리 캐시 사용 ? 재고 데이터는 큰 데이터는 아니기 때문에 적절할 수 있음. 그러나 대용량으로 요청이 올 땐 WAS의 힙 메모리 차지가 클 수 있다는 단점이 존재함
- DB 분산 부하가 주된 목적이기 때문에 분산 캐시에 초점을 두고 있음
- 재고 데이터는 휘발 되서는 안되는 데이터이기 때문에, 읽기 전략 Look Aside 와 쓰기 전략을 적절히 혼합하여 사용해야 함
4. 레디스 원리
💥 분산데이터 ? 데이터 정합성 문제 발생할 수 있음
✔️ 캐시 히트
✔ 읽기 전략
- Look Aside (캐시 조회 -> (없을 경우) DB 조회 해서 값 가져옴 -> 캐시 업데이트)
- Read Through (캐시 조회 -> (없을 경우) DB 조회 -> 캐시가 DB 조회 후 업데이트 -> 캐시에서 값 가져옴)
✔ 쓰기 전략
- Write Back (모든 데이터를 Cache Store 에 저장 -> 일정 시간이 지난 후 DB 저장)
- Write Through (DB 저장 내용 Cache 저장 -> DB 로 저장)
- Write Around (모든 데이터는 DB 에 저장 -> Cache miss 가 발생하는 경우만 DB 와 캐시에 데이터 저장)
✔ 읽기 쓰기 전략 조합
- Look Aside + Write Around
캐시를 조회하고 없으면 DB 조회 후 캐시 업데이트
쓸 때는 DB에만 데이터 저장하고, cache miss 나는 경우만 cache 저장
- Read Through + Write Around
- Read Through + Write Through
💥 Redis 사용시 캐시 히트 문제는 3장에서 다시 자세히 다루어야 하는 문제임
5. 레디스 기업 사용 예시
🥑레디슨을 사용하는 이유 [동시성과 데이터 정합성]
1. 문제 상황
- 여러 요청이 한 자원을 공유 할 때 각 분산 DB의 동기화가 여러 요청의 동기화 속도를 따라가지 못하는 상황 발생 (즉, 재고의 수량이 업데이트 되기 이전에 다른 스레드가 재고를 조회하는 상황)
- Redis를 사용하여 재고를 확인할 예정이므로, 싱글 스레드의 특성을 사용할 수 있음 (이 장점을 사용할 방법)
2. 어떤 해결 방법들이 있을까
✔️ @Transactional
스터디 발표 중 스터디원이 아주 좋은 질문을 주셨다.
“@Transactional 을 쓰는 것으로 락 문제를 해결할 수 없을까?”

- Transactional을 사용하면 ‘프록시’ 객체를 사용하여 DB 접근시 락을 얻는데, 문제 상황은 재고 조회를 동시에 하는 것에서 발생 (조회에는 따로 락이 걸리지 않음)
- 락이 풀리고 그 다음 스레드가 다시 락을 얻은 후에, ‘같은 값’ 으로 update (=재고 차감 x) ❓ 롤백되는 건지 update 되는 건지
- JPA 의 경우 비관적인 LOCK(읽기 잠금, 공유 잠금) 을 트랜잭션과 함께 설정함으로써 해결할 수 있음
“@Transactional 사용시 스레드는 언제 락을 얻는 걸까? 서비스 실행 시점? 아니면 repository 접근 시점?”

- 트랜잭션 시작 후 DB 접근 시점에 획득함
✔️ DB Lock
- 공유 자원에 락을 걸음 (레코드)
- DB 데이터 자체에 Lock을 설정하는 쿼리 (JPA) DB Connection 비용과 Disk I/O 발생
- 공유 Lock : 데이터를 변경하지 않는 읽기 작업을 위해 잠금
- 배타 Lock : 데이터를 변경하는 작업을 위해 잠금
✔ 비관적 Lock
- 충돌은 무조건 발생한다 라는 전제
- @Lock 어노테이션을 사용하여 구현 가능
- 데드락에서는 벗어날 수 있으나, API 콜 대기 시간이 길어짐 (배타락 점유 시간 )
✔ 낙관적 Lock

- 충돌은 거의 발생하지 않는다는 전제
- 어떤 데이터도 락을 걸지 않기 때문에 데드락은 발생하지 않음
- 버전 충돌로 인해 트랜잭션이 롤백될 가능성
✔️ (분산락) Redisson
- 임계 구역에 락을 걸음
- pub/sub 방식으로 동작
- 간단한 Redis 명령어로 사용할 수 있음
- 실제로 작업을 처리하는 부분이 ‘싱글 스레드’ 로 동작하여 원자성 보장
- 분산 환경 (여러 서버에서 요청) 에서의 동시성 제어가 가능 (!= synchronized)
- 스케일 아웃된 DB 환경에서도 동시성 제어가 가능함
💥 DB 락 오류 정리
- 데드락 : 격리 수준에 따라서 트랜잭션 select 쿼리로 조회하는 경우 레코드에 공유 락을 획득한 후, 함께 점유한 레코드에 대해서 배타락 (update)를 요청할 때 벌어지는 현상

- 교착상태 : Lock 간의 경합이 발생하여 특정 트랜잭션이 작업을 진행하지 못하고 대기하는 상태 (예, commit 하지 않은 상태에서 다른 작업에서 무한 대기)

3. 그 중 왜 레디슨인가
✔️내가 구현한 시스템을 살펴보자

- 공유 자원을 레디스에 올려둘 예정임 -> Redis 서버를 사용 가능
- 분산락의 관리자가 Redis가 되면서 MSA 환경에서도 동시성 이슈 제어가 가능함
- 요청마다 락을 점유하고 데이터를 업데이트 하기 때문에 DB의 동기화를 기다리지 않아도 됨
🚫 주의
트랜잭션이 나중에 락 반납 이후에 반납 되면 동시성 이슈 생김. 트랜잭션 내부에서 분산락 반납하지 않도록 주의. 즉, [락 획득 → 트랜잭션 시작 → 트랜잭션 종료 → 락 해제] 순으로 실행해야 함
4. 레디슨 원리
- 메소드 블록을 Lock을 잡아줌
- 레코드에 락을 걸어서 다른 로직들에게 대기를 걸게 됨
- 락이 해제되면 해당 락을 subscribe 중인 클라이언트들이 신호를 받고 락에 진입할 수 있음
5. 레디슨 기업 사용 예시
🌿 참고 문헌
카프카
- https://dev-youngjun.tistory.com/259 (카프카 기본 세팅)
- https://velog.io/@cho876/%EC%B9%B4%ED%94%84%EC%B9%B4kafka-vs-RabbitMQ (카프카 비교)
- https://always-kimkim.tistory.com/entry/kafka101-broker https://heodolf.tistory.com/49 (개념)
레디스
- https://sabarada.tistory.com/178 (레디스 스프링)
- https://inpa.tistory.com/entry/REDIS-📚-캐시Cache-설계-전략-지침-총정리 (캐싱 전략)
- https://velog.io/@ksk0605/요즘-Redis-안하면-신입이-취업을-어케함-ㅋㅋ (레디스 기본 원리)
- https://escapefromcoding.tistory.com/704 (레디스와 memcached 비교)
- https://yozm.wishket.com/magazine/detail/2341/ (캐싱 방법 비교 정리)
레디슨
- https://velog.io/@hgs-study/redisson-distributed-lock (분산락 동시제어)
- https://gengminy.tistory.com/59 (개념)
- https://devoong2.tistory.com/entry/Spring-Redisson-라이브러리를-이용한-Distribute-Lock-동시성-처리-2 (분산락 구현예)
동시성
- https://velog.io/@jhkim31/%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-%EB%B6%84%EC%82%B0%EB%9D%BD%EA%B3%BC-Transactional (트랜잭션과 분산락 로직)
- https://ksh-coding.tistory.com/121 (DB 락)
- https://velog.io/@dangddoong/learning-solutions-concurrency-issues-e-commerce-inventory-management-logic (분산락 DB락)
- https://meorimori.tistory.com/156 (락 비교)
- https://oneny.tistory.com/113
대량 트래픽
- https://guti-coding.tistory.com/197?category=1195671
'SERVER > Kafka' 카테고리의 다른 글
| [Kafka/Redis] Kafka 설치 (0) | 2026.02.18 |
|---|---|
| [Kafka/Redis] Kafka 개념 (0) | 2026.02.03 |
| [Redis/Kafka 이용한 대용량 트래픽 예약 및 쿠폰 발급 서비스] 3. Kafka와 Redis로 동시성, 대량 트래픽 제어 (0) | 2025.03.24 |
| [Redis/Kafka 이용한 대용량 트래픽 예약 및 쿠폰 발급 서비스] 1.멀티 스레드의 동시성을 고려하지 못한 기존 구조 (0) | 2025.03.02 |
| [Kafka] 왜 카프카 인가 (0) | 2025.02.02 |