본문 바로가기
Study OR Book/실전 레디스

[실전 레디스] Chaprter 06_트러블 슈팅

by Baest 2025. 7. 1.

 

1. INFO 명령어로 서버 정보 읽기

레디스 트러블슈팅의 첫 번째 단계는 현재 서버 상태를 정확히 파악하는 것이다. INFO 명령어는 레디스 서버의 전반적인 상태 정보를 제공하는 가장 기본적이면서도 강력한 도구이다.

기본 사용법

# 전체 정보 조회
redis-cli INFO

# 특정 섹션만 조회
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO replication

주요 섹션별 정보

Server 섹션

  • redis_version: 레디스 버전
  • uptime_in_seconds: 서버 가동 시간
  • tcp_port: 포트 번호

Memory 섹션

  • used_memory_human: 사용 중인 메모리 (사람이 읽기 쉬운 형태)
  • used_memory_peak: 최대 메모리 사용량
  • maxmemory: 설정된 최대 메모리 제한

Stats 섹션

  • total_commands_processed: 총 처리된 명령 수
  • instantaneous_ops_per_sec: 초당 명령 처리 수
  • keyspace_hits: 키 히트 수
  • keyspace_misses: 키 미스 수

실전 활용 팁

Spring Boot 애플리케이션에서 헬스체크나 모니터링 목적으로 활용할 수 있다.

@Component
class RedisHealthChecker(
    private val redisTemplate: RedisTemplate<String, Any>
) {
    fun getRedisInfo(): Map<String, String> {
        return redisTemplate.execute { connection ->
            connection.info().associate { line ->
                val parts = line.split(":")
                if (parts.size == 2) parts[0] to parts[1] else null
            }.filterNotNull().toMap()
        } ?: emptyMap()
    }
}

2. 지연 시간 조사

레디스의 성능 문제를 진단할 때 가장 중요한 것은 지연 시간(latency)을 정확히 측정하고 분석하는 것이다.

슬로우 로그 활용

슬로우 로그는 설정된 임계값보다 오래 걸린 명령들을 기록하는 기능이다.

설정 방법

# 100 마이크로초 이상 걸린 명령 기록
CONFIG SET slowlog-log-slower-than 100

# 최대 1000개의 슬로우 로그 유지
CONFIG SET slowlog-max-len 1000

조회 및 분석

# 슬로우 로그 조회
SLOWLOG GET 10

# 슬로우 로그 개수 확인
SLOWLOG LEN

# 슬로우 로그 초기화
SLOWLOG RESET

슬로우 로그 출력 예시:

1) 1) (integer) 0          # 로그 ID
   2) (integer) 1609459200 # 타임스탬프
   3) (integer) 1500       # 실행 시간 (마이크로초)
   4) 1) "GET"             # 명령어
      2) "my:key"          # 인자

redis-cli 옵션을 통한 지연 시간 측정

지연 시간 히스토리 모니터링

# 실시간 지연 시간 모니터링
redis-cli --latency

# 지연 시간 히스토리 (1초마다 측정)
redis-cli --latency-history -i 1

# 지연 시간 분포 확인
redis-cli --latency-dist

연속 핑 테스트

# 100번의 ping 테스트
redis-cli --latency -i 1 | head -100

지연 시간 모니터링 시스템 구축

Spring Boot에서 지연 시간을 모니터링하는 방법:

@Component
class RedisLatencyMonitor(
    private val redisTemplate: RedisTemplate<String, Any>,
    private val meterRegistry: MeterRegistry
) {
    
    @Scheduled(fixedDelay = 5000)
    fun monitorLatency() {
        val startTime = System.nanoTime()
        
        try {
            redisTemplate.opsForValue().get("health-check")
            val latency = (System.nanoTime() - startTime) / 1_000_000.0 // ms
            
            Timer.Sample.start(meterRegistry)
                .stop(Timer.builder("redis.latency")
                    .description("Redis command latency")
                    .register(meterRegistry), latency, TimeUnit.MILLISECONDS)
                    
        } catch (e: Exception) {
            meterRegistry.counter("redis.errors").increment()
        }
    }
}

3. 메모리 문제 해결

메모리 관련 문제는 레디스에서 가장 흔하게 발생하는 이슈 중 하나이다.

메모리 사용량 분석

키별 메모리 사용량 확인

# 메모리 사용량이 큰 키들 찾기
redis-cli --bigkeys

# 특정 키의 메모리 사용량 확인
MEMORY USAGE my:key

데이터 타입별 분석

# 샘플링을 통한 메모리 분석
MEMORY STATS

메모리 정책 설정

Eviction 정책 설정

# LRU 기반 키 삭제
CONFIG SET maxmemory-policy allkeys-lru

# TTL이 있는 키만 LRU 삭제
CONFIG SET maxmemory-policy volatile-lru

# 최대 메모리 제한 설정 (2GB)
CONFIG SET maxmemory 2gb

메모리 최적화 설정

# 해시 테이블 최적화
CONFIG SET hash-max-ziplist-entries 512
CONFIG SET hash-max-ziplist-value 64

# 리스트 최적화
CONFIG SET list-max-ziplist-size -2

Spring Boot에서의 메모리 모니터링

@Component
class RedisMemoryMonitor(
    private val redisTemplate: RedisTemplate<String, Any>
) {
    
    @EventListener
    @Scheduled(fixedDelay = 30000)
    fun checkMemoryUsage() {
        val info = redisTemplate.execute { connection ->
            connection.info("memory")
        }
        
        val usedMemory = extractMemoryValue(info, "used_memory")
        val maxMemory = extractMemoryValue(info, "maxmemory")
        
        if (maxMemory > 0 && usedMemory.toDouble() / maxMemory > 0.8) {
            logger.warn("Redis memory usage is high: ${usedMemory}/${maxMemory}")
            // 알림 로직 추가
        }
    }
    
    private fun extractMemoryValue(info: String?, key: String): Long {
        return info?.lines()
            ?.find { it.startsWith(key) }
            ?.split(":")
            ?.get(1)
            ?.toLongOrNull() ?: 0L
    }
}

메모리 누수 방지

TTL 설정 강화

@Service
class CacheService(
    private val redisTemplate: RedisTemplate<String, Any>
) {
    
    fun setWithTTL(key: String, value: Any, ttl: Duration = Duration.ofHours(1)) {
        redisTemplate.opsForValue().set(key, value, ttl)
    }
    
    // 기본 TTL이 없는 키 방지
    fun safeSet(key: String, value: Any) {
        redisTemplate.opsForValue().set(key, value, Duration.ofDays(1))
    }
}

 

 

레디스 트러블슈팅은 상황에 맞는 접근이 중요하다.

앞서 언급된 INFO 명령어로 전반적인 상태를 파악하고, 슬로우 로그와 지연 시간 모니터링으로 성능 이슈를 추적하며, 메모리 사용량을 지속적으로 모니터링하는 것이 본 챕터의 핵심이다.