Redis가 높은 CPU를 사용하는 이유: 디버깅 및 최적화 기법

중요한 인메모리 데이터 저장소인 Redis에서 갑작스러운 높은 CPU 사용률을 조사합니다. 이 가이드는 `SLOWLOG` 및 `INFO` 명령을 사용하여 `KEYS *` 또는 대규모 키 삭제와 같은 비효율적인 작업을 정확히 찾아내는 부하 디버깅 방법을 자세히 설명합니다. 비동기 `UNLINK`로 전환, 파이프라이닝 활용, 지속성 설정 조정 등 실용적인 최적화 기법을 배워 서버 부하를 즉시 줄이고 최적의 Redis 성능을 복원하세요.

Redis가 높은 CPU를 사용하는 이유: 디버깅 및 최적화 기법

Redis의 높은 CPU 사용률은 일반적으로 세 가지 중 하나를 의미합니다: Redis가 메인 실행 경로에서 너무 많은 명령 작업을 수행하고 있거나, 지속성과 같은 백그라운드 작업이 부하를 가중시키고 있거나, 클라이언트가 Redis가 효율적으로 처리할 수 없는 형태로 트래픽을 보내고 있는 경우입니다. 해결 방법은 어떤 경우에 해당하는지에 따라 다릅니다.

서비스가 이미 중단되지 않는 한 Redis를 재시작하는 것으로 시작하지 마십시오. 재시작은 증상을 없애고 증거를 지울 수 있습니다. 명령 지연 시간, 명령 조합, 클라이언트 수, 지속성 상태 및 호스트 CPU를 먼저 캡처하십시오. 이러한 정보를 통해 잘못된 명령, 잘못된 트래픽 패턴, 과부하된 단일 코어 또는 시끄러운 호스트 중 어떤 문제인지 알 수 있습니다.

Redis 아키텍처 및 CPU 부하 이해

Redis는 종종 단일 스레드로 설명되며, 이는 명령 실행에 대해 대부분 사실이지만, 최신 Redis는 백그라운드 스레드와 선택적 I/O 스레딩을 사용할 수도 있습니다. 실용적인 요점은 여전히 동일합니다: 너무 오래 걸리는 명령은 다른 클라이언트를 지연시킬 수 있으며, 하나의 포화된 코어는 시스템의 다른 곳에 유휴 CPU가 있더라도 눈에 띄는 지연 시간을 만들기에 충분할 수 있습니다.

Redis CPU 부하에 영향을 미치는 주요 요인

일반적인 원인은 비용이 많이 드는 명령, 큰 값, Lua 스크립트, 한 번에 한 번의 왕복으로 전송되는 너무 많은 작은 명령, 많은 연결 변경, 지속성 활동 및 Redis가 예상하는 것보다 커널이 더 열심히 일하도록 강제하는 메모리 압력입니다.

높은 CPU 사용률 디버깅

최적화하기 전에 부하의 원인을 정확히 식별해야 합니다. 모니터링 도구와 내장 Redis 명령은 진단에 필수적입니다.

1. INFOLATENCY 명령 사용

INFO 명령은 서버 상태의 스냅샷을 제공합니다. CPU 섹션과 명령 통계에 집중하십시오.

redis-cli INFO cpu

절대값뿐만 아니라 변화율을 살펴보십시오. used_cpu_user가 빠르게 증가하면 종종 명령 처리를 나타냅니다. used_cpu_sys가 빠르게 증가하면 네트워킹, 메모리 관리 또는 디스크 관련 활동과 같은 커널 작업을 나타낼 수 있습니다.

지연 시간 도구는 Redis가 관찰한 이벤트 클래스를 보여줍니다:

redis-cli LATENCY LATEST
redis-cli LATENCY DOCTOR

2. SLOWLOG로 느린 명령 식별

Redis 느린 로그는 지정된 실행 시간을 초과하는 명령을 기록합니다. 이는 성능이 낮은 작업을 찾는 가장 직접적인 도구입니다.

