TV쇼핑지원금 신규 API 서버 구축과 개발

Jsbae
CJ 온스타일 기술 블로그
6 min readFeb 19, 2024

안녕하세요. 플랫폼개발팀에서 회원서비스를 담당하는 배진섭입니다.

이번에 TV쇼핑지원금 개발 일지를 한 번 적어보려합니다.

TV쇼핑지원금에 대한 내용은 아래 링크를 참고해주세요!

이번 프로젝트에서 제가 진행했던 부분은 크게 2개 항목이었습니다.

  1. 신규 API 서버 구축
  2. API 개발

신규 서비스인만큼 새로운 API서버를 구축하기로 했고 API 개발과 함께 제가 담당하기로 했습니다.

API 서버 구축

새로운 API 서버는 Spring boot 2.7로 구성했습니다. 이미 Spring boot 3가 있었지만 적용에 몇 가지 애로사항이 있었습니다.

  • 사내 표준 프레임워크 사용의 어려움
  • 사내 레퍼런스 부족
  • Spring framewok6에 대한 지식 부족

사내 프레임워크는 Spring boot 2.x 까지 사용이 되고 있었고, 아직 3버전에 대한 호환성 검증 끝나지 않아서 버전 결정에 시간이 좀 걸렸습니다.

레퍼런스 부족과 지식 부족은 해결이 가능한 부분이었지만! 인증, 보안 등 각종 기능을 제공하는 사내 프레임워크를 활용 못하는 점은 문제가 될 수 있었기 때문에 향 후 마이그레이션을 하기로 결정 후 2.7 버전으로 진행하게 되었습니다.

구성은 금방 끝났습니다. 기존에 Spring boot 2.x 버전 프로젝트들이 많이 있어서 큰 어려움은 없었습니다.

API 개발

API는 크게 조회, 지급, 사용으로 구분지어 개발을 진행했습니다. 가장 기본적인 기능들이라 기능 자체에 대한 것 보단 개발 시 신경 썼던 부분을 이야기해보려합니다.

📚 TV쇼핑지원금 ‘조회' 에서 신경 쓴 점

조회에서 가장 신경 쓴 부분은 역시 성능이었습니다. 호출하는 곳이 마이존, 상품상세, 주문서, 백오피스 등 많이 사용되는 메뉴였기때문에 최대한 빠른 처리를 목표로 했습니다. 캐싱이 가능한 영역은 캐싱을 통해 성능개선을 진행했지만 잔액 같이 실시간 조회가 필요한 부분은 캐싱을 사용을 하지 않았습니다. 이 부분은 DB 인덱스와 쿼리 튜닝으로 해결을 했고, 아직 큰 문제가 발생하지 않았습니다.

향 후 데이터가 늘어나 조회가 느려진다면 상황에 맞는 방법을 고려해보려 합니다.

💰 TV쇼핑지원금 ‘지급' 에서 신경 쓴 점

지급에서도 성능을 신경썼습니다. 실시간 지급이 아닌 배치로 하는 지급이 대부분이었지만! 또 배치가 너무 길어지면 안되니까 신경을 써봤습니다. API는 다건 지급이 가능하도록 List로 받아서 처리하도록 했습니다. 그리고 사이즈가 많으면 병렬로 처리하도록 구현을 했습니다.

Stream<Point> pointStream;

if (pointSaveList.size() > PARALLEL_EXEC_SIZE) {
pointStream = pointSaveList.parallelStream();
} else {
pointStream = pointSaveList.stream();
}

실제로 70~100만건씩 지급이 되었을 때 큰 문제 없이 정상처리 되었습니다.

동시성에 대한 문제도 있지만 다행히(?) 아직까진 DB 조회를 통한 중복 검증에서 문제가 발생하지 않았습니다. 이 부분은 지속적으로 방법을 탐구 중입니다. MQ, Redis를 사용하는 방법을 고민하고 있습니다.

😎 TV쇼핑지원금 ‘사용' 에서 신경 쓴 점

사용 기능은 정말 모든 부분을 다 신경 쓴 항목입니다. 아무래도 돈과 관련되어있으니 사용자들이 민감한 부분이기도 하고, 데이터가 어긋나면 처리가 까다로운 부분이다보니 고민을 많이 했습니다. 사실 비즈니스가 복잡한 거지 시간을 잡아먹을 부분은 없어서 성능 쪽은 큰 문제가 없었습니다. 역시 중요한건 문제가 생기면 굉장히 머리가 아픈 데이터 정합성쪽이었습니다. 데이터 정합성을 위해 2가지를 구현했었습니다.

1. 사용 완료 후 상태값 확인 가능한 API

사용/사용취소 프로세스가 정상적으로 끝났는지 다시 한 번 확인 가능한 대사 API를 만들었습니다.

프로세스 마지막에 Redis에 상태값만 짧게 저장을 해놓고 대사 API에서 조회하도록 구현했습니다.

2. 주문 완료 여부 확인하기

주문 완료 여부를 확인하고 비정상이면 검증을 하고 사용 취소를 진행하는 기능을 만들었습니다.

이런 흐름으로 진행을 했습니다. 검증은 비동기로 진행을 했습니다.

@Async & Thread.sleep() vs ScheduledExecutorService

일정시간 대기를 위해 둘 중 고민했지만 ScheduledExecutorService를 이용하였습니다. 직접 Thread를 대기시키는것 보다 자바 패키지를 통해 컨트롤 해주는 것이 좀 더 안전하지 않을까 판단했습니다.

프로세스는 TV쇼핑지원금 사용완료 30초 후에 검증하는 것으로 했습니다.

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

executorService.schedule(() -> {

// 검증

}, 30, TimeUnit.SECONDS);

이 기능은 실제 운영에서 사용하지 않았습니다. 주문 서비스팀에서 사용하는 비정상 주문 처리에 관련 기능을 추가해서 운영하고 있습니다. 그래도 이런 부분을 고민했던 것 자체가 의미가 있다고 생각합니다.

✅ 테스트는 ?

API 단위로 성공/실패 케이스를 나눠서 테스트 했습니다. 좀 더 명확한 테스트를 위해 Jacoco를 이용해 테스트 커버리지 측정도 진행했습니다.

80%를 목표로!

✅ 부하 테스트는 ?

갓 태어난 신규 API 서버라서 트래픽에 대한 검증이 필요했습니다. 부하 테스트는 nGrinder를 사용해서 진행했습니다. 테스트는 가장 많이 사용 할 것으로 예상된 잔액조회 부분으로 진행했습니다!

깔끔

부하 테스트를 하며 WAS 메모리 사이즈가 적당한지, 혹시 메모리 누수는 없는지 DB 커넥션 Pool은 적당한지 등등을 확인했습니다.

(지원해주신 JeonYB님에게 언제나 감사드립니다.)

직접 API 서버까지 구축하면서 오너쉽도 생기고 사내 프레임워크에 대해서도 더 깊게 알게 되는 좋은 기회였다고 생각합니다.

연말에 때마침 재미있는 프로젝트를 진행하게 되어 한 해 마무리를 즐겁게 한 것 같습니다.

읽어주셔서 감사합니다.

--

--