실시간 랭킹 계산...

peccavi의 이미지

안녕하세요..

유저들이 게임한 결과(스코어)를 가지고

실시간 랭킹을 보여줘야 하는데...

마땅한 방법이 생각이 안나네요..

일단, 생각해본게

게임에서, 한판이 끝나면 결과창에 보여주는 랭킹은

게임서버가
select count(score) from gamedata where score > 5000(유저 스코어)

뭐 이런식으로 쿼리를 날리려고 하는데요..

부하가 장난 아닐것 같네요..

좋은 방법 알고계신분, 한수 지도 부탁드립니다.. (__)

정태영의 이미지

peccavi wrote:
select count(score) from gamedata where score > 5000(유저 스코어)

뭐 이런식으로 쿼리를 날리려고 하는데요..
부하가 장난 아닐것 같네요..

인덱스를 제대로 탄다면.. 저정도는.. 부하가 거의 걸리지 않습니다 :)

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

leilei의 이미지

디비를 못 믿으시겠다면 간단히 미들웨어를 하나 만드심도 좋을 것 같네요. :)

그런데.. 어자피 방금한 결과를 반영해서 랭킹을 구해야 하니 별차이가 없지 않을까요? 인텍싱만 잘 되어 있다면 충분히 빠르리라는데 저도 한표 !

Jun92의 이미지

인덱스 잘 타구 옵티마이즈 잘 되어 있다면 어느정도까지는 견디겠습니다만,

혼자하는 게임도 아니고, 몇천 몇만이 사용할 가능성도 고려한다면
안심하기는 힘들듯합니다.

현실적으로 그런 랭킹 데이타는 실시간보다는 주기적으로 계산을 해서
캐쉬하고 있다가 요청이 오면 보내주는 형식으로 합니다. 길게는 하루
에서부터 짧게는 1분정도로..

참고로 이전 회사에서 미친척하고 한번 해 봤던 짓은 랭킹 서버를 하나
만들어서 실제 사용자의 승패 결과를 실시간으로 랭킹 서버로 보내구
랭킹 서버는 실제 사용자승패 정보를 다 메모리에 올려서.. -.-;;; 소켓을
통해서 몇등부터 몇등까지 정보를 보내구 그랬었습니다. 램을 좀
많이 집어넣었죠... 쩝.. 이것두 가입 사용자가 많아지면 대략 낭패가
되는 솔루션이었습니다. 그당시 가입자가 약 100만이었구요..
다행히도 100만됐을때 그 게임의 다음버젼이 나와서... ^^;

=============================
야후!

liongo의 이미지

제가보기엔 천만건 이하라면 그냥 인덱스 잘타게 해서 쓰시고요..

천만 이상이거나 요청이 많아서 서버가 못버틴다면.. 중간에 게이트웨이를둬서

순위를 항상 캐쉬하게 하면 될것같습니다.. 캐쉬서버는 주기적으로

디비를 읽어서 업데이트를 하고.. 클라이언트의 응답은 캐쉬가 가진

데이타를 주는것이 좋겠습니다.. 모 귀찬으시다면 디비 튜닝을 하셔서

해결하셔되 됩니다만 비슷한 노력이 들것같습니다.. :twisted:

' 형식이 내용을 규정한다. '

peccavi의 이미지

좋은 의견들 감사드립니다..

Jun92님 말씀처럼 저도 랭킹서버를 따로 두는것도 생각을 해봤는데요.. 이런식이었죠..

1. 랭킹서버는 유저들의 모든 스코어를 DB에서 읽어와 메모리에 보관하고 있는다(1시간 등 주기적으로)

2. 게임서버는 유저들의 게임이 끝날때마다 랭킹서버로 랭킹 계산을 요청한다.

3. 랭킹서버는 요청된 유저의 스코어를 메모리에 갱신하며 그 유저의 랭킹을 뽑아낸 후 게임서버로 전송한다.

4. 게임서버는 랭킹서버의 응답이 오면 유저들에게 게임 결과 화면을 전송한다.

대충 이럴 생각이었는데
select count 쿼리가 그다지 부하가 걸리지 않으면 간단하게 해결할 수도 있을것 같네요..
(근데 문제가, 현재 게임서버 내의 게임처리 부분이 단일스레드라는...)
테스트를 해보는게 제일 좋을텐데 시간이 없네요..

