Loading
2022. 4. 24. 19:21 - lazykuna

[개발회고록] iidx ranktable service

웹 표준 기술, 그리고 이를 기반으로 한 프레임워크들이 비약적으로 발전하고 있는 지금 와서는 어디가서 내놓기 부끄러운 수준의 서비스지만 ㅎㅎ... 이것도 생각해보면 오래 유지보수했고, 투자 대비 이런저런 에피소드가 많았던 서비스였습니다. 나름 월평균 1천~2천명의 접속자수도 유지했었고요.

그동안 겪었던 경험들과 생각 등 이모저모들을 기록으로 남겨두려 합니다.

이 서비스는 무엇인고?

iidx 플레이 기록을 전달받아서 이를 서열표로 보여주는 기능을 합니다.

iidx 플레이 기록은 타 플레이 기록 저장 사이트나, 코나미 csv로부터 전달받을 수 있고, 서열표 자료는 여러 곳에서 업데이트되는 서열표 자료를 참조할 수 있습니다 (zasa, 5ch 스레드 등)

실제 작동하는 모습은 이렇습니다.

이거 왜 만듬?

요즘은 바쁘기도 하고 다른 게임 하느라 바쁜것도 있어서 (^^;) 잘 하지는 않지만, 태초에 리듬게임 갤러리에 “투덱 서열표"라는게 있었습니다. 보이는 것처럼 단순하고 직관적으로 생겼는데, 이 서열표에 자신의 클리어 내역을 직접 칠해서 남들에게 뽐낼 수 있었죠.

한 가지 주목할 것은 “서열"이 들어가 있다는 점인데, 이는 투덱의 난이도 체계에서 비롯된 문제에서부터 시작합니다. 투덱은 난이도가 1~12까지 있었고, 8레벨 전까지는 큰 이슈 없이 대부분의 사람들이 그럭저럭 기본 재능이 있으면 빠르게 올라옵니다.

문제는 8레벨 이후부터인데, 곡의 밀도가 급격히 높아지면서 + 각종 기믹이 추가되면서 실력이 잘 늘지 않게 되고, 그러다 보니 같은 레벨 내에서의 난이도 차이 체감도 훨씬 심해집니다. 그리고 또 다른 큰 문제는 이러한 숫자로는 패턴에 따라 개인이 느끼는 난이도(= 개인차)를 제대로 반영할 수 없다는 것입니다. 예를 들면,

위처럼 축노트가 있거나, DP 무리스크가 있는 경우, 혹은

스크래치만 잔뜩 있는 이런 “스크곡" 같은 경우는 이런 패턴에 익숙한 사람이면 아주 쉽게 클리어 할 수 있는 반면, 그렇지 않으면 체감 난이도가 급상승하는 경향을 보입니다.

그러다 보니 같은 레벨 안에서 입문곡과 졸업곡이 생기게 되는 기행이 벌어지게 되고, 같은 12렙인데 한 곡은 하드클 한 곡은 클리어도 못하는 것은 다반사요, 심한 경우 11렙 졸업곡의 경우는 12렙 중반 입문을 하는 와중에도 안정적으로 클리어를 못하는 웃픈 일이 벌어지기도 합니다.

이러한 문제를 극복하고자, 유저들이 자발적으로 매긴 난이도가 사실상 “서열표"가 아닌가 싶네요. 서열표에서 또 재미있는 점은, 위에서 말한 개인차를 감안하기 위해서, 개인차가 심한 곡은 “개인차" 탭에 몰아넣는 구조로 되어 있어 그러한 함정곡을 어느정도 피할 수 있도록 설계되어 있다는 점입니다. 사람들이 괜히 많이 찾는 게 아니죠.

아, 그래서 결국 이걸 왜 웹 서비스로 만들었냐면,

  1. 서열표 칠하기 귀찮아서
    칠 하려면 매번 페인트 앱 켜서 서열표 원본 열고 수정하고 저장하고 해야 하는데 귀찮아...
  2. 서열표의 자동화를 할 수 있지 않을까?
    서열표도 결국은 사람의 힘을 빌려서 매기는 작업이라 종종 틀린 정보가 들어가기도 합니다.
    그리고 전 기계의 힘을 믿기 때문에, 기계한테 난이도 매기려고요. 머신러닝도 살짝 배워놨겠다 충분히 할 수 있지 않을까...

