2025 스프링 캠프(KSUG) 갔다 옴

꺄악 운석이다·2025년 6월 29일
0

https://springcamp.ksug.org/2025/

이번년도에도 돌아온 스프링 캠프를 갔다 왔습니다.

그래서 작성하는 정리

난 Spring에서 ML서빙을 해봤어요

파이썬이 ML에 특화되어 있으나 파이썬 특성상 GIL으로 인해 병렬처리가 안된다는 단점이 있고 라이브러리 호환성 맞추기가 생각보다 어렵다는 문제점으로 JVM을 활용해 ML을 서빙했다는 내용이었다.

JVM에도 ONNX, TensorFlow, DJL... 등 사용할 수 있는 ML 라이브러리를 통해 구현을 했는데

DJL은 ML에 대해 지식이 없어도 활용이 쉽고, 허깅 페이스를 통해 다양한 모델들을 선택할 수 있으나, 하드웨어를 극한까지 끌어써야 하는 ML 에서 튜닝이 어렵다는 단점이 있어 TensorFlow를 활용했다고 한다.

지금까지 ML하면 파이썬으로만 가능할 줄 알았는데 JVM에서 ML을 사용할 수 있다는 사실을 처음 알았다.
오히려 JVM으로 하면 병렬 처리 같은 이점이 있다는 사실이 신기했었고, 생각보다 간단하게(DJL) 적용이 가능해서 사이드 프로젝트할 때 시도해볼 법하다는 생각이 들었다.

올리브영 물류 시스템 개선기

올리브영에서 물류 시스템 개선을 어떻게 했는지에 대한 내용이었다.

기존에는 입출고 주문이 들어오면 배치를 통해 물류센터로 입고 주문을 날리는 형식이었으나 배치 특성상 일정 주기마다 작동되는 방식이라 시간이 늦어져 발생하는 문제가 있었다 했다. (시간 지연으로 입고 포기, 실시간으로 데이터 동기화가 안되는 등...)

이를 해결하기 위해 입고 주문 발생 시 카프카를 활용하여 실시간성을 확보하고 만약 카프카에서 예외가 발생하면 DLQ를 구현하여 재처리 프로세스를 구축했다고 했다.

두번째로 오프라인 재고 조회 개선기에 대한 내용이었는데

기존에는 오라클 DB 하나만을 여러 서비스가 바라보고 있어 부하가 발생했다고 한다.
이를 해결하기 위해 Redis를 통해 읽기 DB를 분리하여 부하를 분산 시켰고 Redis를 활용하여 발생한 문제를 어떻게 해결했는지에 대해서도 설명을 해주었다.

Redis를 활용하면서 발생한 문제

  1. 재고 조회/수정 시 동시성 이슈
    • Redisson으로 분산락 처리
  2. 조회 성능 이슈
    • 단건 조회의 경우 Redis가 빠르나 여러건 조회의 경우 Redis SCAN기반 패턴 탐색으로 속도가 느림
    • 이를 해결하기 위해 레디스 데이터 셋을 분리하여 단건 조회용/여러 건 조회용/역인덱스 조회용 으로 분리했다고 한다.
  3. Redis 사망
    • 서킷 브레이커를 통해 레디스 오류 시 오라클DB를 바라보도록 설계

카프카를 사용했다는 점에서 신기함 + 그렇다면 정확히 어떻게 사용을 했는가? 에 대해 의문이 들었다. (카프카 토픽은 어떻게 정의를 했고(지점마다 하나의 토픽을 쓴건지 아니면 지점명 + 물품명으로 토픽을 지정했는지) 순서 보장은 어떻게 했는지 등...)

그리고 레디스면 메모리 기반이라 단순히 빠를 줄만 알았는데 여러 건 조회 시에는 오히려 불리할 수 있겠구나라는 사실을 알게 되었다.

실전! MSA 트랜잭션 개발 가이드

MSA

  • 시스템을 여러개로 독립적으로 분할
  • 이유는 여러 팀이 독립적으로 일하도록 분리

가장 중요한거는 다른 테이블에 액서스 하면 안된다.(테이블 변경 시 파급력이 매우 커진다.)