답변 감사드리구요, 좋은 주말 보내세요~

----
jai guru deva om...

bugiii의 이미지

모든 스코어를 읽어온다음 (사용자 계정과 연결시킬 필요없이) vector에 넣습니다.

소팅합니다.

검색해서 찾은 위치를 순위로 합니다. (항상 소팅되어 있으므로 binary_search 류의 stl 알고리즘 이용)

게임이 끝나면 이전 점수를 vector 에서 빼고 새 점수를 삽입합니다.

다시 소팅합니다.

이렇게 했습니다. 빠르더군요...

정태영의 이미지

bugiii wrote:
모든 스코어를 읽어온다음 (사용자 계정과 연결시킬 필요없이) vector에 넣습니다.
소팅합니다.

검색해서 찾은 위치를 순위로 합니다. (항상 소팅되어 있으므로 binary_search 류의 stl 알고리즘 이용)

게임이 끝나면 이전 점수를 vector 에서 빼고 새 점수를 삽입합니다.
다시 소팅합니다.
이렇게 했습니다. 빠르더군요...

데이타베이스에서 인덱스가 걸린 것들은..
따로 정렬되어 저장되기 때문에.. :D

데이타베이스를 이용하면.. 구지 전부 읽어올 필요도 없고..
정렬을 따로 할 필요도 없습니다 흐흐흐

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

fibonacci의 이미지

포트리스 랭킹이 기억나는군요.

예전에 1000등 가까이 가본적은 있는데 (왠 딴소리 -_-; )

사용자가 많으면 실시간은 쿨럭.. 힘들지도.

No Pain, No Gain.

bugiii의 이미지

네 DB 를 이용할 수도 있겠지만요... 오직 스코어에 의한 랭킹만 필요하다면 점수만 소팅해도 소기의 목적을 달성할 수 있습니다.

점수에 인덱스주기도 뭐하고... 사용하는 DB 가 오라클정도라면 row 가 있어서 바로 되겠지만 PostgreSQL 을 사용하고 있는 실정이라... 좀...

angpoo의 이미지

심심해서 DB만으로 백만건을 넣어 실행해봤더니 대략
하위 10%: 1초
상위 10%: 0.1초
상위 1% : 0.01초
이정도 걸리는군요.
인덱스를 타더라도 where score > xxx면 나름데로 시간이 걸릴 수 밖에 없을듯 하네요.

사용자 규모뿐 아니라 점수 변동이 얼마나 빈번한지 점수분포가 어떻게 되는지에 따라서 다른 해결책이 달라 질것 같습니다.

hb_kim의 이미지

DB 에 전혀 지식이 없는 저로써는 몇몇 용어를 이해할수가 없네요.

인덱스를 탄다는 말이 무슨 뜻인가요?

bugiii의 이미지

SQL 쿼리시 DB 가 where 절의 조건을 검색할 때, 주어진 컬럼에 인덱스가 있다면 검색에 그 인덱스를 사용한다는 것입니다.

인덱스를 사용해서 검색을 빠르게 하도록 한다는 은어(?)라고 알고 있습니다.

인덱스가 없으면 처음부터 하나 하나씩 읽어서 비교해야 하니까 이런 풀 스캔은 시간이 많이 걸린다고 합니다.

그래서 SQL 쿼리 문장을 만들 때 인덱스를 타는지(!) 항상 검사해보는 습관을...

그렇다고 모든 컬럼에 인덱스를 만들었다가는 욕먹겠죠. 모든게 그렇듯이 넘치면 모자람만 못하는... 인덱스가 검색할 때에는 빠르게 해주지만 삽입이나 삭제는 인덱스를 건드려야 하니까 속도가 떨어지고 용량이 늘어나게 된다고 하더군요.

p.s. 글 쓰신 시간이 3:52 이라면... 축구 했었나요?

atie의 이미지

bugiii wrote:

