떡상하라 무시코인 개발 후기

황씨·2022년 2월 13일
2
post-thumbnail

후기에 앞서 무시코인에 대해 설명이 필요할 듯 합니다. 무시코인은 유튜브 콘텐츠인 ‘우정리 노트’에 나오는 이벤트입니다. 동물의 숲의 무처럼 사용자는 시간대 별로 가격이 달라지는 무시를 사고 팔며 시세 차익을 통해 재화를 벌 수 있는 메커니즘이지요.

저는 한동안 우정리 노트에 푹 빠져 살았는데 그러는동안 문득 재미있는 것을 만들고 싶다는 생각이 들어 무시코인을 웹 사이트로 만드는 미니 프로젝트를 기획하게 되었습니다. 회사에서 C#을 주로 사용하기 때문에 Java를 공부 해보고자 Spring Framework를 사용하여 프로젝트를 준비 했습니다.

✔️ 목표

  • 일단 재밌는 것을 만들어 보자.

✔️ 사용한 기술

  • Server : Apache Tomcat 9.0
  • DBMS : MySQL
  • Language : Java, Servlet/JSP, HTML, CSS, JavaScript
  • Framework/Libray : Spring, MyBatis, Bootstarp, JQuery, Ajax

✔️ 요구 사항

  • Spring Scheduler를 이용하여 1시간 마다 한 번씩 무시의 퍼센트가 랜덤하게 바뀌도록 한다.
    무시 가격 = 이전 무시 가격 + (이전 무시가격 * 무시 퍼센트)
  • Cookie에 사용자 ID, 소지금, 무시의 개수가 저장되도록 한다.
  • 하루 최대 구매량을 50개로 제한하고 자정이 지나면 구매 개수를 초기화 하도록 한다.

✔️ DB 설계



✔️ 페이지 구성


📢 화면 설명

  • 카운트 다운 타이머와 무시코인 진행 회차를 알 수 있는 메인 페이지입니다.
  • header에서 소지 중인 재화를 확인할 수 있습니다.
  • 최초 접속 시 기본 소지금 10,000원이 지급됩니다.

📢 화면 설명

  • 현재 코인의 가격을 확인하고 구매, 판매, 재시작을 할 수 있는 페이지입니다.
  • 가격이 내려갔을 때 과다 구매할 수 없도록 하루 구매 개수 제한을 50개로 두었습니다.


콘텐츠에 등장하는 귀여운 캐릭터들의 도트를 찍었습니다.
페이지의 전체적인 디자인은 00년대 휴대폰 배경을 떠올리며 디자인 했습니다.


✔️ 주요 로직

스케줄러

  @Scheduled(cron = "0 0 0/1 * * *") //1시간마다 한번씩 실행
	public int mushiSchedule() {
		// LocalDateTime 클래스는 날짜와 시간을 표현하는 java8 문법
		LocalDateTime now = LocalDateTime.now();
		int result = 0;
		Mushi mushi = new Mushi();

		do {
			mushi = generateMushi();
			//무시 가격이 900원 이하이거나 50000원 이상이면 가격 재측정
		} while(mushi.getPrice() < 900 || mushi.getPrice() > 50000);
		
		result = mushiDao.mushiSchedule(mushi);
		
		return result;
	}

1시간마다 무시의 가격을 바꾸고 DB에 저장하는 함수를 생성했습니다.

Spring Scheduler는 Linux의 crontab 기능을 합니다.

  • 어노테이션으로 설정하는 방법도 있고 XML로 설정하는 방법도 있는데 저는 편한 방법으로 전자를 선택했습니다.
  • 주기적으로 실행할 메소드의 앞에 @Scheduled를 붙이면 됩니다.

Cron 식을 찾아보다가 원하는 조건을 입력하면 자동으로 크론 표현식을 생성하는 사이트를 알게 되어 공유해봅니다.


무시 가격 설정

메소드를 실행하면 일정 확률로 -300% ~ 300% 값을 리턴합니다.

