String: Redis는 C 언어의 전통적인 문자열 표현을 직접 사용하지 않고 단순 동적 문자열 SDS라는 고유한 추상 유형을 구현합니다. C 언어의 문자열은 자체 길이 정보를 기록하지 않지만 SDS는 길이 정보를 저장하므로 문자열 길이를 O(N)에서 O(1)로 얻는 데 걸리는 시간이 줄어들고 버퍼 오버플로를 피하고 수정 필요성이 줄어듭니다. 문자열 길이에 필요한 메모리 재할당 수입니다.
연결된 목록: redis 연결 목록은 양방향 비순환 연결 목록 구조입니다. 많은 게시 및 구독, 느린 쿼리 및 모니터링 기능이 연결 목록을 사용하여 구현됩니다. listNode 구조. 각 노드 이전 노드와 후속 노드에 대한 포인터가 있으며, 헤더 노드의 이전 노드와 다음 노드는 모두 NULL을 가리킵니다.
사전 해시 테이블: 키-값 쌍을 저장하는 데 사용되는 추상 데이터 구조입니다. Redis는 기본 구현으로 해시 테이블을 사용합니다. 각 사전에는 일상적인 사용과 재해시를 위한 두 개의 해시 테이블이 있습니다. 해시 테이블은 키 충돌을 해결하기 위해 체인 주소 방법을 사용하며 동일한 인덱스 위치에 있는 여러 키-값 쌍에 할당됩니다. -way 연결 리스트가 형성되며, 해시 테이블을 확장하거나 축소할 경우 서비스 가용성을 위해 재해시 과정이 한꺼번에 완료되지 않고 점진적으로 완료됩니다.
건너뛰기 목록: 건너뛰기 목록은 순서화된 집합의 기본 구현 중 하나입니다. 건너뛰기 목록은 Redis에서 순서화된 집합 키와 클러스터 노드의 내부 구조를 구현하는 데 사용됩니다. Redis 스킵 테이블은 zskiplist와 zskiplistNode로 구성됩니다. zskiplist는 스킵 테이블 정보(헤더, 테일 노드, 길이 등)를 저장하는 데 사용됩니다. zskiplistNode는 테이블 스킵 노드를 나타내는 데 사용됩니다. 1부터. to 32. Number, 동일한 점프 테이블에서는 여러 노드에 동일한 점수가 포함될 수 있지만 각 노드의 구성원 개체는 점수의 크기에 따라 고유해야 합니다. 멤버 개체의 크기에 따라 정렬됩니다.
Integer set intset: 정수 값을 저장하는 데 사용되는 컬렉션 추상 데이터 구조입니다. 기본 구현은 배열입니다.
압축된 목록 ziplist: 압축된 목록은 메모리를 절약하기 위해 개발된 순차 데이터 구조입니다. 여러 노드를 포함할 수 있으며 각 노드는 바이트 배열 또는 정수 값을 저장할 수 있습니다.
이러한 기본 데이터 구조를 기반으로 redis는 문자열 객체 문자열, 목록 객체 목록, 해시 객체 해시, 컬렉션 객체 집합 및 정렬된 컬렉션 객체 zset를 포함하여 자체 객체 시스템을 캡슐화하며, 각각은 최소한 하나의 기본 데이터 구조.
redis는 인코딩 속성을 통해 객체의 인코딩 형식을 설정하여 유연성과 효율성을 향상합니다. Redis는 다양한 시나리오에 따라 자동으로 최적화합니다. 다양한 개체의 인코딩은 다음과 같습니다.
String 개체 문자열: int 정수, embstr 인코딩된 단순 동적 문자열, 원시 단순 동적 문자열
List 개체 목록: ziplist, linkedlist
해시 객체 해시: ziplist, hashtable
컬렉션 객체 세트: intset, hashtable
Ordered 컬렉션 객체 zset: ziplist, Skiplist
redis는 매우 빠릅니다. 단일 Redis는 초당 수만 개의 동시성을 지원할 수 있으며, mysql과 비교할 때 성능은 수십 배입니다. 빠른 속도의 주요 이유는 다음과 같습니다.
완전히 메모리 작업 기반
C 언어 구현, 최적화된 데이터 구조, 여러 기본 데이터 구조 기반, redis는 많은 최적화를 수행했으며 성능은 매우 뛰어납니다. high
단일 스레드 사용, 컨텍스트 전환 비용 없음
비차단 IO 다중화 메커니즘 기반
redis는 멀티스레딩을 사용합니다. 스레드는 단일 스레드를 완전히 포기하지 않습니다. Redis는 여전히 단일 스레드 모델을 사용하여 클라이언트 요청을 처리하며, 데이터 읽기 및 쓰기와 프로토콜 구문 분석을 처리하는 데에는 여전히 단일 스레드를 사용합니다.
이의 목적은 Redis의 성능 병목 현상이 CPU가 아닌 네트워크 IO에 있기 때문입니다. 멀티 스레딩을 사용하면 IO 읽기 및 쓰기 효율성이 향상되어 Redis의 전반적인 성능이 향상됩니다.
소위 핫키 문제는 Redis의 특정 키에 갑자기 수십만 건의 요청이 발생하는 것입니다. 이로 인해 트래픽이 너무 집중되어 물리적 네트워크 카드의 상한선에 도달하게 되어 Redis 서버가 충돌하고 눈사태를 유발합니다.
단축키 솔루션:
단축키를 미리 다른 서버에 분산시켜 부담을 줄이세요
두 번째 수준 캐시를 추가하고 redis가 다운된 경우 미리 단축키 데이터를 메모리에 로드하세요. , 메모리 쿼리로 가세요
캐시 분해의 개념은 단일 키의 동시 액세스가 너무 높다는 것입니다. 만료되면 모든 요청이 바로 db로 전송됩니다. 이는 단축키 문제와 유사합니다. 요점은 만료로 인해 모든 요청이 DB에 도달한다는 것입니다.
해결책:
업데이트 잠금, 예를 들어 A 쿼리를 요청했는데 캐시에 없는 것으로 확인되면 키 A를 잠그고 동시에 데이터베이스로 이동하여 데이터를 쿼리하고 캐시에 넣은 다음 사용자에게 반환하므로 후속 요청이 캐시에서 데이터를 얻을 수 있습니다.
만료 시간 조합을 값으로 작성하고, 이러한 현상을 방지하기 위해 비동기식으로 만료 시간을 지속적으로 새로 고칩니다.
캐시 침투는 캐시에 존재하지 않는 데이터를 쿼리하는 것을 의미합니다. 각 요청은 캐시가 존재하지 않는 것처럼 DB에 도달합니다.
이 문제를 해결하려면 Bloom 필터 레이어를 추가하세요. 블룸 필터의 동작 단계는 해시 함수를 통해 데이터를 비트 배열의 K개 지점으로 매핑하고 이 지점을 1로 설정하여 데이터를 저장하는 것입니다.
이렇게 하면 사용자가 A를 다시 쿼리하고 A의 Bloom 필터 값이 0인 경우 바로 반환되며 분석 요청이 생성되지 않고 DB에 도달하게 됩니다.
분명히 Bloom 필터를 사용하면 문제가 발생하게 되는데, 이는 오판입니다. 왜냐하면 그것은 배열 자체이고, 이론적으로는 우리의 길이만큼 동일한 위치에 속하는 값이 여러 개 있을 수 있기 때문입니다. 배열이 충분히 길면 오판을 피할 수 있으며, 이러한 문제는 실제 상황에 따라 처리해야 합니다.
예를 들어 캐시 서비스가 다운되는 등 특정 순간에 대규모 캐시 장애가 발생하면 대량의 요청이 들어와 DB에 직접 타격을 가해 전체 시스템이 붕괴될 수 있습니다. , 이를 눈사태라고 합니다. 고장 및 핫키 문제와 달리 눈사태 문제는 대규모 캐시가 동시에 만료되는 문제를 의미합니다.
눈사태에 대한 여러 솔루션:
동시 만료를 방지하기 위해 서로 다른 키에 대해 서로 다른 만료 시간을 설정합니다.
전류 제한 Redis가 다운된 경우 많은 수의 요청으로 인해 DB가 충돌하는 것을 방지하기 위해 전류를 제한할 수 있습니다. 동시에
레벨 2 캐시, 동일한 단축키 솔루션.
Redis에는 주로 2가지 만료 삭제 전략이 있습니다
지연 삭제는 쿼리할 때만 키를 감지하고 만료된 경우 삭제하는 것을 의미합니다. 만료된 키에 액세스하지 않은 경우에는 해당 키가 계속해서 메모리를 차지하고 삭제할 수 없다는 단점이 있습니다.
Redis에서 주기적 삭제는 지정 시 데이터베이스의 키-값 쌍을 확인하고 만료된 키-값 쌍을 삭제하는 것입니다. Redis는 작업 삭제 시 모든 키에 대해 폴링을 수행할 수 없으므로 일부 키는 검사 및 삭제를 위해 무작위로 선택됩니다.
redis가 주기적으로 키를 무작위로 쿼리할 때마다 키를 삭제하지 않고 이러한 키가 쿼리되지 않는다고 가정하면 이러한 키는 redis에 저장되고 현재 메모리 제거 메커니즘은 삭제할 수 없습니다. Redis에 도달하게 됩니다.
휘발성-lru: 만료 시간이 설정된 키에서 최근에 가장 적게 사용된 키를 제거하여 제거
휘발성-ttl: 만료 시간이 설정된 키에서 곧 만료될 키를 제거
휘발성-random: 제거할 만료 시간이 있는 키에서 무작위로 키를 선택합니다.
allkeys-lru: 제거할 키에서 가장 최근에 사용된 키를 선택합니다.
allkeys-random: 무작위로 선택합니다. Elimination
noeviction: 메모리가 임계값에 도달하면 새로운 쓰기 작업에 대해 오류가 보고됩니다.
Redis 지속성 솔루션은 RDB와 AOF의 두 가지 유형으로 구분됩니다.
RDB 지속성은 구성에 따라 수동으로 또는 주기적으로 실행할 수 있습니다. RDB 파일은 특정 시점의 데이터베이스 상태를 압축된 바이너리 파일로 저장하는 것입니다. 복원된 특정 시점의 데이터베이스 상태입니다. RDB 파일은 하드디스크에 저장되기 때문에 redis가 충돌하거나 종료되더라도 RDB 파일이 존재하는 한 데이터베이스의 상태를 복원하는 데 사용할 수 있다.
SAVE 또는 BGSAVE를 통해 RDB 파일을 생성할 수 있습니다.
SAVE 명령은 RDB 파일이 생성될 때까지 redis 프로세스를 차단합니다. 프로세스 차단 기간 동안 redis는 명령 요청을 처리할 수 없으며 이는 분명히 부적절한 일입니다.
BGSAVE는 하위 프로세스를 분기한 다음 하위 프로세스가 RDB 파일 생성을 담당하게 됩니다. 상위 프로세스는 프로세스를 차단하지 않고 계속해서 명령 요청을 처리할 수 있습니다.
AOF는 RDB와 다릅니다. AOF는 Redis 서버에서 실행되는 쓰기 명령을 저장하여 데이터베이스 상태를 기록합니다.
AOF는 추가, 쓰기, 동기화의 세 단계를 통해 지속성 메커니즘을 구현합니다.
AOF 지속성이 활성화되면 서버가 쓰기 명령을 실행한 후 쓰기 명령이 aof_buf 버퍼 끝에 추가됩니다
서버에서 각 이벤트 루프가 끝나기 전에 aof_buf의 내용을 AOF 파일에 저장할지 여부를 결정하기 위해 플러시AppendOnlyFile 함수가 호출됩니다. 이는 appendfsync를 구성하여 결정할 수 있습니다.
always ##aof_buf内容写入并同步到AOF文件 everysec ##将aof_buf中内容写入到AOF文件,如果上次同步AOF文件时间距离现在超过1秒,则再次对AOF文件进行同步 no ##将aof_buf内容写入AOF文件,但是并不对AOF文件进行同步,同步时间由操作系统决定
설정하지 않으면 기본 옵션은 Everysec이 됩니다. 왜냐하면 Always가 가장 안전하기는 하지만(단 하나의 이벤트 루프 쓰기 명령만 손실됨) 성능이 좋지 않고 Everysec 모드에서는 1초의 클럭 데이터만 손실될 수 있기 때문입니다. , 모드 없음의 효율성은 Everysec의 효율성과 유사하지만 AOF 파일의 마지막 동기화 이후의 모든 쓰기 명령 데이터가 손실됩니다.
고가용성을 달성하려면 하나의 머신만으로는 충분하지 않습니다. 고가용성을 보장하기 위해 Redis에는 2가지 옵션이 있습니다.
마스터-슬레이브 모드는 고가용성을 달성하기 위한 가장 간단한 솔루션이며 핵심은 마스터-슬레이브 동기화입니다. 마스터-슬레이브 동기화의 원리는 다음과 같습니다.
슬레이브가 마스터에게 동기화 명령을 보냅니다
마스터가 동기화를 받은 후 bgsave를 실행하고 RDB 전체 파일을 생성합니다
마스터가 슬레이브의 쓰기 명령을 캐시에 기록합니다
bgsave가 실행된 후 RDB 파일을 슬레이브로 보내면 슬레이브가 이를 실행합니다. 마스터가 캐시에 있는 쓰기 명령을 슬레이브에게 보내고, 여기서 작성한 명령은 동기화이지만. redis2.8 버전 이후 psync가 sync를 대체하는 데 사용되었습니다. 그 이유는 sync 명령이 시스템 리소스를 소비하고 psync가 더 효율적이기 때문입니다.
마스터-슬레이브 솔루션의 단점은 여전히 매우 명백합니다. 마스터가 다운되면 데이터를 쓸 수 없으며, 슬레이브는 해당 기능을 잃게 되며 수동으로 전환하지 않으면 전체 아키텍처를 사용할 수 없게 됩니다. 주된 이유는 자동 장애 조치 메커니즘이 없기 때문입니다. 센티널의 기능은 단순한 마스터-슬레이브 아키텍처보다 훨씬 더 포괄적입니다. 자동 장애 조치, 클러스터 모니터링, 메시지 알림과 같은 기능이 있습니다.
마스터 사전 및 서버 정보를 초기화합니다. 서버 정보는 주로 ip:port를 저장하고 주소 및 인스턴스 ID
마스터와 명령 연결, 구독 연결 두 개를 만들고 sentinel:hello 채널을 구독하세요
현재 정보를 얻기 위해 10초마다 마스터에 info 명령을 보냅니다. 마스터와 그 아래의 모든 슬레이브의
마스터에 새로운 슬레이브가 있음을 발견한 후 센티넬도 새 슬레이브와 두 개의 연결을 설정하고 10초마다 info 명령을 보내 마스터 정보를 업데이트합니다
센티넬은 1초마다 모든 서버에 ping 명령을 보냅니다. 만약 서버가 구성된 응답 시간 내에 계속해서 잘못된 응답을 반환하면 오프라인으로 표시됩니다.
리더 센티넬을 선출하려면 동의가 필요합니다.
리더 센티넬은 모든 슬레이브 중 하나를 선택하여 마스터로 변환합니다.
모든 슬레이브가 새 마스터의 데이터를 복사하도록 합니다
원래 마스터를 새 마스터의 슬레이브 서버로 설정하고, 원래 마스터가 연결을 재개하면 새 마스터의 슬레이브 서버가 됩니다
센티넬은 모든 인스턴스(마스터-슬레이브 서버 포함)에 ping 명령을 보냅니다. 및 기타 감시자) 1초마다 응답을 기반으로 오프라인 여부를 판단하는 방식을 주관적 오프라인이라고 합니다. 주관적으로 오프라인이라고 판단되면 다른 모니터링 센티널에게 요청하여 절반 이상의 투표자가 오프라인이라고 판단하면 객관적으로 오프라인으로 표시하고 장애 조치를 실행합니다.
Node
노드 A는 클라이언트로부터 Cluster Meet 명령을 받습니다
A 수신된 IP 주소와 포트 번호를 기반으로 B에게 Meet 메시지를 보냅니다
노드 B는 Meet 메시지를 받고 pong을 반환합니다
A는 B가 Meet 메시지를 받았다는 것을 알고 ping 메시지를 반환하고 악수를 합니다.
마지막으로 노드 A는 가십 프로토콜을 통해 노드 B의 정보를 클러스터 내 다른 노드에 전파하고, 다른 노드도 B와 악수를 하게 됩니다.
slot
슬롯은 비트 배열이며, 배열의 길이는 16384/8=2048이며, 배열의 각 비트는 노드에서 처리하도록 1로 표시하고, 0은 처리되지 않음을 의미합니다. 해당 노드 A는 슬롯 0-7을 처리합니다.
클라이언트가 노드에 명령을 보낼 때 슬롯이 현재 노드에 속하는 것을 발견하면 노드는 명령을 실행합니다. 그렇지 않으면 클라이언트를 다음 노드로 안내하기 위해 MOVED 명령이 클라이언트에 반환됩니다. 올바른 노드. (MOVED 프로세스는 자동입니다.)
노드를 추가하거나 제거하는 경우 슬롯을 재할당하는 것도 매우 편리합니다. Redis는 전체 프로세스가 완전히 온라인이며 서비스를 중지할 필요가 없습니다.
노드 A가 노드 B에 ping 메시지를 보내고 노드 B가 지정된 시간 내에 pong에 응답하지 않으면 노드 A는 노드 B를 pfail로 표시하고 오프라인인 것으로 의심함과 동시에 B의 상태를 메시지 형태로 보냅니다. 노드의 절반 이상이 B를 실패로 표시하면 B는 실패로 표시됩니다. 이때 장애 조치가 발생하고 더 많은 복제 데이터가 있는 슬레이브 노드가 됩니다. 마스터 노드가 되기 위해 먼저 선택되고 오프라인 노드의 슬롯을 차지합니다. 전체 프로세스는 Sentinel의 프로세스와 매우 유사하며 선거를 위한 Raft 프로토콜을 기반으로 합니다.
redis는 MULTI, EXEC, WATCH 및 기타 명령을 통해 트랜잭션 메커니즘을 구현합니다. 트랜잭션 실행 프로세스는 일련의 여러 명령을 동시에 순차적으로 실행하며 실행 중에 트랜잭션이 중단되지 않으며 클라이언트도 중단되지 않습니다. 실행 모든 명령이 실행될 때까지 추가 요청이 수행됩니다. 트랜잭션의 실행 과정은 다음과 같습니다.
서버가 클라이언트 요청을 받고 MULTI로 트랜잭션이 시작됩니다
클라이언트가 트랜잭션 상태이면 트랜잭션이 큐에 들어가고 반환됩니다. 그렇지 않으면 직접 이 명령을 실행합니다
클라이언트 EXEC 명령을 수신하면 WATCH 명령은 전체 트랜잭션의 키가 수정되었는지 모니터링하고, 수정된 경우 클라이언트에 빈 응답을 반환합니다. 그렇지 않으면 redis는 전체 트랜잭션 대기열을 순회하고 대기열에 저장된 모든 명령을 실행하여 최종적으로 클라이언트에 결과를 반환합니다. 모니터링되는 키는 연결된 목록에 저장됩니다. 키가 수정되면 REDIS_DIRTY_CAS 플래그가 열리고 서버는 트랜잭션 실행을 거부합니다.
위 내용은 Redis 인터뷰 질문과 답변은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!