Redis 느린 로그는 실행 시간이 임계값을 초과하는 명령을 기록합니다. 네트워크 시간이나 클라이언트 풀에서 대기하는 시간은 포함하지 않으므로 애플리케이션 지연 시간 메트릭과 함께 사용하는 것이 가장 좋습니다.

구성 예:

slowlog-log-slower-than 1000
slowlog-max-len 1024

로그 검색:

redis-cli SLOWLOG GET 10

명령 이름, 키 이름 및 기간을 검토하십시오. KEYS, 대규모 HGETALL, 거대한 SMEMBERS, 광범위한 정렬된 집합 범위 또는 Lua 스크립트가 로그를 지배하는 경우 CPU 문제는 아마도 애플리케이션에 의해 발생한 것입니다.

3. 네트워크 및 클라이언트 활동 모니터링

MONITOR는 인시던트 중에 유혹적이지만, 바쁜 서버에서는 비용이 많이 듭니다. INFO commandstats, INFO clients, 느린 로그, 클라이언트 라이브러리 메트릭 및 복제본이 있는 경우 복제본에서 샘플링을 선호하십시오.

유용한 명령:

redis-cli INFO commandstats
redis-cli INFO clients
redis-cli CLIENT LIST

배포 후 명령 볼륨이 두 배로 증가한 경우 cmdstat_get, cmdstat_hgetall 또는 유사한 카운터에서 볼 수 있습니다. 클라이언트가 계속 연결 및 연결 해제하는 경우 Redis를 조정하기 전에 풀링을 수정하십시오.

일반적인 원인 및 최적화 전략

문제가 되는 명령이나 프로세스를 식별한 후에는 대상 최적화 기법을 적용하십시오.

1. 차단 명령 제거

가장 빠른 해결책은 일반적으로 Redis가 거대한 키 공간을 탐색하거나 거대한 값을 직렬화하도록 강제하는 명령을 제거하는 것입니다.

비효율적인 명령 높은 CPU를 유발하는 이유 최적화 / 대안
KEYS * 전체 키 공간을 스캔합니다. O(N). 반복적으로 SCAN을 사용하거나 데이터 액세스를 재구성하십시오.
FLUSHALL / FLUSHDB 비동기 모드를 사용하지 않으면 모든 키를 삭제합니다. 신중한 범위 삭제, UNLINK 또는 적절한 경우에만 비동기 플러시를 사용하십시오.
HGETALL, SMEMBERS (매우 큰 집합의 경우) 전체 구조를 메모리로 검색하고 직렬화합니다. HSCAN, SSCAN을 사용하거나 큰 구조를 더 작은 키로 분할하십시오.

매우 큰 키의 경우 DEL 대신 UNLINK를 사용하십시오. DEL은 동기적으로 메모리를 해제합니다. UNLINK는 키 공간에서 키를 제거하고 비동기적으로 메모리를 해제하므로 일반적으로 대규모 삭제 중에 눈에 띄는 지연 시간을 줄입니다.

# 큰 키에 DEL 대신
UNLINK large_key

2. 지속성 최적화 (RDB 및 AOF)

RDB 스냅샷 및 AOF 재작성은 백그라운드 자식 프로세스를 사용하며 포크 비용, 쓰기 시 복사 메모리, 디스크 대역폭 및 CPU 경합을 통해 부모 프로세스에 영향을 줄 수 있습니다.

  • RDB 스냅샷: 자주 저장하는 경우(예: 매분), 반복되는 fork() 호출은 반복적인 CPU 스파이크를 유발합니다. 자동 저장 빈도를 줄이십시오.
  • AOF 재작성: AOF 재작성(BGREWRITEAOF)도 리소스를 많이 사용합니다. Redis는 최소 I/O를 수행하여 이를 최적화하려고 시도하지만, 프로세스 중에 CPU 사용률이 증가합니다.

