가상화폐 모의투자 플랫폼 지향 웹 서비스 “FUNCO” (ssafy 우수 프로젝트 1등 수상)
실시간 가상화폐 시세로 다른 사람들과 함께 투자하며 즐기는 모의투자 서비스
다른 사람에게 투자하는 팔로윙 투자
짜릿한 100배 배율이 가능한 선물 거래
모두와 함께 즐기고 경쟁하는 랭킹 시스템
투자에 대해 소통하는 인사이트 게시판
나의 투자 통계를 보고싶어? 투자내역 및 통계
SPA React.js와 Monolithic Architecture Spring Boot Server로 1차 개발 완료 및 배포
➡️ 2차 개발 기간 동안 Next.js와 12개의 MSA Spring Boot Server로 전환 및 고도화 개발 및 배포
분류
기술 스택
BE
FE
Infra
협업도구
🌐 System Architecture (MSA)
랭킹
알림
포트폴리오 구매
투자노트
투자노트 상세보기 및 댓글
💡 회원은 Spring Security & JWT & Oauth2.0 사용하여 구글 소셜 로그인 구현
QueryDslItemReader를 활용하여 Chunk-oriented Processing으로 데이터를 처리하여 저장
매일 오전 6시에 전날의 거래 내역으로 일별 통계 내역을 생성하는 Job
체결 내역 테이블의 데이터를 누적 계산하여 도출된 손익을 임시 손익 테이블에 저장하는 Step
임시 손익 테이블의 데이터를 일별 통계 테이블에 저장하는 Step
매월 1일 자정에 전달의 일별 통계 내역으로 월별 통계 내역을 생성하는 Job 실행
전달의 일별 통계 테이블의 데이터를 누적 계산하여 월별 통계 테이블에 저장하는 Step
100여 개의 코인의 시세를 실시간 웹소켓으로 받아오는데 보유 및 관심 코인 리스트에서는 백여 개의 코인 시세를 실시간으로 받아올 필요가 없습니다
웹소켓을 모듈화 하여 다른 파일에서도 웹소켓의 send 요청을 보낼 수 있도록 했습니다
랭킹은 어쩔 수 없이 매번 총 자산과 총 팔로워 금액을 구해야하기 때문에 성능에 대한 고민이 있을 수 밖에 없었습니다.
실시간은 쿼리가 많이 발생하여 너무 서버에 부담이 갈 것 같아서 30분마다 스케줄링을 돌려 계산을 하고 계산한 값들은 레디스에 넣도록 했습니다.
조회가 많이 일어나기 때문에 redis 사용을 고려했습니다.
정렬 기능을 필요로 했기 때문에 레디스의 ZSet을 활용하여 정렬을 하였고 조회할 때마다 레디스에서 캐싱하여 보여주었습니다.
ZSet 연산은 O(log(n))으로 단순히 java의 timsort, Arrays.sort()의 평균 O(nlog(n))보다 훨씬 효율적입니다.
zrange의 시간복잡도는 O(log(n) + m(반환받는 멤버들의 개수))로 효율적으로 페이징 처리를 했습니다.
서버에서 실시간으로 등록된 예약 거래가 처리되어야 했다.
서버가 웹소켓 클라이언트가 돼서 실시간으로 메모리에 코인 시세들을 받아와 저장한다.
예약 거래를 동시성 처리를 위해 ConcurrentHashMap으로 관리했고 각 코인 별 매수, 매도 우선순위 큐를 사용해 시세를 감지하여 거래가 될 수 있는 데이터 또는 하나의 데이터만 확인하도록 O(1)로 구현했습니다.
성능 최적화를 위해 예약 거래에 등록된 코인의 시세 데이터만 유동적으로 받아오도록 웹소켓 메시지를 동적으로 처리했습니다.
핀테크 프로젝트 특성 상 정확한 소수점 연산을 다뤄야 함. 우리의 경우 정확한 코인 수량과 가격에 대한 정확하고 일관적인 연산 결과가 필요.
BigDecimal Utility class 를 만들어 전역으로 사용함으로써 일관적인 연산과 정확한 소수점 연산을 할 수 있게 됐다.
Offset 방식의 Pagination은 Offset 값이 커질수록 그만큼의 row를 읽어야하므로 성능저하가 일어납니다.
가상화폐 거래 사이트 특성상 무수히 많은 거래 내역이 저장 될 것이므로 Cursor Pagination을 사용하여 조회 성능을 최적화 하였습니다.
이러한 방식은 Batch의 ItemReader에도 적용하였습니다.
전날의 모든 거래 내역으로 일별 통계를 생성하는 Job에서 QueryDslNoOffsetItemReader를 사용하여 Offset 없이 Chunk 단위로 데이터를 읽어 프로세싱합니다.