서비스간 트랜잭션 보장은 어떻게?

  • 2PC(Two Phase Commit) 는 사용 안하는게 낫다
  • 여러 서비스에 걸친 쓰기는 트랜잭션 보장이 안됨
    - DB 롤백, Uncommited read 로 독립성이 떨어짐

데이터 오너십 원칙

  • 테이블 직접 조인 < DAO 호출 < 서비스 호출 순으로 모듈화 수준이 높아진다.
  • 오너십을 가진 서비스만 데이터를 써야 한다. 여러 서비스가 접근하면 안된다.
    - A서비스에서 A데이터를 변경할 수 있는 서비스는 A서비스가 유일해야 한다.
  • 데이터의 주인(?)을 나누는 방법 : 테이블을 나눌 때 속성으로 나누거나 레코드로 나누거나

실패한 트랜잭션 처리 방법

만약 B에서 오류나면 완벽하게 롤백이 안된다.

  • 여러개의 트랜젹션의 경우 보상 트랜잭션/재시도를 구현해야 한다.

Pivot Transaction

  • 트랜잭션 중 에러가 발생했을 때 재시도를 취소할지 말지를 결정
  • Pivot를 기준으로 성공/실패를 가른다.
    - 만약 WriteB에서 예외가 발생하면 재시도, WriteA에서 예외가 발생하면 롤백

트랜잭션 격리성 보완

  • MSA를 하면 Read Uncommited로 수준이 떨어짐
    • 변경 중인 데이터를 다른 트랜잭션이 보게 된다.
    • 변경중인 데이터를 후행 트랜잭션이 고칠 수 있게 된다.

보통은 문제가 잘 안되지만 변경중인 데이터를 다른 트랜잭션이 덮어쓰면 문제가 커진다.

제어 방법

  • semantic lock : 업무적인 의미를 추가(예매 중인 좌석에 대해 표현 가능하도록 한다든가)
  • tcc
  • offline lock
  • select for update 를 통해 select 를 할 때 락을 잡음
    • 커밋 되면 락 해제
    • 신뢰할 수 있는 락 해제
  • 트랜잭션 아웃박스 패턴
    • 주의점 : 멱등성 주의

Talk3 - 기술 Talk

여러 연사 분들이 나누어서 여러 기술적인 질문들에 대해 이야기를 나누는 시간이었다.

그 중 가장 인상깊었던 것은 JPA엔티티와 도메인 객체를 나누는 것이 좋은지에 대한 이야기였다.

이 질문에 대해 연사 분들은 설계에는 좋고 나쁨이 없다. 상황에 따라 나누면 좋다 이야기를 해주셨다.(DB 스키마가 자주 바뀌거나 레거시한 경우, DB스키마와 도메인 객체 변경 타이밍이 다른 경우...에는 나누는 것이 좋다 예시를 들어주셨다.)
다만 프로젝트 초기부터 나누지 말고 상황을 봐서 나누는 것이 좋다 이야기를 해주셨다.

이에 더불어 확장성과 오버엔지니어링의 경계에 대해서도 이야기가 나왔다.
확장성 있는 설계를 하는 이유는 변경을 최소화 하기 위해 하는 것인데, 너무 미래를 예언해서 설계를 하기보단 현재 상황의 요구사항에 집중해서 설계를 하는게 좋고, 변화에 열려있는 태도를 가지는게 좋다고 해주셨다.

개발 경력이 길지는 않으나, 프로젝트를 진행하면서 프로젝트의 설계를 좋게 하고 싶은 마음 vs 너무 과한거 아닌가(+ 귀찮음) 이 두 개의 생각을 자주 했었다.
그리고 지금까지의 프로젝트를 생각해보면 프로젝트의 방향이 내 예상에 적중한 적이 없었다(...)

그래서 패널톡에서 한 이야기처럼 현재의 요구사항에 맞추어 설계를 하되, 앞으로의 변화를 적극적으로 반영하는 태도를 가지는게 좋은 균형점이라는 생각을 가지게 되었다. (+ 변화가 필요할 때 빠르게 결단을 내려야 한다는 것도)

profile
멸종은 면하자

0개의 댓글