정도가 될 것 같습니다 ㅎㅎ.

처음에는 혼자서 이것저것 해볼 요량으로 만든 거라서, 트래픽 및 유지보수나 확장성 등의 철저한 설계를 한 건 아니고 토이프로젝트 수준으로 시작했습니다.

기본 설계

사실 이 설계를 할 때만 해도 웹서버 아키텍처에 대한 이해도가 거의 없다시피 했습니다. 이전에 APM(Apache+PHP+MySQL) 설치해서 몇 번 굴려본 게 전부라서, 바닥부터 설계하는 건 처음인 상황입니다. 그래서 남들 하는 거 그대로 따라서 해보기로 결정합니다.

백엔드 프레임워크

개발을 시작했던 당시에는 Ruby on rails와 Django 둘이 웹개발 트렌드로 자리잡았던 상황으로 기억합니다. 그 중에서 django를 고른 이유라면,

  • Python은 제가 구사할 수 있던 언어
    Ruby는 웹 원툴이라 저한텐 그렇게 익숙하지 않아요...
  • 주변 스크립트들도 모두 Python
    서비스 구동에 필요했던 크롤러나 각종 스크립트들을 모두 python으로 작성했었습니다. 당연히 호환성 측면에서 python이 훨씬 나은 모습을 보여주겠죠.
  • 윈도우 비친화적이고 쓸데없이 복잡한 Gem
    디펜던시 시스템을 확고하게 잘 꾸리겠다는 의도는 좋았는데, 뭔가 엄청나게 복잡합니다. 고작 웹서버 하나 올리는 데 이렇게 많이 까는게 맞아...?
    컴파일도 엄청나게 돌려댑니다. 당시에 윈도우 썼던 거 같은데, 거의 안 돌아가다시피 합니다. 고작 장난감 만들자고 새로 세팅 다 올리기도 귀찮고... -_-
    장고는 적어도 시작할 때 기준으로는 장고 하나만 넣으면 끝나는 수준이라, 이런 거 잘 몰랐던 당시의 저에게는 훨씬 친숙하고 납득할 수 있는 모습이었습니다.

웹 프레임워크 (프론트엔드)

웹 프레임워크는 이것저것 많이 안쓰고, bootstrap + jQuery + CSS 조합으로 했습니다. 사실 HTML 기술이 하루가 다르게 어마어마한 속도라 발전한 지금 와서는 이건 이미 사장된 조합이긴 하지만, 티스토리/텍스트큐브 쓰면서 생긴 jQuery 짬(?)이 유효했던 당시에는 이건 꽤 유효한 접근 방법이었습니다.

  • 퍼포먼스 그런건 잘 모르겠고... DOM 뜯기에는 도가 텄기 때문에 가능한 방법이었습니다 ㅎㅎ

그리고 나서 만든 건, 이 프로젝트의 가장 핵심인 서열표 렌더링 로직 이었습니다.

이 부분에는 큰 변화가 있었는데, 맨 처음에는 div로 직접 서열표를 만들고, 이후 이미지 파일로 다운받고자 하는 경우 이를 HTMLToCanvas javascript 라이브러리를 이용하여 canvas로 export 하는 방식을 사용하였습니다. 하지만 이 방식의 경우 HTMLToCanvas가 완벽하지 않은 문제도 있었거니와, div로 서열표를 구성하는 건 웹 렌더링 로직을 많이 타기 때문에 브라우저에 따라 깨져보이는 문제도 있을 뿐더러, 곡 제목이 아주 긴 경우에는 가로 크기가 지정한 레이아웃을 벗어나기 때문에 보기 흉한 문제가 있었습니다.

