티스토리 뷰



작년 12월 22일, 방학식이 얼마 남지 않아 들떠있던 디미고에선 재학생 및 교직원을 대상으로 음악회가 개최됐었습니다. 이 음악회에서는 기존 교내 음악회에서는 볼 수 없던 'Voice of DIMIGO'라는 새로운 프로그램이 진행됐었는데 이 프로그램에서 사용되었던 '실시간 투표 시스템'을 개발하면서 생긴 문제점, 해결 방법 등을 글로 남기려고 합니다. 글이 앞뒤가 안맞고 보기 힘들어도 양해 부탁드립니다.


11월 30일 찍은 미 완성 시스템 동영상


Voice of DIMIGO란?

자신의 노래 실력을 다른 학생들 앞에서 뽐낼 수 있는 기회를 제공하기 위해 2016년 디미고 음악회에서 처음 진행한 프로그램으로 '무대를 보는 학생들이 실시간으로 투표에 참여한다'라는 특징을 가지고 있습니다. 기본적인 룰은 아래와 같습니다.

  • 학생들과 참가자 사이에 막을 두어 순수하게 노래 실력만으로 평가를 할 수 있는 프로그램
  • 학생들은 노래를 실시간으로 평가해 참가자의 합격과 불합격을 결정할 수 있음
  • 1절이 끝난 후 합격 표가 60% 이상일 경우 2절에는 얼굴 공개를 하고 노래를 부름 (단 60% 미만일 경우 2절을 부르지 못함)

개발 플랫폼 선택

디미고 학생들은 모두 노트북을 가지고 있어 PC 버전으로 개발하려 했으나 강당의 위치 등 여러 가지 불편함을 생각했을 때 노트북보다는 태블릿, 스마트폰 같은 모바일 기기를 이용해 투표하는 것이 편하겠다고 생각해 '모바일 애플리케이션을 개발하자'라는 마음을 먹게 되었습니다.

'모바일 앱'을 만드는 거야!라고 정한 다음 다시 한 번 생각해보니 저는 iOS 건 안드로이드건 모바일과는 전혀 관계가 없는 사람이란 것을 깨달았습니다.

그래도 방법은 있다!



마침 전 여태껏 웹을 개발해왔었고, 웹에 가장 자신이 있었기 때문에 결국은 아이폰이건 안드로이드건 PC건 모든 디바이스에서 접속이 가능한 인터넷, 웹을 이용하자라는 결론을 내게 되었습니다.


개발 프레임워크 선택

웹으로 정하고 난 뒤 기존에 계속해서 개발해왔고 사용했던 PHP Codeigniter 와 한 달 정도 전 STAC이라는 공모전에 제출할 앱의 RESTful API 서버를 만들기 위해 사용해봤던 Python flask 중 어떤 언어를 선택할지 고민이 되었습니다. 그래서 두 프레임워크의 장단점을 비교해봤습니다. (극도록 주관적입니다)

 

 장점

단점 

PHP Codeigniter

 - 계속 써왔던 언어기 때문에 개발 속도가 빠르다

 - 주변으로부터 욕을 많이 먹는다 (?)

Python flask 

 - 새로운 언어로 웹을 짜볼 수 있다 => 경험

 - RESTful API 밖에 개발을 안해봤다

 - 많이 다뤄보지 못해서 개발 속도가 느리다


PHP를 주로 사용했었던 약 2년간 (지금은 flask를 주로 사용합니다) 저는 제가 얕게만 배운 탓인지 딱히 PHP라는 언어의 단점을 찾지 못했었습니다. 그렇지만 주변 선배나 개발자분들이 PHP는 해로운 언어라고 막 욕하길래..가 아니라 경험을 중요시 하는 제 가치관 때문에 Python flask로 프레임워크를 결정했습니다.

프론트엔드는 기존에 계속 사용했던 BootstrapjQuery를 사용했습니다.


개발 전에 생각을 해보자!

1. 실시간 투표는 어떻게 구현할까?

이 시스템에서 가장 중요한 것은 실시간으로 입력할 수 있고 확인할 수 있는 기능이라고 생각합니다. 사실 이게 다인 시스템이긴 하지만요. HTTP로 데이터를 주고 받을 때에는 먼저 request를 날려야 합니다. 하지만 제가 만들려 했던 시스템은 무려 '실시간'으로, 그러니까 투표가 하나 될 때마다 갱신이 되어야 하는 시스템이였기 떄문에 생소했던 웹소켓이란 것을 사용하기로 했습니다.


사실 웹소켓의 정의라던지 방식같은 것은 아직도 모릅니다. 그냥 예전에 잠깐 수박 겉핥기도 아니고 수박 구경하기 수준으로 해봤던 socket.io 때문에 생각하게 됐습니다. socket.io에 있던 예제가 전부 nodejs 로 짜져있길래 개발 프레임워크를 nodejs로 바꿔야 하나라고 잠시 생각 했었지만 감사하게도 github에 Flask SocketIO 가 있길래 언어를 바꾸는 불상사는 일어나지 않았습니다.


사실 전 nodejs를 못합니다