그렇다고 모든 컬럼에 인덱스를 만들었다가는 욕먹겠죠. 모든게 그렇듯이 넘치면 모자람만 못하는... 인덱스가 검색할 때에는 빠르게 해주지만 삽입이나 삭제는 인덱스를 건드려야 하니까 속도가 떨어지고 용량이 늘어나게 된다고 하더군요.

전 DBA는 아니지만, 한 테이블에 5개 정도까지는 적절하다고 알고 있습니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

차리서의 이미지

atie wrote:
bugiii wrote:

그렇다고 모든 컬럼에 인덱스를 만들었다가는 욕먹겠죠. 모든게 그렇듯이 넘치면 모자람만 못하는... 인덱스가 검색할 때에는 빠르게 해주지만 삽입이나 삭제는 인덱스를 건드려야 하니까 속도가 떨어지고 용량이 늘어나게 된다고 하더군요.

전 DBA는 아니지만, 한 테이블에 5개 정도까지는 적절하다고 알고 있습니다.


저는 아예 문외한에 가깝지만, 단편적인 경험이나마 이야기해보자면 '어떤 특성의 필드'냐도 중요한 것 같습니다.

primary key를 포함해서 2~3 개의 정수 혹은 문자열 필드에 인덱스를 걸어서 상당히 빨라졌던 테이블이 있었습니다. 이 중 한 필드는 primary key니까 당연히 unique, not null하고 (cardinality = 레코드 수), 나머지는 레코드 수의 10~30% 정도의 cardinality를 갖고 있는 not null 필드들이었습니다. 나중에 욕심을 부려서 레코드 수의 70% 남짓 되는 cardinality를 갖고 있던 not null 문자열 필드에 인덱스를 걸었다가 죽는 줄 알았습니다. 이유는 잘 모르겠지만 무지막지하게 느려지더군요. 검색할 때에도 말이죠. (where 항목에 별다른 특별한 것도 없이 해당 필드에 대한 '=' 연산 하나랑 잡다한 것 한두개만 더 있는 단순 select였습니다.)

당시 DBMS는 MySQL 3.23.x였습니다. 혹시 이런 특성에 관해 더 자세히 아시는 분이 계시면 저도 설명을 조금 듣고싶습니다. DB 최적화에 관한 제 지식은 거의 '전무'합니다.

--
자본주의, 자유민주주의 사회에서는 결국 자유마저 돈으로 사야하나보다.
사줄테니 제발 팔기나 해다오. 아직 내가 "사겠다"고 말하는 동안에 말이다!

nohmad의 이미지

유지해야 할 탑 랭킹 스코어의 개수가 일정하다면--예를 들어 상위 5000위까지의 순위 정보(플레이어, 스코어)만 유지한다고 할 때--, 직접 트리를 구현해도 좋을 것 같군요. 제일 낮은 순위의 리프와 비교하여, 크다면 그놈을 내보내고 적당한 노드에 삽입, 주기적으로 균형을 맞추고 등등... 실은 회사일로 제 뒷자리의 사람이 이틀 동안 작업해서 구현했다고 하더군요. :)

Seven..의 이미지

상위 몇명의 랭킹만 보여주면 되는거라면..

where로 받아와서 따로 소팅 하는거보다
점수에 인덱스를 추가하고
order by.. limit 몇개 이렇게 뽑아오는 거가 더 낳을 듯 하네요..
인덱스가 있다면 전체 스캔을 할 필요가 없으니까..

점수를 primary key로 줄 수는 없는 노릇이고..
cluster는 힘들어도..
인덱스로 걸어놓으면..

그정도의 쿼리라면.. row에 해당하는 field의 크기에 연관을 받을 수도 있지만
단지 점수와 이름 시간 등 정도라면

초당 백건에서 천건사이로 무리 없이 되지 않을까 생각합니다만..

VENI VIDI VICI

Seven..의 이미지

추가로 primary 인덱스가 아닌경우..

인덱스를 타게 되는 데이타 량이..

전체의 10%가 넘는다면.. 예를들어

User.age가 unclustered index라면..

select count(*) from User U where U.age>10

이런 쿼리는 때로 인덱스가 없는 경우보다 오래 걸릴 수도 있다고 알고 있습니다.

옵티마이저의 역할이긴 하지만..

여러 where절이 있다던가, sub query에서는 옵티마이저가..