지속성이 CPU 스파이크와 일치하는 경우 INFO persistence 및 호스트 디스크 메트릭을 확인하십시오. RDB 빈도를 줄이고, 트래픽 피크에서 무거운 백업을 예약하고, 더 많은 메모리 여유를 두거나, 스토리지를 개선할 수 있습니다. 지속성을 일시 중지하면 부하를 줄일 수 있지만 데이터 손실 위험도 증가하므로 신중한 운영 결정이어야 합니다.

3. 메모리 조각화 및 스와핑 처리

메모리 문제는 종종 높은 메모리 사용량과 관련이 있지만, 심각한 메모리 조각화 또는 더 나쁜 경우 운영 체제가 Redis 데이터를 디스크로 스와핑(스래싱)하기 시작하면 커널이 메모리를 관리하기 위해 싸우면서 CPU 사용률이 급격히 증가합니다.

  • 스와핑 확인: OS 도구(vmstat, top)를 사용하여 시스템이 Redis 프로세스에 속한 메모리 페이지를 적극적으로 스와핑하고 있는지 확인하십시오.
  • 메모리 조각화 비율: INFO memory에서 mem_fragmentation_ratio를 확인하십시오. 높은 비율은 할당자 동작이 메모리를 낭비하고 있을 수 있다는 단서이지만, RSS, 데이터 세트 크기 및 호스트 메모리 메트릭으로 확인하십시오.

스와핑이 발생하는 경우 데이터 세트를 줄이고, maxmemory를 낮추고, 호스트에서 작업을 옮기거나, 메모리를 추가하십시오. Redis는 핫 데이터 세트가 디스크로 페이징될 때 잘 수행되도록 설계되지 않았습니다.

4. 네트워크 최적화 및 파이프라이닝

CPU 부하가 많은 수의 작은 명령을 추적하는 경우 문제는 명령 오버헤드 및 네트워크 변경일 수 있으며, 명백히 느린 명령 하나가 아닐 수 있습니다.

파이프라이닝을 사용하면 클라이언트가 각 명령 후에 응답을 기다리지 않고 여러 명령을 보낼 수 있습니다. 왕복 시간을 줄이고 대량 쓰기 또는 읽기의 처리량을 향상시킬 수 있습니다. 파이프라인 배치를 제한하십시오; 수천 개의 무거운 명령이 있는 파이프라인은 자체 지연 시간 스파이크를 만들 수 있습니다.

지속적인 성능을 위한 모범 사례

향후 CPU 스파이크를 방지하려면 이러한 아키텍처 및 구성 모범 사례를 채택하십시오:

  1. 클 수 있는 키에는 UNLINK를 사용하십시오.
  2. KEYSSCAN으로 바꾸고, 전체 컬렉션 읽기를 커서 기반 읽기로 바꾸십시오.
  3. 배포 후 INFO commandstats를 추적하여 새로운 명령 패턴이 당신을 놀라게 하지 않도록 하십시오.
  4. 실제 디스크 및 메모리 여유를 고려하여 지속성을 조정하십시오.
  5. 명령 수정 후 하나의 Redis 인스턴스가 정당하게 포화된 경우 Redis Cluster, 클라이언트 측 샤딩, 별도의 캐시/세션 인스턴스 또는 더 나은 단일 코어 성능을 가진 더 큰 인스턴스로 워크로드를 분할하십시오.

빠른 인시던트 체크리스트

스파이크 중에 다음을 실행하십시오:

redis-cli INFO cpu
redis-cli INFO commandstats
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli SLOWLOG GET 20
redis-cli LATENCY LATEST

그런 다음 해당 결과를 애플리케이션 배포, 크론 작업, 트래픽 변경, 지속성 이벤트 및 호스트 메트릭과 연결하십시오. 높은 Redis CPU는 일반적으로 수정 가능하지만, 수정 방법은 구체적입니다: 비용이 많이 드는 명령을 제거하고, 수다스러운 클라이언트를 배치 처리하고, 연결 변경을 중지하고, 지속성이 작동할 공간을 제공하거나, 단일 인스턴스가 실제로 한계에 도달했을 때 워크로드를 분할하십시오.