/FunCo

가상화폐 모의투자 플랫폼 지향 웹 서비스 FunCo Main Repository ( next.js, MSA )

Primary LanguageJava

funco-logo

📢 Introduction

서비스 소개

  • 가상화폐 모의투자 플랫폼 지향 웹 서비스 “FUNCO” (ssafy 우수 프로젝트 1등 수상)
  • 실시간 가상화폐 시세로 다른 사람들과 함께 투자하며 즐기는 모의투자 서비스
  • 다른 사람에게 투자하는 팔로윙 투자
  • 짜릿한 100배 배율이 가능한 선물 거래
  • 모두와 함께 즐기고 경쟁하는 랭킹 시스템
  • 투자에 대해 소통하는 인사이트 게시판
  • 나의 투자 통계를 보고싶어? 투자내역 및 통계

📝 History

  • SPA React.js와 Monolithic Architecture Spring Boot Server로 1차 개발 완료 및 배포
  • ➡️ 2차 개발 기간 동안 Next.js와 12개의 MSA Spring Boot Server로 전환 및 고도화 개발 및 배포

🤝 Team Member

박세웅 [팀장, BE] 소재열 [CTO, BE, INFRA] 이선주 [BE] 이태호 [BE, INFRA] 엄소현 [FE, BE] 황주영 [FE]

🕊️ Deploy URL

🛠️ Skills

분류 기술 스택
BE Java SpringBoot Spring Data JPA Spring Security Spring Batch QueryDsl JWT OAuth
FE TypeScript React Recoil Vite Node.js npm
Infra AmazonEC2 Nginx Ubuntu Docker Jenkins MariaDB Redis Portainer
협업도구 GitLab Figma Mattermost Notion Gather


🌐 System Architecture (MSA)


💾 ERD



🏠 Service Layout

landing quote asking-price trade
메인 페이지 시세 호가 거래
landing Investment-details Investment-details follow
선물거래 투자내역 팔로우 원 초기화
ranking notification notification notification notification
랭킹 알림 포트폴리오 구매 투자노트 투자노트 상세보기 및 댓글


⚙️ Function

🎯 가상화폐 거래

  • 시간대 별 코인 시세 차트 조회
  • 실시간 코인 시세 조회 및 검색
  • 시장가(간편 거래) 매수, 매도
  • 지정가(예약 거래) 매수, 매도
  • 가상화폐 체결, 미체결 내역 조회
  • 거래 체결 시 알림
  • 관심 코인 추가, 조회, 삭제
  • 보유 코인 조회

🎯 선물 거래

  • 선물 거래 레버리지(배율) 설정
  • Long 거래
  • Short 거래
  • 자동 청산 및 정산 시스템
  • 선물 거래 내역

🎯 투자내역

  • 보유자산 목록 조회
  • 일별, 월별 투자 손익 조회
  • 기간/거래종류/자산종류 별 자산 변동 내역 조회
  • 팔로잉, 팔로워 투자 자산 조회
  • 팔로우 거래, 보유 내역 조회
  • 모든 가상화폐 미체결 거래 내역 조회

🎯 팔로우

  • 팔로우 시 자산 동기화
  • 팔로잉의 투자에 따라 자동 투자
  • 팔로우 정산 시 알림

🎯 랭킹

  • 정각 기준 1분 마다 랭킹 업데이트
  • 총 팔로워 금액에 따른 랭킹 조회
  • 총 자산에 따른 랭킹 조회

🎯 투자 인사이트 게시판

  • 코인 별 투자 게시판
  • 다양한 카테고리의 게시판 글쓰기 및 댓글

🎯 내 포트폴리오 판매

  • 내 투자내역 ( 포트폴리오 )을 비공개로 가격 설정하여 구독판매

🎯 회원

💡 회원은 Spring Security & JWT & Oauth2.0 사용하여 구글 소셜 로그인 구현

  • 회원 가입
  • 로그인, 로그아웃
  • 유저 투자 포트폴리오 조회
  • 닉네임 수정
  • 한줄 소개 수정

🎯 알림

  • 실시간 알림 및 알림 히스토리 조회
  • 투자 정산, 팔로우 정산, 선물 청산, 게시글 댓글, 답글 등 다양한 알림기능

⏰ Batch

  • QueryDslItemReader를 활용하여 Chunk-oriented Processing으로 데이터를 처리하여 저장
  • 매일 오전 6시에 전날의 거래 내역으로 일별 통계 내역을 생성하는 Job
    • 체결 내역 테이블의 데이터를 누적 계산하여 도출된 손익을 임시 손익 테이블에 저장하는 Step
    • 임시 손익 테이블의 데이터를 일별 통계 테이블에 저장하는 Step
  • 매월 1일 자정에 전달의 일별 통계 내역으로 월별 통계 내역을 생성하는 Job 실행
    • 전달의 일별 통계 테이블의 데이터를 누적 계산하여 월별 통계 테이블에 저장하는 Step

💪 Challenges

FrontEnd

  • 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 단위로 데이터를 읽어 프로세싱합니다.

고민한 문제들 등등 ( 자세한건 노션 )