그래서 이러한 문제를 해결하고자, 아예 테이블을 렌더링하는 로직을 따로 작성하였습니다. 이후로는 이 부분에서 문제가 발생한 건 없었네요. 다만, canvas에 수작업으로 렌더링하는 것보다는 SVG로 렌더링 하면 접근성 측면에서 더 좋지 않았을까 하는 생각은 듭니다.

데이터베이스

장고를 골랐으니, DB는 자연스럽게 RDB를 고르게 되었습니다. 사실 당시에 NoSQL에 친숙하지 않기도 했습니다. 그래서 일단 MariaDB를 선택합니다.

그리고 MariaDB에 온갖 정보를 다 쑤셔박기로 결정합니다. 유저 정보는 물론이고 서열표 정보도 넣고, 유저와 서열표 PK를 들고 오면 플레이 레코드도 쉽게 구현할 수 있을 거라고 생각합니다. 그래서 이것도 다 장고에 ORM으로 구현하고, 유지보수는 장고 내부에 커스텀 스크립트를 만들어서 그거 부르는 걸로 하기로 합니다.

이 정도면 합리적인 설계 같았습니다. 그래서 이대로 하기로 합니다 ㅎㅎ.

웹서버 라우터

그리고 마지막으로 라우터 역할을 할 (+ 덤으로 웹서버 역할을 할) nginx를 설치합니다. 이것도 딱히 대안은 없습니다. Apache 대비 가볍다는 게 제일 컸습니다. Event-driven으로 동시커넥션 소화 능력도 우수하다지만, 그만큼 극한으로 굴릴 일은 없겠죠 ^^;

아, 아무리 문외한인 저라도 static file은 따로 서빙할 수 있도록 라우팅을 해 주었습니다. CDN까지는 귀찮아서(그만큼 트래픽도 없고) 이용하지는 않았는데, 적어도 장고에서 직접 서빙하는 것보다는 훨씬 리소스 소모량은 적으니 탁월한 선택이었습니다.

호스팅

마지막으로 이 모든 걸 올릴 호스팅 업체를 찾아야 합니다. 일단 다른 건 몰라도, 당시 가난한 학생에게 가장 중요한 건 돈! 이었습니다.

그런데 이 모든 걸 올리기에는 AWS의 t2.micro는 너무 작았습니다. 그래서 다른 걸 찾다 보니... Vultr이 있더라고요. 월 만원 정도에 메모리 768MB면 적당히 DB+django+nginx를 다 올릴 수 있는 견적이 나왔습니다.

누군가는 물을 수 있을거 같습니다. 왜 굳이 서버 하나에 모든 인스턴스를 다 몰아넣지? 라고요. 왜 그렇게 했냐면, 평상시에 혼자 서버 운용할 때 그런 환경으로 해 왔으니까요 (...) 그닥 합리적인 이유는 아닙니다 :p

최종 아키텍처

그래서, 최종적인 아키텍처를 지금 그려본다면 아래와 같은 모습일 겁니다. 좀 부족하긴 해도, 지금 생각해 보면 “당시 저걸 어떻게 했지?” 싶긴 하네요. 하나도 모르고 그냥 이것저것 글만 주워다 읽어서 한 것 치곤 준수한 구성이 아니었나 싶습니다.

정말 간단한 모습인데, 사실 저기에 API라고 할 것도 없었습니다. 파이썬 모듈 임포트 해서 쓰는 걸로 도메인 로직과의 연동은 끝이었으니까요.

의도치 않은 트래픽 증가, 그리고 이슈

그렇게 대충 짜놓고 혼자서 즐기면서 굴리고 있었는데, 어디서 소문을 탔는지 사람들이 이용하기 시작합니다. 구글에서도 검색되기 시작했습니다. 실 사용자들이 생기면서, 서비스를 계속 유지하면서 여러 이슈들을 맞이하게 됩니다.

반갑지 않은 스팸 댓글들

사이트를 만들 때, 공지사항과 해당 건의사항을 확인하기 위해서 사이트 내에 자체 댓글 기능을 만들어 두었습니다. 그런데, 그렇게 댓글 기능을 만들고 나니 봇들이 와서 엄청나게 댓글을 달아댑니다 -_-;

