본문 바로가기

전체 글

(231)
카프카 오프셋 커밋과 메시지 손실, DLT 프로젝트에서 카프카를 사용 중인데 처음 사용해보는거라 아직 모르는 부분이 많다. 카프카를 사용해보며 들었던 의문들을 정리해보고자 한다.자동 커밋 vs 수동 커밋카프카의 자동 커밋(auto commit) 기능을 사용하면, 메시지를 소비한 후 일정 주기마다 오프셋이 자동으로 커밋된다. 이 과정에서 메시지를 가져온 후 처리하는 과정에 예외가 발생하더라도, 이미 오프셋이 커밋되었기 때문에 해당 메시지를 다시 소비할 수 없는 문제가 발생한다. 예제를 통해 살펴보자. 다음은 카프카 설저어 코드와 리스너 코드이다.@EnableKafka@Configurationpublic class KafkaConsumerConfig { @Bean public ConsumerFactory consumerFactory() {..
Redis Stream을 메시지 브로커로 사용하기 0. 개요이 글은 프로젝트를 진행하며 메시지 브로커로 Redis Stream을 활용한 경험을 작성한 글이다. 메인 서버(가챠 서버)에서 사용자가 특정 등급의 아이템을 모두 획득한 경우, 로또를 발급해준다. 이때 로또 발급 로직을 별도의 프로세스로 진행하고자 로또 서버를 생성했다. 그리고 메시지 브로커로 두 서버 간 통신을 이뤄 비동기 통신을 구현하고자 했다. Kafka, RabbitMQ 등의 메시지 브로커가 있는데, 기존에 Redis를 사용 중이었기 때문에 Redis를 활용했다. Redis의 pub/sub과 stream을 메시지 브로커로 사용할 수 있다.1. Redis Stream일반적으로 레디스를 이용해 메시지를 발행할 때는 pub/sub을 많이 사용한다. 하지만 이 방식은 메시지를 발행했을 때 수신자..
구매 요청 동시성 제어하기 가챠가챠 프로젝트는 스프링 부트 서버와 MySQL만 사용 중이다. 따라서 프로젝트에서 마주했던 동시성 문제를 레디스나 다른 도구 없이 해결한 과정을 기록하고자 해당 글을 쓴다.0. 문제 상황사용자는 마켓에서 아이템을 구매할 수 있다. 이때 아이템 A를 판매하는 판매자가 n명이라면, 아이템 A의 수량은 n개가 된다. 구매자가 구매를 요청하면, 해당 아이템을 가장 처음에 등록한 판매자의 상품을 구매하게 된다. 예를 들어, 아이템 수량이 1개, 즉 판매자가 1명이고, 이를 구매하려는 구매자가 5명이라고 가정하자. user 테이블에는 다음과 같이 구매자 5명(user1~5), 판매자 1명(seller)가 저장되어 있다. 그리고 아직 거래가 이뤄지기 전이므로 6명의 coin 값은 초기 값인 20,000이다. 그리..
MDC(Mapped Diagnostics Context)를 사용하여 로그 추적하기 로깅이란로깅이란, 시스템이 동작할 때 시스템의 상태 및 동작 정보를 기록하는 것을 의미한다. 로깅을 통해 개발자는 개발 과정 또는 개발 후에 발생할 수 있는 예상치 못한 애플리케이션의 문제를 진단할 수 있고, 다양한 정보를 수집할 수 있다. 사용자 로그의 경우 분석 데이터로 활용할 수도 있다. 하지만 적절한 수준의 로그 기록 기준을 잡지 못하면 방대한 양의 로그 파일이 생성되는 문제를 겪거나, 의미 있는 로그를 쌓지 못하는 경우가 발생할 수 있다. 결국 효율적으로 로깅하는 방법을 이해하는 것이 중요하다.로깅 라이브러리로깅 관련 프레임워크는 대표적으로 log4j, logback, log4j2가 있고, 이들으르 통합해서 인터페이스로 제공하는 slf4j 라이브러리가 있다. 현재 log4j는 deprecated..
[백준] 5567. 결혼식 https://www.acmicpc.net/problem/55671. BFS로 푸는 방법import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.*;public class Main { static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); static StringTokenizer st; public static void main(String[] args) throws IOException { int n = Integer.parseInt(br.readLine..
다익스트라에서 방문처리를 하는 시점 https://www.acmicpc.net/problem/1753위 문제는 기본적인 다익스트라 문제이다. 그런데 다음과 같이 풀면 틀린다.import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.*;public class Main { static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); static StringTokenizer st; public static void main(String[] args) throws IOException { st = new..
분산 환경에서 데이터 일관성 확보하기 0. 개요프로젝트에서 PT 수업 예약 API를 개발하며 고려한 점들을 정리하고자 한다. PT 수업 예약 요청은 Pt 서버와 Auth 서버를 거치는 분산 환경에서 처리된다. 단일 서버에서 모든 로직을 수행한다면 구현이 간단하지만, 여러 서버를 거치게 되면 트랜잭션의 원자성 및 데이터 일관성을 유지하기 위해 다양한 상황을 고려해야 한다. 이 글은 분산 환경에서 어떤 것들을 고려했는지 그 고려 사항들을 정리한 글이다.1. 분산 환경에서 로컬 트랜잭션들 간 원자성 보장하기분산 환경에서의 원자성분산 환경에서는 여러 개의 로컬 트랜잭션들이 묶여 하나의 논리적인 트랜잭션을 구성한다. 그렇기 때문에 로컬 트랜잭션들이 순차적 또는 병렬로 실행되면서 원자성이 깨지는 문제가 발생할 수 있다. 예를 들어, 마이크로서비스 A..
Transactional Outbox Pattern을 이용한 분산 환경에서의 결과적 일관성 확보 문제 상황사용자 정보를 변경한 후 커밋되었지만 메시지가 발행되지 않는 경우메시지를 발행했지만 사용자명 변경 내역이 롤백된 경우다음과 같이 컨트롤러에서 userService를 호출해서 사용자 정보를 변경하여 DB에 커밋한 후 kafkaService를 호출해서 변경된 사용자 정보를 카프카 메시지로 발행한다고 가정하자.@RestController@RequiredArgsConstructorpublic class UserController { private final JwtUtils jwtUtils; private final UserService userService; private final KafkaService kafkaService; @PutMapping("/edit") publ..