2. 외부인이 접속해서 투표하면 어쩌지?

이 부분은 쉽게 결론이 도출됐습니다. 교내 API를 이용해 인트라넷 계정을 통해 로그인하게 만들면 되겠구나라는 생각이 들었고 파이썬 dimigo api 모듈을 만들어 로그인을 구현했습니다. 물론 모듈이 완성은 아니지만 추후에 충분히 API 문서를 보고 코드를 추가, 수정할 때 내 입장에서 편하게 해놨습니다.


추가로 PHP로 작성된 dimigo api 클래스도 있습니다. 나중에 파이썬 모듈이랑 같이 묶어서 한 번에 공개할까 생각중입니다.


3. 동시접속자가 많을텐데 어떻게 처리해야되지?

동시접속자가 400이 넘어가는 페이지를 한 번 개발해봤던 경험을 빼곤 몇백명의 동시접속자를 받아본 적이 없어서 고민이 많이 됐었습니다. 물론 동시접속자가 400이 넘는 페이지도 단일페이지라 버틸 수 있었던 것 같고요. 그래서 그냥' 대규모 접속은 무시하고 짠 뒤 하드웨어 성능을 빵빵하게 넣어주자' 라고 결론냈습니다. (서버는 디미고 14기 웹프로그래밍과 염x우 학생이 지원해줬습니다 짞짞)


4. 만약에 서버가 터지면 어떡하지?

본래 저는 db를 사용하지 않고 변수만을 이용해 투표 수를 저장하는 방식으로 구현하려 했습니다. 어차피 로그인은 디미고 api가 처리해주니까요. 그런데 서버가 터지면 해당 무대에 했던 투표는 모두 날라가게 될테고 저에게 날라올 욕들이 무서워서 'db에 투표를 저장하게 만들자'라고 생각을 바꾸게 됐습니다. db에 투표를 저장하면 서버 앱을 새로 키고 새로고침만 하면 될테니까요.


구현

1. 학생들이 보는 페이지

학생들이 볼 수 있는 페이지는 두개로 로그인과 투표 페이지 였습니다. 로그인 페이지는 dribbble에서 여러 디자인을 참고하면서 프론트앤드를 만들었고, 디미고 API를 연동해놨습니다. 시스템 서버에서 디미고 api 서버에 request를 보내고 response를 받아오는 시간이 꽤 걸리길래 사용자 피드백을 주기 위해 response 대기시에 로딩을 띄우게 했습니다.

이 로딩도 꼼수를 써서 구현했습니다 :)



아무래도 학생, 즉 사용자들이 직접적으로 볼 수 있는 페이지들이기 때문에 여러가지 디자인도 신경 많이 썼었습니다. alert같은 경우도 SweetAlert2의 디자인을 커스터마이징해서 사용했습니다.


수정 전 디자인 수정한 후 디자인



투표 페이지는 모든 디바이스에서 사용할 수 있게 반응형으로 코딩했고, 처음에 계획했던 대로 소켓을 이용해 서버랑 통신하게 만들었습니다. 소켓을 통해 어드민 패널에서 변경하는 무대를 실시간으로 화면에 띄워주고, UP과 DOWN을 서버로 보내고 서버에서 다시 실시간 투표 확인 페이지에 데이터를 뿌려주는 걸로! 


2. 실시간 투표 현황 확인 페이지

강당 프로젝터를 통해 무대에 현재 투표 현황을 확인할 수 있게 만들어야 했습니다. 그래서 처음은 그냥 4:3 비율인 스크린을 생각해 만들었습니다. 듀엣가요제 스크린에서 영향을 받아서 동그란 그래프 안에 숫자를 적어놓은 디자인으로 만들었고 색과 아이콘 모양때문에 고급시계가 연상된다는 말을 들었습니다 ㅠㅠ


그래프는 chartjs 를 사용했고 끝이 둥글게 만드는건 chartjs 의 커스터마이징 기능(?)을 이용해 제작했고, 눈이 내리게 하는 건 h4wldev/jquery-Snowfall 기존에 있던 라이브러리를 수정해서 만들어 사용했습니다.

나름 신경 많이 쓴 첫 디자인


'Voice of DIMIGO'는 원래 커다란 박스 안에 참가자를 넣어 놓고 진행하는걸로 기획되서 학생들 입장에서 스크린이 보였지만, 음악회가 진행되기 2일 정도 전에 박스 대신에 참가자 앞에 가림막을 두는걸로 기획이 변경됐습니다. 막이 물결모양으로 생개서 프로젝트를 쏴도 글자가 안보이길래 디자인을 변경해야 했습니다.


변경된 디자인


음악회 리허설날 한 테스트 (노래 정보는 안보이길래 지웠습니다)


바뀐 디자인 처럼 가로로 서로 막대가 왔다갔다 하는 모양의 그래프를 지원하는 라이브러리가 없는 것 같아 직접 canvas를 이용해 만들었습니다. 그래서 기존 디자인에 있던 애니메이션이 사라지고 딱딱하게 바꼈습니다 ㅠㅠ


3. 어드민 패널 페이지

