grep

Engineering

개발자를 위한 레디스 튜토리얼 04

NHN

2020년 3월 18일

원문에서 보기 ↗

이것만은 하지 마세요!

이제 많은 분이 요청주셨던 레디스의 장애 포인트 에 대해서 말씀드리려고 합니다. 레디스, 잘 몰라도 괜찮으니 이것만은 하지 마세요!

요구사항 파악하기 (캐시용? 저장소용?)

서비스에서 레디스의 도입을 고민할 때, 캐시용으로 사용할 것인지, 혹은 저장소용으로 사용할 것인지를 분명히 해야 합니다. 즉, 레디스에 저장되었던 데이터가 없어져도 같은 데이터가 RDBMS에 남아 있기 때문에 문제가 없거나, 혹은 일부 값이 유실되어도 괜찮은 경우인지 확인해야 합니다. 데이터운영팀에서는 특별한 경우가 아니면 레디스를 영구 저장소용으로 사용하는 것은 추천드리지 않습니다.

왜냐하면 레디스의 데이터를 파일로 보관하기 위한 persistence 기능(RDB, AOF) 으로 인한 장애발생 가능성이 굉장히 크기 때문입니다. fork()로 인한 COW(Copy-On-Write)로 전체 성능 저하가 발생하거나, 파일이 생성되지 않으면 레디스에 write를 할 수 없는 등 다양한 장애 사례가 존재합니다.

따라서, 꼭 필요한 경우에만 데이터를 저장하는 것이 좋습니다. 레디스를 캐시 용도로 이용할 때에는 RDB와 AOF를 쓰지 마세요. 만약 스토리지 용도로 사용한다면 RDB보다 AOF를 권장드리며, 관련 파라미터도 수정하는 것이 안전합니다. 파라미터에 관한 설명은 아래에서 더 이어가겠습니다.

오버스펙을 피해보아요

앞서 살펴본 것과 같이, 레디스를 어떻게 배치하는지에 따라 장단점이 달라집니다. 각 구성에 대한 정확한 이해 없이 대충 레디스를 이용하면 리소스 낭비는 물론, 이로 인해 장애가 발생할 가능성도 존재합니다. (ex. 클러스터가 제일 좋으니까 클러스터 써볼까? 서버 하나에 레디스 인스턴스 6개 띄워보자! -> Max Memory 설정 없고, Persistence 설정 킨 상태에서 사용률 증가한다면 D.I.E ) 따라서 서비스 도입 전 어떤 구성의 레디스를 사용해야 할 지 충분한 고민이 필요합니다.

그래서 도대체 어떤 걸 쓰면 되는걸까? 하는 분들은 아래 그림을 참고해주시기 바랍니다. 물론 서비스에 따라 구성이 약간씩 변할 수 있습니다. Sentinel 구조에서 Replica의 개수가 달라지거나, 혹은 강력한 고가용성을 위해 클러스터를 7개 노드로 구성할 수도 있겠죠. 이렇게 결정된 구조에서 데이터를 영구 저장해야한다면 Persistence 옵션을 추가하면 되겠죠? 1.png

위험한 커맨드

레디스는 Single Thread로 동작합니다 (정확히는, 커맨드를 처리하는 쓰레드가 한 개입니다). 그렇기 때문에 만약 실행이 오래 걸리는 명령어 한 개가 쓰레드를 잡아먹는다면, 나머지 커맨드는 밀리게 됩니다. 이 또한 장애 상황으로 이어질 수 있는 케이스입니다. 따라서 다음 커맨드는 사용 전에 내가 진짜 지금 이 커맨드를 날려야만 하나?! 다시 한번 생각해보아요.

※ KEYS *

KEYS *는 레디스에 저장된 모든 key를 출력하는 커맨드입니다. 논리적으로 O(n)만큼의 시간이 필요하기 때문에, 메모리에 저장된 값이 많을 때 이 커맨드를 사용하면 큰일 날 수 있습니다. KEYS는 SCAN 으로 대체 가능합니다. 커서를 통해 key의 일부분을 조회할 수 있으며, KEYS와 동일하게 GLOB 패턴도 사용할 수 있습니다.

※ FLUSHALL / FLUSHDB

메모리에 존재하는 전체 데이터를 삭제하는 커맨드입니다. 당연한 얘기지만 모든 데이터가 삭제되기 때문임은 물론, O(n)의 시간이 필요하기 때문에 주의해서 사용해야 합니다.

※ SAVE

다른 클라이언트의 커맨드를 차단하며 전체 메모리 내용을 파일로 저장합니다.

※ MONITOR

