SLOWLOG 명령어를 사용한 느린 Redis 쿼리 진단 및 해결
Redis SLOWLOG를 사용하여 느린 명령어를 찾고, 임계값을 조정하며, 클라이언트를 검사하고, 비용이 많이 드는 액세스 패턴을 교체하세요.
SLOWLOG 명령어를 사용한 느린 Redis 쿼리 진단 및 해결
Redis는 매우 빠른 인메모리 데이터 저장소로, 캐싱, 실시간 분석, 세션 관리, 메시지 브로커링에 널리 사용됩니다. 그 성능은 종종 이를 기반으로 구축된 애플리케이션의 응답성에 중요합니다. 그러나 Redis의 속도에도 불구하고, 최적화되지 않은 명령어나 예상치 못한 부하는 느린 쿼리로 이어져 전체 애플리케이션 성능을 저하시키는 병목 현상을 만들 수 있습니다.
근본 원인을 식별하는 것은 Redis SLOWLOG에서 시작됩니다. 이는 서버 측 실행 시간이 임계값을 초과하는 명령어를 기록하여 KEYS, 광범위한 LRANGE, 큰 HGETALL 또는 느린 Lua 스크립트와 같은 비용이 많이 드는 명령어를 찾는 데 도움을 줍니다.
Redis SLOWLOG 기능 이해
SLOWLOG는 지정된 실행 시간을 초과하는 쿼리를 기록하는 시스템입니다. 이는 구성된 임계값보다 오래 걸린 명령어를 기록하는 인메모리 로그입니다. 기존 파일 기반 로그와 달리 SLOWLOG는 Redis 메모리에 직접 저장되어 디스크 I/O 오버헤드 없이 빠르게 액세스하고 관리할 수 있습니다.
각 항목에는 고유 ID, Unix 타임스탬프, 마이크로초 단위의 실행 시간, 명령어 인수, 그리고 최신 Redis 버전에서는 사용 가능한 경우 클라이언트 주소와 클라이언트 이름이 포함됩니다. SLOWLOG는 Redis 내부의 명령어 실행 시간을 측정하며, 네트워크 지연 시간, 클라이언트 측 대기 시간, 또는 Redis가 명령어 실행을 시작하기 전에 대기열에서 보낸 시간은 포함하지 않습니다.
SLOWLOG 작동 방식: 구성 매개변수
SLOWLOG를 효과적으로 사용하기 전에 두 가지 주요 매개변수를 이해하고 구성하는 것이 중요합니다. 이 매개변수는 기록되는 내용과 유지되는 항목 수를 제어합니다.
slowlog-log-slower-than
이 매개변수는 명령어가 기록되기 위한 실행 시간 임계값(마이크로초)을 정의합니다. 지정된 값보다 오래 걸리는 명령어만 SLOWLOG에 기록됩니다. 이 값을 너무 낮게 설정하면 너무 많은 명령어가 기록되어 상당한 메모리를 소비하고 분석이 어려워질 수 있습니다. 너무 높게 설정하면 실제로 느린 쿼리를 놓칠 수 있습니다.
- 기본값:
10000(10밀리초) - 권장 사항: 기본값으로 시작하여 애플리케이션의 성능 요구 사항에 따라 조정하세요. 고성능 시스템의 경우
1000마이크로초(1밀리초) 또는100마이크로초로 낮출 수 있습니다. - 특수 값:
0으로 설정하면 모든 명령어가 기록됩니다. 음수 값으로 설정하면SLOWLOG가 완전히 비활성화됩니다.
이 매개변수의 현재 값을 볼 수 있습니다:
redis-cli config get slowlog-log-slower-than
새 값을 설정하려면(예: 5000 마이크로초 또는 5밀리초):
redis-cli config set slowlog-log-slower-than 5000
이 변경 사항을 영구적으로 적용하려면 redis.conf 파일을 업데이트하거나 Redis 버전과 설정에서 지원하는 경우 CONFIG REWRITE를 사용해야 합니다.
slowlog-max-len
이 매개변수는 Redis가 SLOWLOG에 유지할 최대 항목 수를 지정합니다. 로그가 최대 길이에 도달하면 새 항목이 가장 오래된 항목을 자동으로 제거합니다(FIFO - 선입선출).
- 기본값:
128개 항목 - 권장 사항: 기본값은 바쁜 프로덕션 시스템에는 너무 작은 경우가 많습니다. 메모리 영향을 고려하여 충분한 기록을 확보하려면
1024또는4096으로 늘리는 것을 고려하세요.
현재 값을 볼 수 있습니다:
redis-cli config get slowlog-max-len
새 값을 설정하려면(예: 1024개 항목):
redis-cli config set slowlog-max-len 1024
다시 한 번, 이 변경 사항을 redis.conf 파일에 영구적으로 저장해야 합니다.
SLOWLOG 항목 검색 및 분석
SLOWLOG가 구성되면 명령어 세트를 사용하여 상호 작용할 수 있습니다.
SLOWLOG GET
이 명령어는 SLOWLOG에서 항목을 검색하는 데 사용됩니다. 선택적으로 count를 지정하여 가장 최근 항목 중 특정 개수를 검색할 수 있습니다.
SLOWLOG GET: 로그의 모든 항목을 검색합니다.SLOWLOG GET <count>: 최신<count>개 항목을 검색합니다.
예시:
# 가장 최근 느린 로그 항목 10개 검색
redis-cli slowlog get 10
예시 출력(명확성을 위해 단순화):
1) 1) (integer) 12345 # 로그 항목의 고유 ID
2) (integer) 1678886400 # Unix 타임스탬프 (예: 2023년 3월 15일 오후 12:00:00 UTC)
3) (integer) 25000 # 마이크로초 단위 실행 시간 (25ms)
4) 1) "LRANGE" # 명령어
2) "mybiglist" # 인수 1
3) "0" # 인수 2
4) "-1" # 인수 3
5) "127.0.0.1:54321" # 클라이언트 IP 및 포트
6) "client-name-app" # 클라이언트 이름 (설정된 경우)
...
SLOWLOG LEN
이 명령어는 SLOWLOG의 현재 항목 수를 반환합니다.
redis-cli slowlog len
출력:
(integer) 5
SLOWLOG RESET
이 명령어는 SLOWLOG의 모든 항목을 지웁니다. 기존 항목을 분석한 후 새 성능 데이터를 캡처하기 위해 새 로그로 시작하려는 경우 유용합니다.
redis-cli slowlog reset
출력:
OK
SLOWLOG 출력 해석
각 항목은 중요한 정보를 제공합니다:
- 고유 ID: 순차적 식별자입니다. 특정 이벤트를 추적하는 데 유용합니다.
- 타임스탬프: 명령어가 실행된 시간입니다. 느린 쿼리를 애플리케이션 배포 변경 또는 특정 부하 기간과 연관시키는 데 도움이 됩니다.
- 실행 시간(마이크로초): 가장 중요한 지표입니다. 명령어 완료에 걸린 정확한 시간을 알려줍니다. 높은 값은 잠재적인 병목 현상을 나타냅니다.
- 명령어 및 인수: 정확한 Redis 명령어와 그 매개변수입니다. 어떤 작업이 느렸는지 이해하는 데 중요합니다(예:
KEYS *, 매우 큰 목록에 대한LRANGE 0 -1,LIMIT없는SORT). - 클라이언트 주소: 명령어를 실행한 클라이언트의 IP 주소와 포트입니다. 소스 애플리케이션 또는 서비스를 추적하는 데 도움이 됩니다.
- 클라이언트 이름: 애플리케이션이
CLIENT SETNAME을 설정하는 경우(더 나은 관찰성을 위해 적극 권장), 이는 추가 컨텍스트 계층을 제공하여 애플리케이션의 어느 부분이 느린 쿼리를 만들었는지 나타냅니다.
실제 예시: 느린 명령어 식별
느린 명령어를 시뮬레이션하고 SLOWLOG가 이를 어떻게 캡처하는지 살펴보겠습니다.
먼저, 데모를 위해 slowlog-log-slower-than을 낮은 값(예: 1000 마이크로초(1밀리초))으로 설정합니다:
redis-cli config set slowlog-log-slower-than 1000
다음으로, 대규모 데이터 세트에 적용될 경우 잠재적으로 느린 것으로 알려진 작업(예: KEYS * 또는 많은 요소가 있는 목록에 대한 LRANGE)을 수행합니다.
큰 목록을 만들어 보겠습니다:
for i in {1..100000}; do redis-cli LPUSH mybiglist $i; done
이제 이 큰 목록에서 모든 요소를 검색하는 LRANGE 명령어를 실행합니다:
redis-cli LRANGE mybiglist 0 -1
이 명령어는 1밀리초 이상 걸릴 가능성이 높습니다.
마지막으로 SLOWLOG를 확인합니다:
redis-cli slowlog get 1
다음과 유사한 출력이 표시됩니다(값은 다를 수 있음):
1) 1) (integer) 12346
2) (integer) 1678886450
3) (integer) 15432 # 마이크로초 단위의 느린 실행 시간
4) 1) "LRANGE"
2) "mybiglist"
3) "0"
4) "-1"
5) "127.0.0.1:54322"
6) ""
출력은 LRANGE mybiglist 0 -1 명령어, 실행 시간(15432 마이크로초 또는 15.432ms) 및 발생 시간을 명확하게 보여줍니다. 이는 전체 큰 목록을 가져오는 데 상당한 시간이 소요된다는 것을 즉시 알려줍니다.
느린 쿼리 해결 전략
SLOWLOG를 사용하여 느린 쿼리를 식별한 후 다음 단계는 최적화하는 것입니다. 일반적인 전략은 다음과 같습니다:
데이터 구조 및 액세스 패턴 최적화:
- 대규모 데이터 세트에서
O(N)명령어 피하기:LRANGE 0 -1(모든 요소 가져오기),SMEMBERS(모든 세트 멤버 가져오기),HGETALL(모든 해시 필드/값 가져오기),SORT(LIMIT없이)와 같은 명령어는 느릴 수 있습니다. 큰 컬렉션을 처리해야 하는 경우 한 번에 모든 것을 가져오는 대신SCAN,SSCAN,HSCAN또는ZSCAN으로 반복하는 것을 고려하세요. - 적절한 데이터 구조 사용: 예를 들어, 객체의 속성을 자주 가져와야 하는 경우 각 속성에 대해 개별 키를 저장하는 대신 해시를 사용하세요.
- 결과 제한: 목록이나 정렬된 세트의 경우 전체 구조를 가져오는 대신 합리적인 제한과 함께
LRANGE <start> <end>또는ZRANGE <start> <end>를 사용하세요.
- 대규모 데이터 세트에서
파이프라이닝: 명령어를 하나씩 보내는 대신 파이프라이닝을 사용하여 여러 명령어를 단일 요청으로 일괄 처리하세요. 이는 네트워크 왕복 시간(RTT) 오버헤드를 줄여 개별 명령어가 빠르더라도 애플리케이션 속도를 크게 높일 수 있습니다.
# 파이프라이닝 없음 (여러 RTT로 인해 느림) r.set('key1', 'value1') r.set('key2', 'value2') # 파이프라이닝 사용 (더 빠름, 하나의 RTT) pipe = r.pipeline() pipe.set('key1', 'value1') pipe.set('key2', 'value2') pipe.execute()Lua 스크립팅(EVAL): 원자적으로 또는 최소 RTT로 실행해야 하는 여러 Redis 명령어가 포함된 복잡한 작업의 경우 Lua 스크립트 사용을 고려하세요. 스크립트는 Redis 서버에서 직접 실행되어 네트워크 지연 시간을 줄이고 원자성을 보장합니다. 그러나 장기 실행 Lua 스크립트는 Redis를 차단할 수 있으므로 신중하게 최적화해야 합니다.
프로덕션에서
KEYS피하기:KEYS명령어는O(N)(N은 데이터베이스의 키 수)이며, 특히 대규모 데이터베이스에서 Redis 서버를 장기간 차단할 수 있습니다. 프로덕션 환경에서 키를 반복하려면SCAN을 사용하세요.SCAN은 일시 중지 및 재개할 수 있는 반복자와 유사한 기능을 제공하여 긴 차단 작업을 방지합니다.# 프로덕션에서 나쁨 redis-cli KEYS * # 반복을 위한 프로덕션에서 좋음 redis-cli SCAN 0 MATCH user:* COUNT 100연결 풀링: 애플리케이션이 Redis에 대한 연결을 효율적으로 관리하기 위해 적절한 연결 풀링을 사용하는지 확인하세요. 모든 명령어에 대해 연결을 열고 닫는 것은 리소스를 많이 소모할 수 있습니다.
샤딩 및 클러스터링: 데이터 세트나 워크로드가 단일 Redis 인스턴스가 처리할 수 있는 것보다 커지면 여러 Redis 인스턴스에 데이터를 샤딩하거나 Redis Cluster를 채택하는 것을 고려하세요. 이는 부하와 데이터를 분산하여 단일 인스턴스가 병목 현상이 되는 것을 방지합니다.
읽기 복제본: 읽기 집약적인 워크로드의 경우 읽기 쿼리를 Redis 읽기 복제본에 오프로드하세요. 이는 읽기 처리량을 확장하고 기본 인스턴스의 부하를 줄여 쓰기에 집중할 수 있게 합니다.
SLOWLOG 사용 모범 사례
- 정기적 모니터링: 설정하고 잊어버리지 마세요. 특히 배포 후 또는 피크 부하 시간에 정기적으로
SLOWLOG항목을 확인하세요. - 적절한 임계값: 애플리케이션의 허용 가능한 대기 시간에 따라
slowlog-log-slower-than을 조정하세요. 한 앱에서 느린 것이 다른 앱에서는 정상일 수 있습니다. - 충분한 로그 길이:
slowlog-max-len을 의미 있는 기록을 유지할 수 있을 만큼 충분히 크게 설정하되, 과도한 메모리를 소비하지 않을 정도로 설정하세요. - 주기적으로 지우기: 항목을 분석한 후
SLOWLOG RESET을 사용하여 새 데이터를 얻거나,SLOWLOG를 모니터링 시스템과 통합하는 경우 이 프로세스를 자동화하는 것을 고려하세요. - 클라이언트 이름 지정: 애플리케이션 코드에서
CLIENT SETNAME <name>을 사용하세요. 이는SLOWLOG항목에 귀중한 컨텍스트를 추가하여 느린 명령어를 애플리케이션의 특정 부분으로 더 쉽게 추적할 수 있게 합니다.
핵심 요점
SLOWLOG를 사용하여 비용이 많이 드는 Redis 명령어를 포착한 다음, 임계값만 높이는 대신 액세스 패턴을 수정하세요. 느린 항목이 큰 키에 대한 광범위한 읽기를 보여주면 결과를 페이지화하고, 점진적으로 스캔하고, 데이터 모델을 변경하거나, 무거운 작업을 요청 경로 밖으로 이동하세요.