진짜 정확히 저런 식의 댓글을 다는 봇이 마구마구 사이트에 들어와서 DB를 더럽히기 시작합니다.

이를 위해서 아래와 같은 방법을 도입했습니다.

  • 금지어 목록 추가
    본문에 링크나 태그를 거는 행위(꺽쇠), 광고들에서 자주 보이는 특정 단어들을 막도록 해놨고, 그 단어들을 DB로부터 불러올 수 있도록 하여 유지관리를 용이하도록 하게 하였습니다.
  • 금지 IP 대역 추가
    이것도 보다 보니, 특정 IP 대역에서만 스팸 댓글이 들어오는 경향이 있어 해당 IP 대역을 필터링 할 수 있도록 했고, 마찬가지로 정보를 DB에서 관리하도록 했습니다.
  • Google Captcha 도입
    그래도 들어오는 스팸은 이거면 대부분 다 걸러집니다 ㅎㅎ.

이 정도만 해도 확실히 99%의 스팸은 다 걸러지더라고요.

모바일 접근성 이슈

나름 bootstrap로 짜서 이건 어느정도 자동으로 챙겨지겠거니 하고 별 생각 안 하고 있었는데, 어느날 우연히 모바일에서 들어가 보았더니 반응형 디자인이 전혀 작동하지 않아 PC 화면을 기반으로 렌더링되어 너무 작고 불편했던 기억이 납니다.

수정이야 어렵지 않았습니다. 다만, 프론트엔드 개발할 때는 responsive view로 모바일에서 어떻게 보이는지 미리 확인하고 갈 필요가 있겠다는 생각은 하게 되었네요.

마이그레이션 이슈

아마 Django 1.6에서 1.8로 버전업하다가 생겼던 일로 기억하는데, 프로덕션 서버에서 별 생각없이 pip upgrade 를 하고 migration을 돌리려고 하니 스키마 관련 오류를 뿜으면서 “마이그레이션 실패" 메시지를 보여주던 적이 있었습니다.

굉장히 당황스러웠던게, 애당초 버전업으로 기존 코드가 실패할 거라는 생각을 한 적이 없었고, 그랬기 때문에 개발 환경에 대해서 저장해 둔 내용도 없어 롤백하는 것 또한 불가능에 가까웠습니다 ㅋㅋ. 초 긴급하게 문제를 파악해서 직접 해결하는 수밖에 없었습니다.

자세한 기록이 없어 잘 기억이 나지는 않지만, 아마 django의 ORM 관련하여 스펙이 일부 바뀐 것이 있어, 모델 쪽 코드와 스키마 일부만 약간 변경하는 것으로 일단 문제를 빠르게 해결할 수 있었습니다. 그나마 다행이었죠.

다만 이 일 이후로 컴포넌트 업그레이드는 가능하면 지양하게 되었습니다. 레거시를 쓰지 말라고들 하는데, 그게 다 어른의 사정인거죠 ㅎㅎ... 물론 이렇게 하면 안 되고, 중요 모듈은 꾸준하게 업그레이드해야 합니다. 다만, 업그레이드 할 때 로컬에 작업환경을 갖춰놓고서 먼저 테스트 한 후에, 문제가 없으면 이전 버전 정보를 기록하고 프로덕션 업그레이드를 진행하게 되었습니다. 이후에 실제 회사에서 일을 할 때도 비슷한 방식으로 일을 하더라고요.

프로덕션의 마이그레이션은 신중하게 합시다.

잦은 서버 다운

왜인지 언제부터인가 503 오류가 자꾸만 뜬다는 제보가 들려옵니다. 그때마다 서버를 접속해보면 django가 죽어 있습니다. 왜 그런가 살펴보면 메모리가 넘쳐서 죽은 것으로 확인이 됩니다. system log를 살펴보면 503을 내뱉은 시점 근처에 메모리 부족 로그가 같이 있기도 하고, 가끔은 django 로그 자체에 메모리 부족 로그가 나와있기도 했습니다.

