레디스를 세션 캐시로 사용하던 중 로그인도 안되고, 새로운 키 등록도 되지 않는 이상한 문제가 발생했습니다. 🙃
로그를 확인해 보니 다음과 같은 에러가 떴네요.
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk.
Commands that may modify the data set are disabled. Please check Redis logs for details about the error
레디스가 RDB 스냅샷을 저장하도록 설정되어 있지만, 디스크에 데이터를 저장할 수 없는 상황이라는 의미였어요. 즉, 데이터 저장이 불가능하니 키 등록과 세션 캐시 저장이 막힌 것이에요.🤔
레디스 로그를 확인해 보았습니다.
sudo tail -f /var/log/redis/redis.log
로그를 보면 원래는 정상적으로 RDB 저장이 이루어졌었습니다.
RDB: 1 MB of memory used by copy-on-write
Background saving terminated with success
하지만 이후에 메모리 부족으로 인해 저장이 실패하면서 MISCONF 에러가 발생한 것으로 보이네요.
10 changes in 300 seconds. Saving...
Can't save in background: fork: Cannot allocate memory
즉, 레디스가 설정된 조건(300초 동안 10개 이상의 변경 사항 발생)을 충족해 RDB 저장을 시도했지만, 메모리가 부족해서 fork()를 실행할 수 없었고, 결국 저장이 실패한 거죠.😞
우선 응급조치로 아래 명령어를 실행할 수 있어요.
redis-cli CONFIG SET stop-writes-on-bgsave-error no
이 명령어는 레디스가 RDB 저장이 실패하더라도 계속해서 데이터를 저장할 수 있도록 하는 설정이에요. 하지만 근본적인 해결책은 아니죠. 메모리가 부족한 상태에서 저장을 강제로 진행하면 결국 더 큰 문제가 발생할 수 있기 때문이에요.
그래서 현재 레디스의 maxmemory-policy 설정을 확인해 보았습니다.
redis-cli config get maxmemory-policy
출력된 결과는 noeviction이었어요.
1) "maxmemory-policy"
2) "noeviction"
noeviction 정책은 레디스의 메모리가 가득 찼을 때 새로운 데이터를 받아들이지 않는 설정이에요. 따라서 메모리가 부족하면 데이터 저장이 실패하고, MISCONF 에러가 발생할 가능성이 높아지죠.
이 문제를 예방하기 위해 allkeys-lru 정책으로 변경하는 게 좋다고 판단했어요.
redis-cli CONFIG SET maxmemory-policy allkeys-lru
allkeys-lru 정책은 레디스의 모든 키를 대상으로 LRU 알고리즘을 적용해 가장 오래 사용되지 않은 키를 삭제하여 메모리를 확보하는 방식이에요. 이렇게 설정하면 메모리가 부족할 때 자동으로 공간이 확보되어 MISCONF 에러가 발생할 가능성이 줄어들죠.
*참고
정책명 | 설명 |
noeviction | 메모리가 가득 차면 새로운 데이터를 저장하지 않음 (기본값) |
volatile-lru | TTL이 설정된 키 중 LRU(Least Recently Used) 알고리즘을 적용해 제거 |
allkeys-lru | 모든 키를 대상으로 LRU 알고리즘을 적용해 가장 오래 사용되지 않은 키 삭제 |
volatile-random | TTL이 설정된 키 중에서 랜덤하게 삭제 |
allkeys-random | 모든 키 중에서 랜덤하게 삭제 |
volatile-ttl | TTL이 가장 짧은 키를 우선적으로 삭제 |
설정을 영구적으로 적용하기 위해 redis.conf 파일을 수정해야 해요.
sudo vi /etc/redis/redis.conf
파일에서 다음 설정을 찾아 allkeys-lru로 변경하면 돼요.
maxmemory-policy allkeys-lru
이제 레디스를 재시작하여 변경 사항을 적용하면 됩니다.
sudo systemctl restart redis
그 후 다시 maxmemory-policy 설정을 확인해 보니 정상적으로 변경되었어요.
redis-cli config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
이제 레디스가 메모리가 부족할 때도 LRU 알고리즘을 통해 공간을 확보할 수 있으므로, MISCONF 에러가 발생할 가능성이 줄어들겠죠.
레디스 운영 환경에서 사용한다면 메모리 관리 정책을 신중하게 설정해야 해요. noeviction 정책은 데이터가 유실되지 않는다는 장점이 있지만, 메모리가 가득 차면 새로운 데이터를 저장할 수 없다는 치명적인 단점이 있죠. allkeys-lru는 가장 적절한 대안중 하나로, 자주 사용하는 데이터를 유지하면서 메모리를 효율적으로 관리할 수 있게 해 줍니다.