레디스에 연결된 모든 클라이언트에서 보낸 모든 커맨드를 보여주는 커맨드입니다. 레디스 공식 문서 에 의하면 한개 클라이언트에서 MONITOR 를 사용해서 모든 커맨드를 모니터링 하는 동안 전체 처리량은 50% 이상 감소할 수 있다고 합니다.

★redis.conf★

레디스를 설치한 뒤 기본 파라미터값을 그대로 사용하는 것도 생각지 못한 장애를 발생시킬 수 있습니다. 레디스 설치 후 꼭 확인해야 할 파라미터들을 정리해봤습니다.

보안을 위한 파라미터

bind <server IP>
protected-mode yes
requirepass <password>

보안을 위해 protected-mode는 yes 로, requirepass에는 접속할 때 사용할 패스워드를 입력합니다. 레디스에 접속해야 하는 서버의 IP를 bind에 모두 추가해주세요. 이 경우 레디스는 bind에 추가된 서버와만 연결할 수 있습니다.

데이터를 파일로 저장하는 persistence 기능

# RDB
save ""
stop-writes-on-bgsave-error no

# AOF
appendonly no
auto-aof-rewrite-percentage 100

캐시 용도로만 사용한다면 RDB 파일을 저장하는 옵션인 save는 "" 로 설정하는 것을 권장합니다. 만약 이 설정을 켜야한다면 stop-writes-on-bgsave-error 는 꺼주세요. 이 옵션이 yes 일 때 RDB 파일 저장에 실패하면 곧바로 레디스에 write할 수 없게 됩니다. AOF파일을 저장하는 옵션인 appendonly도 캐시용으로 사용할 때에는 no 로 설정하는 것이 좋습니다. 그리고 Append Only 한 AOF 파일은 rewrite를 하지 않으면 계속 늘어나기 때문에 auto-aof-rewrite-percentage는 100으로 (100% 크기) 지정하고 주기적으로 rewrite 될 수 있도록 해야 합니다.

복제기능을 사용한다면

replicaof <마스터ip> <마스터port>
masterauth <마스터의 requirepass>

콘솔창에 연결한 상태로 replication을 사용할 수도 있지만, 설정 파일에 마스터의 정보를 지정한 채로 서버를 시작할 수도 있습니다. 이 파라미터는 복제 노드에 추가해야 합니다.

기타 설정

daemonize yes

daemonize를 no 로 설정할 경우(default 설정) 레디스 서버 실행 시 서버 메시지가 화면에 표시되고 리눅스 프롬프트가 떨어지지 않는 foreground로 실행됩니다. 이 경우 Ctrl+C를 하면 레디스 서버가 종료됩니다. 따라서 서버를 background로 실행하기 위해 daemonize를 yes로 설정하는 것이 좋습니다.

maxmemory <가용 메모리의 60~70%>
maxmemory-policy volatile-lru

maxmemory 값이 0이면 swap메모리를 사용할 때까지 메모리는 계속 커질 수 있습니다. persistence 기능을 사용한다거나, 복제 노드를 가질 경우에는 fork() 가 발생할 수 있으니 메모리 사용에 더 주의해야 합니다. 권장하는 값은 가용 메모리의 60~70%선에서 max memory를 설정하는 것입니다.

또한 메모리가 꽉 찼을 때 데이터들을 어떻게 처리하는지는 maxmemory-policy 값에 따라 달라집니다. 기본값은 noeviction 으로, 메모리가 가득 차면 더이상 새로운 입력을 받지 않겠다는 정책입니다. volatile-lru 는 가장 최근에 사용하지 않은 값을 삭제하는 정책입니다. 서비스 특성에 따라 다르겠지만, 캐시용도로 사용할 경우 필요 없는 값을 삭제하고 새로운 입력을 받아들이는 것이 좋을 테니, 이때에는 volatile-lru을 사용하는 것을 권장합니다.

EasyCache (Toast Cloud)

지금까지 레디스의 기초부터 클러스터, 장애를 일으킬 수 있는 포인트까지 쭉 알아보았습니다. 레디스를 이용하고 싶은 마음이 마구마구 생기셨나요? 생각보다 주의해야 할 점이 많아서 헷갈리시는 분도 계실 것이라고 생각합니다.

그래서 소개해 드립니다. 아마존 엘라스틱캐시에 버금가는 토클의 이지캐시!

이지캐시를 이용하면 서버 파라미터나 메모리, 파라미터 등을 고민하지 않고 바로 레디스를 이용 할 수 있을 뿐 아니라, 모니터링도 가능하며, 특정 상황에 알림을 받을 수 있습니다. 2020년 2월 현재 sentinel을 이용한 HA가 가능하며, 앞으로 더 많은 기능이 출시될 예정입니다. 자세한 사항은 EasyCache 사용자 가이드를 참고하세요.