그러면 원인을 찾아야겠죠? 하지만 별다른 원인을 찾기가 어려웠습니다. 애당초 750MB 메모리의 서버 하나에 django 이외에도 DB와 nginx까지 모든 걸 다 올려놨기 때문에, 그 자체만으로도 어떻게 보면 극한 환경이라... 메모리 로거 같은 것을 달고 상황을 장시간 트래킹하기에는 좀 부담스러운 환경이었습니다.

우선 프로세스 메모리 사용량을 보니 MariaDB이 생각 이상으로 메모리를 많이 먹고 있는게 확인이 됩니다. 당시 300MB 이상을 먹고 있던걸로 보여서, 최대한 메모리 캐시를 적게 쓰도록 설정을 변경해서 메모리 공간을 최대한 확보해두도록 했습니다. 그리고, django가 죽으면 계속 켜주도록 하는 스크립트를 돌려서 문제를 일단락지었습니다만 (...)

사실 이 문제는 이렇게 해결하면 안 되죠. 제대로 접근한다면 아래처럼 해결했어야 할 것 같습니다.

  • 컨테이너로 환경 분리 및 리소스 제한
    당장 메모리가 부족해서 죽은 건 장고지만 누가 메모리를 기대 이상으로 많이 소모했는지 정확하게 트래킹은 안 되는 상황입니다. DB가 상상 이상으로 많이 먹었는데, victim이 장고가 되었을 지 누가 알아요.
    • 다만 현실적으로 이걸 실천하기에는 시스템 환경이 좀 좋지는 않습니다. 따라서 완벽한 격리는 어렵더라도, 모니터링 툴이나 설정 파일 등으로 통제하는 방안을 생각해 봄 직 합니다.
  • 모니터링 및 트래킹 툴 추가
    주기적으로 특정 프로세스 모니터링 하고 리소스 사용량이 경고치까지 오면 알람을 보내거나 하는 시스템 정도는 있어야 문제 대처가 훨씬 용이하다는 생각을 다시금 합니다.
  • 시스템 리소스 확보
    솔직히 아무리 토이 프로젝트라도 시스템 전체 가용 리소스 750MB는 좀 그래...

유지보수의 귀찮음

서열표 정보를 갱신하려면 알아야 되는 정보가 크게 두가지가 있습니다 첫번째로는 수록곡 정보를 어디선가 찾아와야 합니다. 두번째로는 서열표 정보도 어디선가 가져와야 하죠.

하지만 수록곡 정보를 가져오는 일부터 문제가 있습니다. 비트매니아는 코나미 게임인데, 세계최고게임회사 코나미는 절대로 정보를 공짜로 풀어주는 일이 없습니다. 유저들의 플레이 정보는 물론이고 심지어 수록곡 정보마저도 풀어주지 않습니다. (무료 계정 한정, 프리미엄 서비스 이용시 조회 가능. 😡)

따라서 수록곡 정보를 얻어오려면 다른 사이트(remywiki 등)들을 크롤링 해야 하는데, 이 사이트들도 사람이 직접 작성한 경우가 대다수라서, 글자가 미묘하게 다른 경우가 많습니다. 그나마 수록곡 정보는 사이트 한 군데만 지속적으로 크롤링 한다고 치면 괜찮다고 가정할 수 있습니다. 하지만 서열표의 정보는 상당히 곤란합니다.

예를 들면, 아래처럼 일본 전각 문자를 반각 문자로 바꿔 써놓든가, 가끔씩은 아예 빼놓기도 하고

  • キャトられ❤恋はモ~モク
  • キャトられ❤恋はモモク
  • キャトられ❤恋はモ~モク

혹은 제목에 추가 정보가 들어 있는 경우 이걸 통째로 빼버리는 경우도 심심치 않게 있고

  • 取り残された美術 (Arranged:HiZuMi)
  • 取り残された美術

레겐 난이도가 추가되면서부터는 그냥 지 멋대로 표기해 버립니다 (...)

  • Verflucht†LEGGENDARIA
  • Verflucht†
  • Verflucht†Leggendaria

