Redis 의 String 장르 가 일 으 킨 참사

7089 단어 RedisString유형
이런 사례 를 본 적 이 있 는데 한 팀 은 이미지 저장 시스템 을 개발 해 야 한다.이 시스템 이 이미지 ID 와 이미지 저장 대상 ID 를 신속하게 기록 할 수 있 도록 요구 하 는 동시에 이미지 의 ID 에 따라 이미지 저장 대상 ID 를 신속하게 찾 을 수 있어 야 한다.저 희 는 10 자리 수로 이미지 ID 와 이미지 저장 대상 ID 를 표시 한다 고 가정 합 니 다.예 를 들 어 이미지 의 ID 는 1101021043 이 고 이에 대응 하 는 이미지 저장 대상 의 ID 는 2301010051 입 니 다.이미지 ID 와 이미지 저장 ID 가 일일이 대응 하 는 전형 적 인 key-value 형식 이기 때문에 먼저 String 형식 으로 데 이 터 를 저장 할 생각 입 니 다.그림 ID 와 그림 저장 ID 를 각각 키 쌍 의 key 와 value 로 저장 합 니 다.그러나 저 장 된 데 이 터 량 이 점점 커지 면서 레 디 스 의 메모리 사용량 도 빠르게 늘 어 나 면서 큰 메모리 레 디 스 인 스 턴 스 가 RDB 생 성 으로 인해 응답 이 느 려 지 는 문제 에 부 딪 혔 다.String 타 입 이 좋 은 선택 이 아 닌 것 은 분명 합 니 다.
그럼 메모리 소 모 를 줄 일 수 있 는 방법 이 있 습 니까?
String 형식의 데이터 구조
우선 String 이 데 이 터 를 저장 할 때 소모 하 는 메모리 공간 이 왜 큰 지 알 아야 합 니 다.방금 사례 에서 이미지 ID 와 이미지 저장 대상 ID 가 모두 10 자리 이기 때문에 우 리 는 8 바이트 의 Long 유형 두 개 로 이 두 ID 를 표시 할 수 있다.따라서 그림 ID 와 저장 대상 ID 의 기록 은 실제 16 바이트 만 있 으 면 된다.그러나 Redis 메모리 분석 을 통 해 이미지 ID 와 저장 대상 ID 가 64 바이트 를 차지 하 는데 왜 String 형식 은 64 바이트 를 사용 합 니까?사실 실제 데 이 터 를 기록 하 는 것 외 에 String 유형 은 데이터 의 길이,공간 사용 정보 등 을 기록 하 는 추가 메모리 공간 이 필요 하 다.이런 정 보 를 메타 데이터 라 고도 부른다.실제 저 장 된 데이터 가 시간 에 비해 메타 데이터 의 공간 비용 이 비교적 크다.String 형식 이 데 이 터 를 어떻게 저장 하 는 지 살 펴 보 겠 습 니 다.64 개의 기호 가 있 는 정 수 를 저장 할 때 String 형식 은 8 바이트 의 Long 형식 정수 로 저장 합 니 다.이런 저장 방식 은 보통 int 인 코딩 방식 이 라 고도 합 니 다.단,저 장 된 데이터 에 문 자 를 포함 할 때 String 형식 은 간단 한 동적 문자열 구조 체(SDS)로 저 장 됩 니 다.다음 그림 에서 보 듯 이:
  • len:4 바이트,buf 의 사용 길 이 를 표시 합 니 다.
  • alloc:4 개의 바이트 는 buf 분배 의 길 이 를 나타 내 고 보통 len 보다 크다.
  • buf:바이트 배열,실제 데 이 터 를 저장 합 니 다.배열 의 끝 을 표시 하기 위해 Redis 는 자동 으로 배열 의 마지막 에'\0'을 추가 합 니 다.
  • SDS 구조 체 에 서 는 실제 데 이 터 를 저장 하 는 buf 외 에 len 과 alloc 의 추가 메타 데이터 비용 도 볼 수 있다.또한 String 유형 에 있어 SDS 의 추가 비용 외 에 RedisObject 구조 체 라 는 비용 도 있다.Redis 의 데이터 형식 이 매우 많 고 서로 다른 데이터 형식 은 모두 같은 메타 데 이 터 를 기록 해 야 하기 때문에(예 를 들 어 마지막 방문 시간)Redis 는 RedisObject 라 는 구조 체 를 사용 하여 이 메타 데 이 터 를 통일 적 으로 기록 할 것 이다.RedisObject 는 8 바이트 의 메타 데이터 와 8 바이트 의 지침 을 포함 하고 있 습 니 다.이 지침 은 String 형식의 SDS 구조 체 가 있 는 메모리 주 소 를 가리 키 고 있 습 니 다.다음 그림 에서 보 듯 이:

    메모리 공간 을 절약 하기 위해 Redis 는 Long 유형의 정수 와 SDS 의 메모리 레이아웃 을 전문 적 으로 설계 했다.한편,Long 형식의 정 수 를 저장 할 때 RedisObject 의 지침 은 정수 데이터 로 직접 할당 합 니 다.그러면 추가 지침 없 이 정 수 를 가리 키 고 지침 의 공간 비용 을 절약 할 수 있 습 니 다.다른 한편,문자열 데 이 터 를 저장 하고 문자열 이 44 바이트 보다 작 을 때 RedisObject 의 메타 데이터,포인터,SDS 는 연속 적 인 메모리 영역 으로 메모리 조각 을 피 할 수 있 습 니 다.이런 레이아웃 방식 도 embstr 인 코딩 방식 이 라 고 불 린 다.문자열 이 44 바이트 이상 이면 SDS 의 데이터 양 이 많아 지고 Redis 는 SDS 와
    RedisObject 는 함께 배치 되 어 SDS 에 독립 된 공간 을 할당 하고 SDS 구 조 를 포인터 로 가리 키 게 됩 니 다.이런 레이아웃 방식 은 raw 인 코딩 모드 라 고 불 린 다.다음 그림 에서 보 듯 이:

    이제 그림 ID 와 그림 저장 대상 ID 의 메모리 사용량 을 계산 해 봅 시다.10 자리 수의 이미지 ID 와 이미지 저장 대상 ID 는 Long 형식 정수 이기 때문에 int 인 코딩 의 RedisObject 로 직접 저장 할 수 있 습 니 다.이에 대응 하 는 RedisObject 메타 데이터 부분 은 8 바이트 이 고 포인터 부분 은 8 바이트 의 정수 로 직접 할당 되 었 습 니 다.이때 각 ID 는 16 바이트 로 합 쳐 모두 32 바이트 다.그런데 다른 32 바이트 가 어디 갔 지?
    Redis 는 전역 해시 표를 사용 하여 모든 키 쌍 을 저장 하기 때문에 해시 표 의 모든 항목 은 dictEntity 의 구조 체 로 키 쌍 을 가리 키 고 있 습 니 다.dictEntity 는 세 개의 8 바이트 지침 으로 구성 되 어 있 으 며,각각 key,value 와 다음 dictEntity 를 가리킨다.아래 그림 과 같다.

    Redis 가 사용 하 는 메모리 분배 라 이브 러 리 는 jemalloc 이기 때문에 jemalloc 는 메모 리 를 분배 할 때 신청 한 바이트 수 N 에 따라 N 보다 크 고 N 에 가장 가 까 운 2 의 멱 횟수 를 분배 하 는 공간 으로 찾 습 니 다.
    그래서 24 바이트 의 dictEntity 를 신청 하면 실제 32 바이트 가 분 배 됩 니 다.
    현재 위치 에 서 는 그림 ID 와 그림 저장 대상 ID 를 저장 하기 위해 String 형식 이 64 개의 바이트 를 차지 하 는 이 유 를 알 수 있 을 것 입 니 다.하나의 유효한 정 보 는 16 개의 바이트 에 불과 합 니 다.String 형식 으로 저장 할 때 64 개의 바이트 메모리 공간 을 차지 해 야 합 니 다.48 개의 바이트 가 메타 데이터 정 보 를 저장 하 는 데 사 용 됩 니 다.이것 은 메모리 공간 을 크게 낭비 하 는 것 이 아 닙 니까?그렇다면 메모리 절약 방법 은 없 을 까?
    압축 목록 으로 메모리 절약
    Redis 에는 압축 목록 이라는 구조 가 있어 메모 리 를 매우 절약 합 니 다.우 리 는 먼저 압축 목록 의 구성 을 되 돌아 보 았 다.표 머리 는 세 개의 필드 zlbytes,zllen 과 zltail 이 있 는데 각각 목록 의 길이,목록 끝의 오프셋 과 목록 중의 entry 의 개 수 를 나타 낸다.압축 목록 표 끝 에 zlend 가 있 습 니 다.목록 이 끝 났 음 을 표시 합 니 다.아래 그림 과 같다.

    압축 목록 은 일련의 entry 로 데 이 터 를 저장 하기 때문에 이 entry 는 메모리 에 하나씩 놓 여 있 습 니 다.추가 포인터 로 연결 하지 않 아 도 됩 니 다.그러면 포인터 가 사용 하 는 공간 을 절약 할 수 있 습 니 다.각 entry 는 아래 의 몇 부분 으로 구성 되 어 있다.
  • pre_len:앞의 entry 길 이 를 표시 합 니 다.prev_len 은 두 가지 수치 가 있 습 니 다.1 바이트 또는 5 바이트 입 니 다.이전 entry 길이 가 254 바이트 보다 작 을 때 prevlen 추출 값 은 1 바이트 입 니 다.그렇지 않 으 면 5 바이트 입 니 다.
  • len:자신의 길 이 를 나타 내 고 4 개의 바이트 를 차지한다.
  • encoding:인 코딩 방식 을 나타 내 고 1 바이트 를 차지한다.
  • content:실제 데 이 터 를 저장 합 니 다.
  • 만약 우리 가 entry 를 사용 하여 그림 저장 대상 ID(8 개의 바이트 차지)를 저장한다 면,이때,각 entry 의 prevlen 은 1 개의 바이트 만 차지 하면 됩 니 다.모든 entry 의 이전 entry 의 길 이 는 264 바이트 보다 작 기 때 문 입 니 다.이렇게 되면 하나의 그림 대상 ID 가 사용 하 는 메모리 크기 는 14(1+4+1+8)바이트 로 실제 16 개의 바이트 가 분 배 됩 니 다.
    Redis 에 서 는 압축 목록 을 기반 으로 List,Hash,Sorted Set 집합 형식 을 실 현 했 습 니 다.이렇게 하 는 가장 큰 장점 은 dictEntity 의 메모리 비용 을 절약 하 는 것 입 니 다.String 형식 에 있어 서 하나의 키 값 은 dictEntity 가 있 고 32 개의 바이트 가 있 습 니 다.집합 유형 에 있어 하나의 key 는 많은 데 이 터 를 대응 하지만 하나의 dictEntity 만 차지 하여 메모리 공간 을 절약 합 니 다.
    어떻게 집합 형식 으로 단일 값 의 키 값 이 맞 는 데 이 터 를 저장 합 니까?
    단일 키 값 이 맞 는 데 이 터 를 저장 할 때 Hash 형식 을 기반 으로 하 는 2 급 인 코딩 방식 을 사용 할 수 있 습 니 다.여기 서 말 하 는 2 급 인 코딩 은 단일 값 의 데 이 터 를 두 부분 으로 나 누고 앞부분 은 Hash 의 key 이 며 뒷부분 은 Hash 의 value 이다.그림 의 ID 는 1101021043 이 고 이에 대응 하 는 그림 저장 대상 의 ID 는 2301010051 입 니 다.저 희 는 그림 의 ID 앞 7 자리(1101021)를 Hash 형식의 키 로 하고,뒤 3 자리(043)와 그림 저장 대상 ID 는 2301010051 을 Hash 형식의 key 와 value 로 합 니 다.우 리 는 이러한 디자인 에 따라 Redis 에 하나의 기록 을 삽입 하고 16 바이트 만 차지 하기 때문에 String 형식 을 사용 하여 64 바이트 를 차지 하 는 것 과 비교 하여 많은 공간 을 절약 했다.마지막 으로,우 리 는 왜 그림 ID 의 앞 7 위 를 Hash 형식의 키 로 하고,뒤 3 위 를 Hash 형식의 키 로 해 야 하 는 지 다시 한 번 생각해 보 자.우 리 는Redis 메모리 구조에서 Redis 의 Hash 유형의 두 가지 바 텀 실현 구 조 를 소개 한 적 이 있 는데 그것 이 바로 압축 목록 과 해시 표 이다.Hash 형식 은 압축 목록 으로 데 이 터 를 저장 할 때의 두 개의 한도 값 을 설정 합 니 다.한도 값 을 초과 하면 Hash 형식 은 해시 표 로 데 이 터 를 저장 합 니 다.이 두 개의 한도 값 은 각각 다음 두 개의 설정 항목 에 대응 합 니 다.
  • hash-max-ziplist-entries:압축 목록 으로 저장 할 때 해시 집합 에서 가장 큰 요소 개 수 를 표시 합 니 다.
  • hash-max-ziplist-value:압축 목록 으로 저장 할 때 해시 집합 에서 단일 요소 의 최대 길 이 를 표시 합 니 다.
  • 메모리 공간 을 절약 하 는 데 있어 서 해시 표 는 압축 목록 만큼 효율 적 이지 않다.우 리 는 하위 3 자리 만 Hash 형식의 key 로 사용 하면 해시 집합 에 있 는 요소 의 개수 가 1000 을 넘 지 않도록 보장 합 니 다.또한 hash-max-ziplist-entries=1000 을 설정 하여 Hash 형식 바 텀 에서 사용 하 는 것 이 압축 목록 이라는 데이터 구 조 를 확보 합 니 다.
    레 디 스 의 한 스 트 링 장르 로 인 한 참사 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.레 디 스 트 링 장르 에 관 한 더 많은 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 읽 어 주시 기 바 랍 니 다.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기