Redis는 외부 세계에 5개의 캡슐화된 객체만 제공하기 때문에 정수 컬렉션에 대해 들어본 적이 없는 학생들도 있을 것입니다! 이전에는 Redis 내부 구조에서 Redis의 3가지 데이터 구조인 List, Hash, Zset을 분석했습니다. 오늘은 설정된 데이터 구조가 내부적으로 어떻게 저장되는지 분석해 보겠습니다.
src/t_set.c에서 우리는 이러한 코드 조각을 발견했습니다
이로부터 우리는 집합이 해시테이블+인트셋이라는 두 가지 데이터 구조로 구성되어 있다는 것을 알 수 있습니다. 그 밖의 redis 내부 구조에 대해서는 [redis 칼럼]에서 구체적으로 소개한다. Hashtable은 오늘날 우리의 주인공이 아닙니다. 오늘 우리는 일반적으로 정수 집합으로 알려진 intset을 먼저 분석합니다.
위 그림에서 볼 수 있듯이 [commonset]과 [cs]라는 두 개의 세트 컬렉션을 구성했습니다. 전자는 문자열을 저장하고 후자는 숫자를 저장합니다.
객체 인코딩 키를 통해 다음 두 컬렉션의 기본 데이터 구조를 살펴보니 하나는 해시테이블이고 다른 하나는 intset인 것을 발견했습니다. 이는 또한 위 세트의 기본 구조에 대한 설명을 확인합니다.
redis에서 외부적으로 제공되는 5가지 주요 유형은 실제로 redisobject라는 redis의 추상 객체입니다. 우리 Redis의 내부 데이터 구조는 내부적으로 매핑됩니다
commonset과 cs 컬렉션의 내부 데이터 구조는 이렇게 이해하면 됩니다
간단히 생각하면 됩니다. 숫자입니다. intset 구조는 저장에 사용됩니다. 뺨을 때릴 것 같습니다. 사실 그렇지 않습니다
다음 두 가지 조건이 동시에 충족되어야 합니다.
그림을 보면 세 가지 값이 아주 명확하게 나와 있습니다. 콘텐츠의 저장을 나타내는 intset 인코딩용입니다. 여기 누군가 질문이 있을 수 있습니다. 콘텐츠 유형이 int8_t 아닌가요? 인코딩이 왜 필요한가요? 여기서 추적하는 소스 코드는 int8_t와 관련이 없습니다. 그리고 기본 데이터 유형은 int16_t입니다. 여기서 길이에 대해 너무 많이 설명할 필요는 없습니다. 콘텐츠 요소의 개수는 콘텐츠 배열의 길이를 나타내지 않는다는 점을 기억하세요!
intset을 아는 학생들은 인코딩의 세 가지 값 범위에 업그레이드 작업이 포함된다는 것을 모두 알고 있습니다! 업그레이드에 대해 이야기하기 전에 먼저 C 및 C++에서 int의 값 범위가 어떻게 정의되는지 이해하겠습니다.
int8_t의 값 범위는 [-128,127]입니다. Java의 바이트와 유사하게 1바이트는 8비트입니다. 그의 가치 범위는
[-2^{7} sim 2^{7}-1 \
, 즉 \입니다.
-128 심 127
]
sadd juejin -123 sadd juejin -6 sadd juejin 12 sadd juejin 56 sadd juejin 321
juejin 이 키는 내부적으로 intset되어 있습니다.
위에서 5개의 요소를 추가했는데 이 5개 요소의 길이가 모두 16개 이내입니다! 따라서 현재 intset의 인코딩은 INTSET_ENC_INT16입니다. -123이 컨텐츠 상위 16위를 차지하고 있습니다.
따라서 콘텐츠의 현재 5개 요소의 길이는 16*5=80입니다.
set가 int형 데이터를 저장할 때 작은 것부터 큰 것 순서대로 내부에 저장된다는 점에 유의하세요.
위 질문을 생각해 보셨는지, 또는 접해 보셨는지 모르겠습니다! Intset의 기본값은 위에서 추가한 5개 요소와 마찬가지로 int16비트입니다. 이때 우리가 추가하는 여섯 번째 요소는 65535(32비트)이다. 그렇다면 16비트의 길이가 저장하기에 충분하지 않은 이때 intset은 무엇을 할 것인가?
그리고 6번째 요소를 추가하고 65535를 삭제하면 추가하기 전과 구조가 같나요? 아래에서 두 가지 질문을 살펴보겠습니다! ! !
먼저 첫 번째 질문부터 살펴보겠습니다. 5개 요소가 모두 16비트인 것으로 밝혀졌고, 이때 추가된 65535의 길이는 32비트이다. 그렇다면 65535에 32비트를 직접 추가할 수 있습니까?
답은 절대 그렇지 않습니다. 우선 직접 추가하는 것은 배열 요소의 순서를 보장할 수 없습니다. 둘째, 처음 5개가 각각 16비트이고 여섯 번째가 32비트인 경우 intset 구조에 표시할 추가 필드가 없습니다. 즉, 파싱 중에 16비트인지 32비트인지 판단하는 것은 불가능합니다.
파싱을 용이하게 하기 위해 redis는 긴 길이가 추가되면 전체 내용을 업그레이드합니다. 전체 내용을 먼저 확장한 다음 데이터를 다시 채우고
65535
을 추가한다는 의미입니다. 먼저, 길이에 따라 확장 후 요소 수는 6개이며 각 요소는 다음과 같습니다. 점유인원은 32이므로 내용의 길이는 32*6=192입니다. 이때 콘텐츠의 처음 80비트는 변경되지 않은 상태로 유지됩니다.
오래된 데이터 이동
충분한 공간이 확보된 후 이전 데이터를 이동할 수 있습니다. 여기서는 원래 배열의 끝에서 이동을 시작합니다. , 에서 이동하기 전에 새 배열의 정렬 위치를 알아야 합니다.
이때, 먼저 321을 비교하여 그의 순위가 새로운 배열에서 5위인지 확인한 다음, 그는 새로운 콘텐츠에서 128~159 범위를 차지하게 됩니다.
마지막으로 처음 5개 요소가 이동됩니다.
마지막으로 새로 추가된 요소를 채워주세요. 업그레이드가 발생하는 경우 새 요소의 길이가 원래 길이보다 길어야 합니다. 그런 다음 해당 값은 새 배열의 양쪽 끝에 있어야 합니다. 음수는 맨 왼쪽, 양수는 맨 오른쪽
그러면 두 번째 질문이 나옵니다. 이때 새로 추가된 65535가 다시 삭제되면 Redis는 어떻게 해야 할까요? 16비트로 만족하지만 현재 인코딩은 32비트입니다. 제 생각에는 다운그레이드되어야 한다고 생각합니다!
하지만 아쉽게도 redis에는 없는데 왜 없는지 생각해 보세요. 구현하라고 했다면 어떻게 구현하겠습니까
추가된 요소가 현재 길이를 초과하면 이때 업그레이드 작업이 필요하다는 것을 쉽게 알 수 있지만, 다운그레이드가 필요한지 어떻게 판단할 수 있습니까? 나머지 요소가 현재 길이보다 작은지 확인하기 위해 다시 탐색해야 하므로 복잡도는 O(N)입니다. 이게 다운그레이드가 안되는 이유 중 하나입니다
역순이 빠르고 어차피 메모리에 있다고 할 수 있는데, 다운그레이드 후 업그레이드 상황이 발생하면 이렇게 왔다 갔다 하는 업그레이드와 다운그레이드하면 프로그램 성능이 저하됩니다. 업그레이드가 필요하다는 것을 알고 있으므로 여기에서 Redis를 다운그레이드하는 전략은 이를 무시하는 것입니다
관련 튜토리얼 권장 사항:Redis 튜토리얼
위 내용은 Redis 정수 세트를 다운그레이드할 수 없나요? 왜?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!