제가 어지간하면 Normalize 과정을 거쳐서 자동화 시켜보려고 했는데, 지금의 상황으로는 불가능한 수준입니다. 결국 서열표가 새로 나오면 수동으로 업데이트를 수행해야 하는데, 굉장히 피로합니다. 그리고 수록곡 정보도 업데이트를 한 사이트에서 계속 하면 괜찮다고 했는데, 사실 remywiki 이전에 사용하던 다른 사이트가 있었는데 그 사이트가 망하면서 (...) 이미 수록곡 소스가 한 번 바뀐 상황입니다. 즉 전체 업데이트시 곡 정보가 수십개는 꼬이게 됩니다.

시스템이 자동화되지 않으면 생각 이상으로 유지보수가 어렵습니다. 무언가를 시작하기 전에 이 점 또한 생각해 볼 필요가 있는 것 같네요. 특히 토이프로젝트라면 더더욱...

저레벨 곡의 서열 정보 부재

사실 서열표 목적 자체가 고렙 곡들의 난이도 변별력을 키우기 위함인 것을 부정할 수는 없습니다. 다만 그러한 특성 때문에 11렙 이하의 서열표는 거의 없다시피한 실정이고, 애매한 레벨대(9~10레벨) 유저들은 참조할 만한 자료가 없는 게 문제입니다. 이미 몇번 만들어 줄 수 없냐는 요청을 받기도 했었습니다.

하지만 서열표는 제가 만드는 물건이 아니라 이미 만들어 진 자료를 가공해 오는 것이죠. 제가 여기서 할 수 있는 건 없습니다. 다만 서열표가 제공할 수 있는 정보가 고렙 위주로 한정된다는 것은 생각해 볼 여지가 있기는 하네요.

난이도 추정 기능 추가

어느 정도 서비스가 안정화 되고, 자료도 모이고 하니 슬슬 본래 목적 중 하나였던 난이도 추정 기능을 추가해보려고 시도하게 되었습니다. 이를 통해 하고자 했던 건...

  • 저레벨 곡들 및 아직 미정된 곡들 서열 자동 매김
    없는 정보를 만들어 낼 수 있다는 것... 엔지니어라면 누구나 해보고 싶은 일이고, 꽤 흥미롭지 않습니까 ㅎㅎ.
  • 개인차에 대한 정확한 수치 추산
    특정 곡이 개인차라는 것도 어떻게 보면 참 주관적인 영역입니다. 동치가 마구 나와서 개인차에 넣었지만, 누군가에게는 동치 정도는 껌일수도 있거든요. 그게 정말 개인차인지 아닌지 숫자로 충분히 계산할 수 있다면, 꽤 유용한 정보가 아닐까요.

당시 생각했던 학습 방법은, 클리어 기록을 0 또는 1 값으로 환산해서, 이걸 sigmoid에 fit시켜 유저의 수준과 곡의 난이도를 동시에 추정하는 것이었습니다. 보다 구체적으로 설명하면,

일단 sigmoid 그래프는 이렇게 생겼죠? 여기에서 x축을 난이도라고 하고, y 축을 클리어 여부라고 가정하고, 그리고 sigmoid의 x축 평행이동 값(a)을 곡 난이도라고 가정합시다. 그러면, 곡 난이도보다 낮은 실력을 가진 유저들은 페일을 할 거고, 반대로 높은 실력자들은 곡을 클리어 할 거라고 생각할 수 있습니다. 대략 아래처럼...

실제 데이터가 아닙니다! 예시로 들고온 자료입니다.

좋아 보이네요! 계획은 완벽하니 실행에 옮기기로 합니다.

프로덕션 서버에서 러닝 하기에는 너무나도 큰 데이터셋

사실 본래 목표는 서버가 있는 웹서버에서 바로 학습을 시켜서 정보를 service할 생각이었습니다. 하지만 시작하기도 전에 오산인 것 같다는 생각이 들었습니다 ㅎㅎ; 제가 정확하게 기억을 못 하지만, 플레이 레코드 기록이 약 1만건 정도 있었는데, 이걸 750MB 램에 micro 수준의 CPU 자원으로 학습한다? 음....

