- 가상화폐 모의투자 플랫폼 지향 웹 서비스 “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 단위로 데이터를 읽어 프로세싱합니다.