확률에 따라 무시의 퍼센트가 정해지며, 사용자의 재미를 위해 확률이 낮을수록 증감 폭이 크게 적용되도록 하였습니다.

  • 먼저 0~999까지 랜덤 난수를 생성하여 확률을 정합니다.
  • 확률 내에서 다시 퍼센트 난수를 생성합니다.
  • 이전 무시 가격 * (퍼센트)에 반올림을 해서 무시 가격을 정했습니다.
  • 이전 무시 가격이 1000원 이하라면 무조건 10% ~ 99% 가격이 오르도록 했습니다.
public Mushi generateMushi () {
		Random r = new Random();
		int probability = r.nextInt(1000);
		int percent = 0;
		
		//이전 무시 가격
		Mushi lastMushi = getLastMushi();
		int lastMushiPrice = lastMushi.getPrice(); 
		
		//마지막 무시가 1000원보다 작다면 10~99% 오른 가격만 적용 될 수 있도록 한다. (떡락 방지)
		if(lastMushiPrice < 1000) {
			percent = r.nextInt(99) + 10;
		}
		else {
			if (probability < 50) { // 5% 확률
				percent = r.nextInt(300) + 200; //200 ~ 300
				log.info("5% 확률");
				
			} else if (probability < 120) { // 7%
				percent = r.nextInt(300) + 200; // -300 ~ -200
				percent *= -1; 
			} else if (probability < 220) { // 10%
				// percent = (r.nextInt(199) + 100); 
				percent = r.nextInt(199) + 99; // 99 ~ 199
				log.info("10% 확률");
			} else if (probability < 320) { // 10%
				percent = r.nextInt(199) + 99; // - 99 ~ - 199
				percent *= -1; 
				log.info("10% 확률");
			} else if (probability < 720) { // 40.0%
				percent = r.nextInt(98) + 10; // -98 ~ -10
				percent *= -1; 
				log.info("40% 확률");
			} else { // 나머지 확률
				percent = r.nextInt(98) + 10; // 10 ~ 98
			}
		}

		int newMushiPrice = (int)Math.round(lastMushiPrice * (1 + (float)percent / 100)); //반올림
		
		Mushi mushi = new Mushi();
		
		mushi.setMushiRound(lastMushi.getMushiRound() + 1);
		mushi.setPrice(newMushiPrice);
		mushi.setPercentage(percent);
		
		return mushi;
	}

✔️ 라즈베리 파이 배포

개발을 하기 전부터 라즈베리 파이로 배포를 하기로 결심했어요. 작년 생일 선물로 라즈베리 파이를 선물 받아서 꼭 써보고 싶었습니다. 라즈베리 파이로 웹 서버를 배포하는 건 잘 정리된 포스팅이 워낙 많기 때문에 생략하고 키워드 흐름만 간단하게 정리를 해봤습니다.

  • 라즈베리파이 조립
  • SD카드에 raspbian OS 설치
  • 라즈베리파이에 원격 프로그램 관련 모듈 설치
  • 고정 아이피 할당
  • 한글 깨짐 설정
  • MySql이라고 쓰고 MariaDB 설치 (라즈비안 최신 버전에서 MySQL 지원하지 않음)
  • Apache Tomcat 설치
  • Java 1.8설치

✔️ 결과

떡상하라 무시코인 베타 버전을 배포 후 2주일 동안 약 8만 명의 방문자57만 건의 구매/판매 기록을 달성했습니다! 🎉

✔️ 배포 후 트러블 슈팅

서비스 배포 이후 여러 곳에서 이슈가 발생했습니다. 쿠키에 값이 저장되기 때문에 클라이언트 쪽에서 재화를 수정할 수 있었고, 또 백신 프로그램 등에 의해 인터넷 기록 등이 삭제 되면 데이터가 날아가는 것도 문제 중 하나 였습니다. 유지보수 부터 CS를 담당하며 겪은 우여곡절 삽질을 정리해보았습니다.


1. 스케줄링이 돌아가지 않아요

라즈베리 파이를 재시작 하고 무시의 가격이 바뀌지 않는 이슈가 발생했습니다. cron의 상태를 확인해보니 작동이 중지되어 있었고 재시작을 해서 오류를 해결을 했습니다.

  • cron 상태 확인