곱게 데스크탑으로 데이터를 export 해서 테스트하기로 했습니다. 그런데 익스포트 스크립트를 돌리는 것만으로도 서버가 뻗더라고요 ㅋㅋㅋ... 램 부족현상이 일어났습니다. 그래서 DB를 통째로 dump후 가져왔는데, 제 기억으로 약 2GB정도의 자료가 나오더라고요.

이걸 가지고 위 모델을 토대로 학습을 수행했습니다. 정확한 각종 파타미터들은 기억이 안 나는데, 이것만으로도 학습 한 번 하는데 서너시간은 걸렸습니다. (당시에는 CPU로 함)

추정값의 부정확함

하지만 일이 생각처럼 쉽게 되지 않았습니다. 예상과 다르게 값이 튀는 곡들이 너무 많았습니다. 왜 그럴까... 파라미터도 바꾸고 epoch도 바꿔 보았지만 역시 개차반이었습니다. 고민하다가, 곡 하나를 가지고 plotting 해 보았더니 세상에. 이런 식으로 결과가 나왔습니다.

발로 그리긴 했지만... 아무튼 기대와는 다르게 분포가 상당히 자유분방하게 나타나는 곡들이 있었습니다. 의외로 유명한 곡들도 이러한 경향을 띄는 경우가 있었습니다.

곰곰이 생각해보다가, 현재 모델로는 아래와 같은 false positive에 대해서 대처가 어렵다는 사실을 깨닫게 되었습니다.

  • 클리어 할 수 있는데, 일부러 클리어하지 않음 (우하단의 경우)
  • 겨우겨우 몸 비틀어서 클리어 함 (좌상단의 경우)

게다가 가끔 쉬운 곡 (불클한사람이 거의 없음)이나 아주 어려운 곡 (클리어한 사람이 거의 없음)의 경우, 난이도가 천정부지로 천장을 뚫고 가는 경우도 가끔 있었습니다. 사실 이 문제는 초창기에 loss function을 square loss로 한 것도 있었기 때문에 -_-; cross entropy로 고치면 사정이 좀 나아집니다만... 그래도 데이터가 워낙 상태가 좋지가 않아서 좋은 결과가 나오지는 않았습니다.

이외에도 아래와 같은 방법들을 시도해 보았으나 결과가 좋지는 않았습니다.

  • 유저별로 분산 값 도입
    분산이 큰 유저는 어려운 건 깨놓고 쉬운 곡들은 제대로 안 깨 놓은 유저로 간주해서, 가중치를 낮게 주었습니다.
  • 플레이 기록이 적은 곡들은 학습에서 배제
    플레이 기록(서열표에 기록된 정보)이 5개도 없는 경우가 꽤나 있어서, 이는 배제하도록 하였습니다.

그리고 아무래도 곡들은 많은데 그에 대비해서 플레이 기록이 적은 점도 문제 요인 중 하나였을 것 같습니다. 오버피팅 되는 경우가 굉장히 많았거든요.

결국은...

결국은 뭐, 이런 자료로는 절대 서비스를 할 수가 없었기 때문에, 바로 본래 서비스하던 데이터로 롤백했습니다. 서열표도 수동으로 계속 업데이트 하는것으로 ^^;...

다만 포기한 건 아니고, 유저 플레이 대신 채보를 데이터로 삼아 난이도를 책정하는 방식을 생각해보고 있습니다. 위에서 이야기 했던 문제가 없을 것이라 훨씬 정확한 결과를 얻을 수 있을 것으로 기대하고 있어요.

(잠정적) 서비스 중단

아무래도 본격적으로 취직하면서 사축의 노예가 되다 보니, 서비스를 유지보수할 시간도 줄어들게 되었고, 집 근처 오락실도 사라져서 주말에나 가끔 가서 게임하는 정도가 되었기도 하고, 게다가 옛날같이 투덱 말고 기타도라라든지 DDR이라든지, 집에서는 디맥 등... 즐길 거리들이 늘어나면서, 예전같이 제 스스로가 투덱을 하지 않게 되었습니다.

