본문 바로가기

MY개발생각

[개발생각] 공포의 주간랭킹 개발하기

프로젝트에서 주간랭킹을 개발해야했다...이게 공포가 될줄이야... 생각할께 너무 많아서 머리가 아픈적은 처음이네 ㅠ

 

여러 이벤트를 이용해 경험치를 유저가 획득하고,

주간으로 획득한 경험치 순으로 주간 랭킹을 구해야 한다는 개발요건이다.

(쉽지??...ㅎㅎ)

그런데... 여기서 끝나는게 아니고,

 

조건이 몇가지 더있다!!!

 

1) 회원 전체 대상 랭킹이 아닌, 소규모로 그룹을 나누고 그 그룹안에서의 랭킹.

2) 소규모 그룹을 나누는 기준은 랜덤.

3) 해당 기준은 주마다 매번 달라야함 (즉, 주마다 랜덤을 섞여야함)

 

이렇게 3가지 조건이다.

 

물론, 단순하게 생각을 하면 뭐 이게 뭔 고민을 할꺼리인가? 라고 생각할수도있다.

하지만, 이 기능은 고민을 하지않고 만들게 되면, 큰 성능상의 문제를 발생할 여기가 다분하게 있다.

 

우선 단순하게 생각하면)

전체 회원 대상으로 주의 시작시점에 배치로, 그룹을 지어주고, 해당 그룹정보를 테이블로 가지고 있으면, 깔끔하게 동작하긴한다.

 

여기서 문제가  발생한다...

만약, 회원이 늘어서 10만, 20만, 100만이 되면, 그때는 그룹을 실제로 생성하여 테이블로 스냅샷을 떠서 사용하는 방식은

성능상으로 문제가 발생하게된다.

주마다 100만명의 소그룹 정보가 쌓이게되고, 주의 시작마다 100만명을 대상으로 스냅샷을 만들어야 하니,

비효율적이다.

 

어떻게 해야할까? 생각을 해봤다.

 

스냅샷을 만드는 방식이 아닌,

쿼리를 통해 실시간으로 그룹을 정해서 소규모그룹리스트를 바로 뽑을수있는 방식을 고민해야겠다고 결정했다.

 

그러기 위해서는 몇가지 상수의 결정과 조건의 정리가 필요했다.

 

1) 유저별 유니크한 상수값이 있어야 한다. 

- user_id를 사용하기로 결정했다. (해당 값은 자동증가하고 유저별 유니크한 값이기에 겹칠일이 없는 유니크한 상수이다)

 

2) 해당 주안에서는 변하지 않고, 주가 지나고 다음주에서는 변하는 값이 있어야 한다.

- year + weekOfYear을 조합하여 사용하기로 했다. (년도와 년안에서의 주의 차수를 조합하면 같은주안에서는 같은값이고, 다른주안에서는 다른값으로 변한다.) -> 이게 핵심이다.

 

3) 그룹의 회원을 섞는 방식이 있어야 한다. (랜덤값을 만들어야한다)

- user_id와 year와 weekOfYear값을 OR연산한 값을 md5 hashing한 값을 사용한다.

- 해당 값으로 그룹의 회원을 매주마다 다른기준으로 섞기위한 기준값을 만들수있다.

 

4) 어떻게 그룹핑을 할것인지 기준방식이 있어야 한다.

- 모듈러 연산을 이용한다. 위 3번에서 구한 md3 hasing값을 모듈러 연산을 통해, group_id를 구하고, 해당 group_id가 같은 유저별로 그룹을 만들도록 한다.

 

 

쿼리는 아래와 같이 사용한다.

 

select *

from  user

where

    abs(md5(user_id or year or weekOfYear) % 100 = :group_id

order by exp_point desc

 

여기서 핵심은 group_id를 쿼리를 통해서가 아닌 코드상에서도 구할수 있어야 한다는것이다.

 

즉, 사용자가 앱에 들어오면 해당 사용자의 user_id를 이용해서 group_id를 코드로 구한다.

그리고 위 쿼리에서 group_id로 넘기면, group_id로 그룹핑된 사용자들 리스트를 구할수있기 때문이다.

 

모듈러 연산의 100은 전체 회원을 100개의 그룹으로 나눈다는 의미이다.

따라서, 전체 회원수를 구하면 전체회원수를 몇명정도로 그룹지울지를 계산하여 100이라는 기준값을 정하면,

좀더 정교하게 그룹수를 지정할수도 있다.

 

우선 기본 설계는 이렇게 마무리 했고, 정상적으로 잘동작하는것도 확인을 하였다.

스냅샷을 유지하지않고, 바로 주마다 달라지는 소규모 랜덤 그룹을 쿼리만을 통해, 조회할수있게 되었다.

 

이제는 쿼리의 튜닝 (인덱스를 잘타게 하는 방식)과 그룹핑된 리스트를 캐싱하여,

재사용하는 방법만 더하면,

얼추 구현이 완료될듯하다...

 

ㅠㅠ 힘들었는데, 이런걸 고민하고 설계하는 맛이 또, 개발자의 맛이지 않을까?!!