- TEAM MEMBER
- DEPLOY URL
- SPECIFICATION
- INTRODUCTION
- SKILLS
- SYSTEM ARCHITECTURE
- ERD
- SERVICE LAYOUT
- FUNCTION
- CHALLENGES
박세웅 [팀장, BE, Infra] | 소재열 [CTO, BE] | 이선주 [BE] | 이태호 [BE] | 엄소현 [FE] | 황주영 [FE] |
- ✅ front-server : https://j10a404.p.ssafy.io
- ✅ back-server : https://j10a404.p.ssafy.io/api
- 팔로윙 투자가 가능한 가상화폐 모의 투자 서비스
- 팔로윙 투자 : 다른 사람에게 투자하고, 그 사람의 투자 내역과 동일하게 자동 투자되고 정산받을 수 있는 기능
분류 | 기술 스택 |
---|---|
BE | |
FE | |
Infra | |
협업도구 |
메인 페이지 | 시세 | 호가 | 거래 |
투자내역 | 팔로우 | 랭킹 | 알림 |
- 시간대 별 코인 시세 차트 조회
- 실시간 코인 시세 조회 및 검색
- 시장가(간편 거래) 매수, 매도
- 지정가(예약 거래) 매수, 매도
- 가상화폐 체결, 미체결 내역 조회
- 거래 체결 시 알림
- 관심 코인 추가, 조회, 삭제
- 보유 코인 조회
- 보유자산 목록 조회
- 일별, 월별 투자 손익 조회
- 기간/거래종류/자산종류 별 자산 변동 내역 조회
- 팔로잉, 팔로워 투자 자산 조회
- 팔로우 거래, 보유 내역 조회
- 모든 가상화폐 미체결 거래 내역 조회
- 팔로우 시 자산 동기화
- 팔로잉의 투자에 따라 자동 투자
- 팔로우 정산 시 알림
- 정각 기준 30분 마다 랭킹 업데이트
- 총 팔로워 금액에 따른 랭킹 조회
- 총 자산에 따른 랭킹 조회
💡 회원은 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 단위로 데이터를 읽어 프로세싱합니다.