그리고 언제부터인가 투덱 곡에 클리어 레이트가 같이 표시되더라고요? 사실상 불렙 여부를 알려주는 지표다 보니, 굳이 서열표를 열심히 볼 이유 또한 사라지게 되었습니다. 클리어 레이트 보고서 하드게이지 걸지 이지게이지 걸지 대충 각이 나오니까요.

그러다 보니 저 스스로도 서비스를 자주 안 쓰게 되고, 자연스럽게 소홀해지게 되었습니다.

게다가 결정적으로 히로인 버스 이후에서 적용된 노트 라이다 그래프가 제가 원하던 기능을 들고 나왔습니다. 이거 있는데 굳이 서열표 왜 써요.

게다가 그동안 서비스를 잠정적으로 중지했던 투덱미 등의 서비스가 다시 재개되면서, 제가 굳이 서비스를 더 해야 할 이유도 사라진 상태라서, 2022년 초 서비스 중단을 하기로 했습니다. 다행히도 쓰는 사람이 이제 없는지 별 이야기는 없는 것 같네요 ㅎㅎ.

별로 한 건 없는 것 같은데, 이렇게 글로 써놓고 보니 꽤나 하고 싶은 것들을 많이 했다는 생각이 듭니다.

만약 서비스를 유지한다면...

만약 제가 충분한 시간이 있었다면, 아마 아래의 작업을 더 진행할 수 있었을 것 같습니다.

  • NoSQL로의 전환
    불필요하게 RDBMS를 사용하여, 서버 리소스(메모리 및 CPU 모두)를 과도하게 점유했습니다.
    꼭 필요한 부분만 제외하고 서열표 DB 및 유저 정보를 모두 NoSQL로 바꿔야 했었습니다.
  • API와 웹 서비스의 분리
    먼저 두 기능이 전혀 의존성이 없기 때문에, 그것만으로도 충분히 분리할 이유가 됩니다.
    그리고 문제 상황 발생 시 적어도 한쪽의 서비스가 살아 있기 때문에 안정성을 보다 보장할 수 있으며, 동시에 문제의 원인을 보다 좁혀 찾아갈 수 있어 도움이 됩니다.
    마지막으로, 파이썬은 코어 로직(서열표 관련 작업)을 수행하기에 너무 느립니다 -_-;... 차후 기회가 된다면 Go+gRPC로 별도로 빼고 싶네요. 이것만으로도 서버 부하가 확 줄듯.
  • 프론트엔드를 SCSS+React 프레임워크로 교체
    이건 페이지 부하가 그렇게 심하지도 않을 뿐더러, 그냥 웹 트렌드 따라서 가는 거라 높은 우선순위는 아닌데 (...) 그래도 비동기 데이터 전달 측면이나, 유지보수 하는데 있어서 확실히 편할 것 같아 고려중입니다.
  • SVG 기반의 서열표 렌더링
    마찬가지로 이미지 렌더링은 접근성 문제가 있어 (곡 제목 복사 등...), 이를 해결하기 위한 조치로 생각하고 있습니다.
  • Auto deployment + 모니터링 툴 붙이기
    문제 상황 발생 시 자동으로 대처함과 동시에 원인 분석을 위해서 필요할 것 같습니다.

서버 규모나 기대 트래픽 자체가 몹시 작기 때문에, 쿠버네티스 형태로 하면 좋겠지만 그렇게는 못할 것 같습니다.

이외에도 아직 충분히 해볼만한 게 많긴 한데, 지금은 제가 작업할 여력이 없네요. 😂

'개발 > Product' 카테고리의 다른 글

[개발회고록] LyricsMaster  (0) 2022.04.03
bmx2ogg 프로그램 - bms 파일을 음악파일로 변환  (0) 2015.12.25
안드로이드 BMS 에디터 - sabuneditor  (2) 2014.07.13
LR2Server  (4) 2014.01.15
DCImageRename  (0) 2013.08.25