기본 소개
Redis 주문 세트도 세트와 마찬가지로 문자열 형식 요소의 모음이며 중복된 멤버는 허용되지 않습니다.
차이점은 각 요소가 이중 유형 점수와 연관되어 있다는 것입니다. Redis는 점수를 사용하여 컬렉션의 구성원을 작은 것부터 큰 것까지 정렬합니다.
주문한 세트의 구성원은 고유하지만 점수는 반복될 수 있습니다.
세트는 해시 테이블을 통해 구현되므로 추가, 삭제, 검색의 복잡성은 O(1)입니다. 컬렉션의 최대 구성원 수는 2^32 - 1^(4294967295, 각 컬렉션은 40억 개 이상의 구성원을 저장할 수 있음)입니다.
주문한 세트는 우선 세트이며, 그 멤버는 고유합니다. 둘째, 각 멤버는 점수와 연관되어 있으므로 점수에 따라 멤버를 정렬할 수 있습니다.
요구 사항 설명
게임에 수백만 개의 플레이어 데이터가 있다고 상상해 보세요. 이제 플레이어의 경험치를 기준으로 상위 10위 순위를 집계해야 한다면 어떻게 하시겠습니까? 일반적인 접근 방식은 다음과 유사한 SQL 문을 작성하여 얻는 것입니다.
select * from game_socre order by score desc limit 0,20
이 방법은 데이터의 양이 적을 때 가능하지만, 데이터의 양이 클 경우 쿼리 속도가 느려집니다. 특히 데이터 양이 많을 경우에는 공동 테이블 쿼리가 필요할 때 속도가 더욱 확연히 떨어집니다.
Implementation
이제 Redis를 사용하여 이 기능을 구현하는 것을 고려할 수 있습니다.
이 기능을 구현하는 데 사용되는 주요 Redis 데이터 유형은 Redis Ordered Set zset입니다. zset은 원래 유형보다 시퀀스 속성이 하나 더 많은 세트 유형의 확장입니다. 이 속성은 데이터가 삽입될 때마다 순서 값을 자동으로 조정하여 값 값이 특정 순서로 연속적으로 정렬되도록 합니다.
주요 구현 아이디어는 다음과 같습니다.
1. 새로운 플레이어가 게임에 참여하면 redis의 zset에 새 기록을 추가합니다(기록 내용은 특정 요구 사항에 따라 다름). .플레이어가 경험치 값을 변경하면 플레이어의 점수 값을 수정합니다
3. redis의 ZREVRANGE 메소드를 사용하여 순위 목록을 가져옵니다
순서된 세트 키에 지정된 범위의 멤버를 반환합니다. 멤버들의 순위는 점수가 높은 순서대로(큰 것부터 작은 것까지) 정렬됩니다. 동일한 점수 값을 가진 구성원은 사전순으로 정렬됩니다. ZREVRANGE 명령은 점수 값이 감소하는 순서로 멤버가 정렬된다는 점을 제외하면 ZRANGE 명령과 동일합니다.
redis 127.0.0.1:6379> ZADD KEY_NAME SCORE1 VALUE1.. SCOREN VALUEN
1. 데이터 준비
2. 상위 10위권 획득(ZREVRANGE는 내림차순, ZRANGE는 오름차순)
3. 사용자 ee의 실제 순위 보기(ZREVRANK) 는 내림차순, ZRANK는 오름차순) ), 실시간 점수
추가 요구최신 24시간 사용자 포인트 순위를 구현하고 상위 10명의 플레이어와 포인트를 계산해야 합니다
주요 구현 아이디어는 다음과 같습니다.ZADD를 사용하여 시간별 사용자 포인트 정보를 추가한 다음 ZUNIONSTORE 유니온을 사용하여 24시간 동안 총 게임 포인트를 달성하여 "24시간 순위 목록"을 달성합니다. 아이디어, 아래에 메시지를 남기고 조언을 주시면 더 좋을 것 같습니다.) )
ZUNIONSTORE destination numkeys key [key ...]
발생할 수 있는 문제
1. 동일한 점수의 문제Redis가 동일한 점수를 발견하면 자체 사전 순서에 따라 집합 멤버를 정렬합니다. 여기서는 두 개의 "user2"와 "user3" 문자열이 역순으로 정렬되면 당연히 user3이 먼저 순위가 지정됩니다. 이 문제를 해결하기 위해 점수에 타임스탬프를 추가하는 것을 고려할 수 있습니다.
타임스탬프가 있는 점수 = 실제 점수 * 10000000000 + (9999999999 – 타임스탬프) timestamp 시스템에서 제공하는 시간() 함수를 사용합니다. , 즉 1970년 1월 1일 이후의 초 수입니다. 우리는 32비트 타임스탬프를 사용합니다(2038년까지 지속될 수 있음). 32비트 타임스탬프는 10자리 십진 정수이므로(최대값은 4294967295) 타임스탬프를 하위 10비트(십진수)를 차지하여 실제 분수를 10^10배로 확장한 후 두 부분을 더한 결과를 zset의 분수로 사용합니다. 시간 역순으로 정렬한다는 점을 고려하면 타임스탬프 부분을 역순으로 정렬해야 하므로 9999999999에서 타임스탬프를 뺍니다. 플레이어의 실제 점수를 읽으려면 마지막 10자리만 제거하면 됩니다. 언뜻 보면 이 계획은 좋아 보이지만 두 가지 문제가 있습니다.첫 번째 문제는 사소한 문제입니다. 동일한 점수를 가진 두 개의 타임스탬프가 동일한 초에 나타나는 경우 초를 사용하면 충분히 구별되지 않을 수 있습니다. 물론 이전 문제가 발생할 수 있습니다. 하지만 실제 시나리오에서는 같은 순간에 누가 앞에 있는지는 중요하지 않습니다.
두 번째 문제는 큰 문제입니다. 왜냐하면 Redis의 분수형은 double을 사용하는데, 64비트 배정밀도 부동 소수점 수는 유효 자릿수가 52자리뿐이고, 정확하게 표현할 수 있는 정수 범위이기 때문입니다. - 2^53 2^53까지는 10진수 정수 16개까지만 표현할 수 있습니다. (최대값은 9007199254740992이며, 사실 16자리도 완전히 표현할 수 없습니다.) 즉, 이전 타임스탬프가 10자리를 차지하면 점수는 6자리만 갖게 되며 일부 리더보드 점수에는 충분하지 않습니다. 예를 들어 2015년 1월 1일부터 시작하여 타임스탬프 수를 줄이는 것을 고려할 수 있지만 여전히 몇 자릿수만 추가됩니다. 또는 구별을 줄이고 분과 시간을 타임스탬프 단위로 사용합니다.
Redis의 점수 유형이 int64라면 위와 같은 문제는 발생하지 않습니다. 실제로 Redis는 추가 int64 유형 ZSet을 제공해야 하지만 현재는 소스 코드를 변경하지 않는 한 환상에 불과할 수 있습니다.
PHP 관련 지식을 더 보려면 PHP中文网을 방문하세요!
위 내용은 PHP+Redis는 24시간 순위의 실시간 업데이트를 달성하기 위해 컬렉션을 주문했습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!