무대를 변경할 수 있고, 무대 준비중을 띄울 수 있는 페이지가 필요하다고 생각해서 어드민 패널도 만들었습니다. 이 페이지는 딱히 설명할 게 없어서 페이지 사진 하나만 올리고 넘어가겠습니다.

실제 음악회에 사용된 시스템은 로그 기능이 없습니다 ㅠㅠ


큰 문제가 생겼고 꼼수를 부림

모든걸 다 만들어 놓고 혹시나 하는 생각에 스트레스테스트를 진행해보기로 했습니다. 그래서 locust라는 라이브러리(?)를 이용해 진행했고 결과는 충격적이였습니다. (아래 사진은 모든 수정을 끝마치고 마지막으로 진행한 테스트 중 찍은 사진입니다)

비 전공자가 보면 멋있을 사진 (아래 세개는 왼쪽부터 mysql 실시간 커넥션 로그, htop, 플라스크 디버깅 모드)


RPS가 10을 넘어가면 CPU나 램 사용량은 괜찮지만 소켓에 병목현상이 생겨 투표수가 안올라가는 현상이 발생했습니다. 제가 코드를 잘 못 짠 것인지 웹 소켓이 원래 이런건지는 잘 모르겠지만 웹 소켓을 몰랐던 제가 수정해봤자 나아지는 것은 없다고 생각해서 무대 변경을 제외한 모든 페이지에 있는 통신 부분을 웹 소켓에서 AJAX로 변경했습니다. 투표 결과를 확인하는 창도 1초에 한번 request를 보내 받은 response로 업데이트하게 꼼수를 부렸습니다. 그러고 나니 RPS가 100을 넘어가도 투표수가 안올라가는 현상을 발생하지 않았습니다.


두근두근! 음악회 당일

전 음악회 당일 방과후 시간(음악회는 야자시간에 진행)까지도 계속 서버 코드를 보고 있었습니다 ㅠㅠ 무슨일이 생기는 건 아닌지 내가 짠 코드 때문에 프로그램 자체가 망하는 것은 아닌지 심장을 졸이면서 'Voice of DIMIGO'의 순서를 기다렸습니다.


'Voice of DIMIGO'가 준비되고 있는 시간에 무대로 나가 투표시스템에 대한 설명을 했고 접속해 로그인을 하라고 했습니다.


여기서 문제가 발생했습니다. 시스템 서버는 문제가 없었지만 디미고 API서버가 동시접속자를 버티지 못했고 대부분의 학생들이 로그인을 못하는 사태가 생겼습니다. 디미고 API 서버를 접근 할 수도 없고 담당 선생님은 퇴근을 하셔서 제가 어떻게 할 수 있는 상황이 아니였기에 아무런 대처를 하지 못했습니다 ㅠㅠ


어쨌든 음악회의 시간이 모자라 무대는 진행 됐고 첫 번째 무대가 시작됐습니다. 두근두근한 마음으로 투표가 잘 올라가나 무대를 쳐다보고 있다가 투표가 올라가는 것을 보고 주변에 있는 친구를 껴안으면서 좋아했었습니다. 첫번째 무대와 두번째 무대는 결과까지 잘 나왔습니다. 학생들이 결과가 나올때마다 소리를 지를 때 뿌듯함을 느끼고 있었습니다.


그런데 아니나 다를까 또 문제가 터졌습니다. 무대가 진행되면 진행될 수록 점점 결과가 공개되는 시간도 늘어났습니다. 결국엔 사회자가 3, 2, 1을 외치고 나서 30초 이따가 결과가 공개되는 상황까지 생겼고요.. 서버를 빌려준 염x우도 시스템을 개발한 저도 원인을 모른체 그냥 기다리다가 서버 앱을 껐다 켜보자라는 결론이 났고 껐다 키니 정상적으로 다시 돌아왔습니다. 그래서 무대가 끝나면 서버를 껐다 키는 눈물겨운 노력을 했었습니다 ㅠㅠㅠ (이 문제는 아직도 원인을 모르고 있습니다)


그렇게 'Voice of DIMIGO'는 끝이 났고 서버가 다운돼서 투표를 하지 못하는 상황같은 큰 악재는 닥치지 않았지만 그래도 문제가 많이 생겨 아쉽긴 했습니다.


개발 후기

여태껏 많은 사람들이 사용하는 서비스를 한번도 개발해본 경험이 없던 저에게는 여러가지 고민을 할 수 있었던 재밌었던 프로젝트였습니다. 처음으로 스트레스 테스트란 것도 해보고 문제를 겪고 해결하면서 머리를 쥐어짜는 스트레스와 쾌감을 느끼기도 했었고요. 음악회 당일날 예상하지 못했던 여러가지 문제점이 또 생기긴해 개인적으로는 아쉬웠지만 그래도 주변 친구들이나 선생님들에게 칭찬도 들어서 뿌듯하기도 했습니다. 이제 고등학교 3학년이 되어서 교내에서 이런 프로젝트를 진행할 여건이 안될것 같긴 하지만 그래도 졸업하기전에 뭔가 더 해보고 싶다는 생각이 듭니다. 끝!

댓글 댓글펼치기