service cron status
  • cron 스크립트 차단 오류 확인
 grep -i cron /var/log/syslog|tail -2
  • cron 시작
/sbin/service cron start

2. 톰캣 재시작 후 사이트 접속이 안 돼요

톰캣은 켜져 있는데 사이트에 접속하면 톰캣 에러 페이지가 나오는 이슈가 있었습니다. 컴퓨터를 재시작 하고 server.xml이 초기화 돼서 포트번호가 8080으로 설정되어 있기 때문이었습니다. web.xml에서 포트번호를 80으로 바꾼 후 정상적으로 접속이 되었습니다.


3. 사이트를 접속하면 무한 로딩이 걸려요

매 정각에 무시의 가격이 바뀌다 보니 가격이 특히 내려가거나 올라가면 사용자가 몰리기도 합니다. 무시의 가격이 크게 올랐을 때 1시간에 약 1000명 정도가 동시 접속을 하였고 사용자가 서버에 접속할 수 없게 되었습니다.

이슈를 해결하기 위해 제가 시도한 방법은 두 가지입니다.

  1. slow query 확인
  2. 라즈베리 파이 성능 확인

문제가 되었던 건 라즈베리 파이의 성능 때문이었습니다.

  • CPU 온도를 확인하는 명령어
vcgencmd measure_temp

접속자가 많을 떄 라즈베리 파이의 온도가 80도를 훌쩍 넘었었는데, 라즈베리 파이는 80도 이상으로 올라가면 자체 보호를 위해 쓰토를링이라는 기능을 이용합니다. 온도를 낮출 때까지 성능을 멈추는 거죠.

라즈베리 파이용 쿨러를 사용해봤지만 결과가 좋진 않았습니다. 퇴근 후 집에 도착하면 은은하게 기계 굽는 냄새가 났으며, 라즈베리 파이가 불에 타는 것처럼 뜨거워져 있었습니다. (냉장고에 넣어야 하나 고민함.)

해당 이슈는 해결하지 못 했지만, 다음에 웹 서버를 구축하게 된다면 클라우드 서버 호스팅을 이용해보려 합니다.


4. 디스크 사용량 어디까지 올라가는 거예요?

떡상하라 무시코인을 약 2주 동안 배포했는데 디스크 사용량이 60%까지 올라갔습니다.

로깅 라이브러리를 이용하여 텍스트 로그를 남겼는데 예상 외로 텍스트가 용량을 엄청 잡아 먹더라고요. (...)

[라즈베리파이]디스크 사용량, 남은 디스크 용량 확인(df, du)

배치를 이용해서 일정 기간이 지나면 로그를 삭제하던가 압축하는 방법을 사용해보려고 합니다. 이 작업을 log rotation이라고 부른다는 것을 처음 알게 되었네요.


✔️ 후기

'떡상하라 무시코인'은 2주 간의 베타 버전을 배포한 후, 개인적인 사정으로 서비스 운영을 중단한 상태입니다. 기획부터 배포 후 유지보수 거기에 CS까지 경험해 볼 수 있는 정말 좋은 기회였습니다. 첫 프로젝트를 무시코인으로 할 수 있어서 다행이라고 생각합니다. 작고 귀여운 실력으로 만든 프로젝트인데 과분한 관심을 받았구나 싶습니다. 앞으로도 즐겁게 공부하고 지식을 쌓으며 여러 사람들이 이용할 수 있는 서비스를 만들어 나가고 싶습니다.

읽어주신 모든 분들께 깊은 감사의 마음을 전합니다.

profile
그냥 기록하기

2개의 댓글

comment-user-thumbnail
2022년 4월 6일

안녕하세요 코인 개발을 계획 중인 대학생입니다. 코인을 개발해보신 dimstar님께 조언을 구하고 싶습니다. 혹시 온라인 혹은 오프라인으로 인터뷰를 해주실 수 있으실까요? 5월 말에서 7월까지 언제든 가능하시다면 꼭 연락주세요🙂

1개의 답글