월등히 약해지는 면모를 보이기도 하고..

인덱스를 만들때는 앞으로 날릴 쿼리가 뭔지

어떤 쿼리가 자주 나오고 어떤 쿼리가 오래걸리는지 그 중요성은 얼마인지

계산해봐야겠죠^^

VENI VIDI VICI

소타의 이미지

partial index 를 만드세요...
인덱스의 범위마다 총 합계를 구해놓고 부분인덱스를 타게끔 하면 아마 DBMS로 구현할 수 있는 가장 빠른 방법이 될 듯 싶습니다.
데이터의 분포를 잘 계산해야 하겠네요. 분포가 변함에 따라 인덱스를 다시 만들고 범위를 재설정 해야 하는 불편함도 있겠지만 가끔씩만 해줘도 되니 자동화 해놓으면 괜찮을듯..

hb_kim의 이미지

bugiii wrote:
SQL 쿼리시 DB 가 where 절의 조건을 검색할 때, 주어진 컬럼에 인덱스가 있다면 검색에 그 인덱스를 사용한다는 것입니다.

인덱스를 사용해서 검색을 빠르게 하도록 한다는 은어(?)라고 알고 있습니다.

인덱스가 없으면 처음부터 하나 하나씩 읽어서 비교해야 하니까 이런 풀 스캔은 시간이 많이 걸린다고 합니다.

그래서 SQL 쿼리 문장을 만들 때 인덱스를 타는지(!) 항상 검사해보는 습관을...

그렇다고 모든 컬럼에 인덱스를 만들었다가는 욕먹겠죠. 모든게 그렇듯이 넘치면 모자람만 못하는... 인덱스가 검색할 때에는 빠르게 해주지만 삽입이나 삭제는 인덱스를 건드려야 하니까 속도가 떨어지고 용량이 늘어나게 된다고 하더군요.

p.s. 글 쓰신 시간이 3:52 이라면... 축구 했었나요?


친절한 설명 감사드립니다.
게임에 관련된 주제인것 같아 들어와 보았다가 여러가지 배우고 가네요.

<- 제 위치에서는 그때가 점심시간이랍니다.

atie의 이미지

차리서 wrote:

primary key를 포함해서 2~3 개의 정수 혹은 문자열 필드에 인덱스를 걸어서 상당히 빨라졌던 테이블이 있었습니다. 이 중 한 필드는 primary key니까 당연히 unique, not null하고 (cardinality = 레코드 수), 나머지는 레코드 수의 10~30% 정도의 cardinality를 갖고 있는 not null 필드들이었습니다. 나중에 욕심을 부려서 레코드 수의 70% 남짓 되는 cardinality를 갖고 있던 not null 문자열 필드에 인덱스를 걸었다가 죽는 줄 알았습니다. 이유는 잘 모르겠지만 무지막지하게 느려지더군요. 검색할 때에도 말이죠. (where 항목에 별다른 특별한 것도 없이 해당 필드에 대한 '=' 연산 하나랑 잡다한 것 한두개만 더 있는 단순 select였습니다.)

당시 DBMS는 MySQL 3.23.x였습니다. 혹시 이런 특성에 관해 더 자세히 아시는 분이 계시면 저도 설명을 조금 듣고싶습니다. DB 최적화에 관한 제 지식은 거의 '전무'합니다.


여기에 답변을 정확하게 해 드리는 것은 무리일 것 같고요, 단순하게 일반적으로 대답을 드린다면, 우선은 index를 스토리지 상에 쓸 때 쓰는 양이 많아졌다는 것과 이것이 띄엄띄엄 쓰여질 수도 있다는 것, 중복되는 데이타가 많으면 btree등의 구성으로 인덱스를 만들때 검색 속도가 현저히 늘려질 수 있다는 것 등의 이유가 될 수 있을것 같은데...DBMS마다 다를 수 있으니 꼭 집어 이거라고는 못하겠습니다. 위의 답변에도 언급이 되었지만 5% - 15% 정도의 data가 인덱스를 타는 것이 가장 효율에서 좋다고 하는 것도 염두에 두어야 할 것 같고요.

----
I paint objects as I think them, not as I see them.
atie's minipage

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.