Redis 기본 - 아키텍처

profile image purple-mocha 2023. 11. 24. 14:03

회사에서 redis를 많이 활용하고 있어서 관련해서 공부가 필요하다고 느꼈습니다.

 

아무래도 단순하게 redis의 자료형과 함수만 알고 있는 것 보다,

엔진이나 아키텍처를 이해하고 좀 더 딥다이브해야 다방면으로 활용할 수 있을 것 같아서입니다.

 

먼저 아키텍처부터 정리를 했습니다.

 

참고: http://www.redisgate.com/redis/configuration/redis_overview.php

 

비교

보통 저는 aws에서 제공하는 완전관리형 서비스를 주로 사용해서,

elastic cache로 사용할 수 있는 인메모리 DB인 memcached와 redis를 비교해보았습니다.

https://aws.amazon.com/ko/elasticache/redis-vs-memcached/

 

지원되는것만 보도 redis가 훨씬 많아서

단순히 캐싱용으로만 쓰지 않고, 큐나 스택 그리고 pub/sub 같은 것을 다른 서비스 구축없이 이용하려면 redis를 사용하는 것이 더 좋아보입니다.

 

그리고 레디스가 더 많은 자료형을 지원하기 때문에 더 높은 확장성을 가지고 있습니다.

 

간편하기 캐싱용으로만 사용할 db가 아니라면

redis를 이용하는게 여러모로 이득을 취할 수 있을 것 같습니다.

 

영속화

레디스는 휘발성이 있기에, 데이터를 백업해두기 위해 영속화 기능을 지원합니다.

 

레디스에는 영속화를 위해 두가지 기능이 있습니다.

 

RDB

특정 시점에 메모리의 모든 데이터를 전부 덤프떠서 dump.rdb 파일로 저장하는 방식입니다.

스냅샷과 같다고 볼 수 있습니다.

 

rdb방식은 내가 5분안에 1번 이상 redis에 생성/수정하면 디스크를 기록하고 싶을 때 저장조건은 "save 300 10" 옵션을 줘서 사용합니다.

참고로 너무 길게 잡으면 그 사이에 장애나면 결국 유실이므로 의미가 없습니다.

 

또는 BGSAVE(비긴 세이브)명령으로 수동으로 save할 수도 있습니다.

 

레디스는 rdb가 안되면 쓰기 요청을 거부하는 옵션을 켤 수 있습니다. 근데 쓰기 안되도 서비스가 계속되는게 더 중요하면 끄는게 낫습니다.

 

rdb는 프로세스를 따로 포크해서 디스크쓰기를 하기때문에 애플리케이션의 성능에는 영향을 주지 않습니다.

다만, redis cpu io가 높아지므로 주의할 필요가 있다.

 

장점은 뭘까요? 서버 시작할 때 rdb로 로딩하는 속도가 aof보다 빠르다.

aof는 rdb와 다른 레디스의 영속화 방식입니다. 

 

바로 알아보도록 하겠습니다.

 

AOF

모든 데이터 말고 변경된 데이터만 appendonly.aof 쓰는 방법입니다.

조회 이외의 명령이 생길때마다 전부 기록하는 always 옵션이 있는데 사실 이 옵션은 메모리DB가 아닐 정도로 성능이 떨어져서 추천하지 않습니다.

 

보통 많이 사용하는 옵션은 everysec이 있는데 1초마다 디스크에 쓰는 걸로 유실도 최소화하고 성능도 보장해줍니다.

 

근데 incr같은거 쓰면 그때마다 계속 파일을 쓰니까 os 파일 사이즈가 커져서 문제가 생길 수 있으므로 특정 시점에 rewrite를 하는 기능을 사용해서 이전 기록 싹 지우고 최종 데이터만 기록되게 할 수 있습니다.

특정 시점은 처음 레디스 시작할 때 aof파일 사이즈로부터 몇 퍼센트커졌는가 또는 용량을 기준으로 설정할 수 있습니다.

또는 BGREWRITEAOF(비긴 리라이터)명령으로 수동으로 시킬 수도 있습니다.

 

영속화를 하는 이유

테스트코드 작성하다가 테스트 독립성 지키겠다고 flushAll하는데 이걸 운영에서 해버리면 복구 할때 유용합니다.

그땐 바로 레디스 셧다운하고 appendonly.aof파일을 vi로 켜서 flushall 명령만 지우고 다시 레디스 시작시키면 db를 살릴 수 있습니다. flushAll 명령은 다음 세줄입니다.

*1
$8
flushall

 

 

HA 무중단

레드스를 구성하는 방법은 여러가지고 있습니다.

 

그 중 차례대로 서버 1대부터 3대 이상까지

무중단 서비스가 가능하도록

차례대로 업그레이드하며 살펴보겠습니다.

 

Standalone

서버 1대로만 구성합니다.

no ha로 마스터만 있습니다. 

 

이중화

서버 2대로 구성합니다.

슬레이브가 마스터를 실시간으로 카피합니다.

 

half ha로 마스터가 다운되면 슬레이브를 마스터로 승격시키고 애플리케이션이 새로운 마스터에 접속할 수 있게 새로 구성해야합니다.

 

센티널

완전 HA로 무중단 서비스가 가능해집니다.

이중화에서 서버 하나 더 추가해서 총 3개의 서버로 구성합니다.

 

센티널이 마스터 감시하다가 다운되면 슬레이브를 마스터로 승격시켜줍니다.

failover 테스트를 위해 마스터를 중지해보면 슬레이브가 마스터로 승격되어있는 것을 확인할 수 있습니다.

 

다시 원래 마스터를 재실행하면 얘는 자기가 마스턴줄 알고 aof랑 rdb를 읽기하는데 어차피 슬레이브로 바뀌게 되어 다시 버려집니다.

그래서 전 마스터를 재실행할 때 aof랑 rdb파일은 어디 다른데 옮겨놓는게 좋습니다.

 

주의할점은 내가 레디스 문제생겨서 센티널 접속해서 서보 정보를 요청하면 이미 다운된 서버를 리턴하기 때문에 꼭 센티널에서 마스터 status를 요청해서 다운된 건 아닌지 봐야한합니다.

 

그리고 복제가 먼저 다운되고 마스터가 다운되고 복제를 시작시키면 여전히 복입니제다. 그래서 복제를 마스터로 실행시키려면 복제의 redis.conf의 slaveof를 삭제해야합니다.

 

만약 복제가 여러개라면 slave-priority를 설정해서 가장 작은 값이 가장 먼저 마스터로 선정되게 할 수 있습다. 복제의 복제 즉, 2차 복제는 센티널이 마스터로 승격하는 대상으로 인지하지 않는 점을 주의합니다.

 

그럼에도 2차복제를 하는 이유는 복제가 마스터가 되면 2차복제는 1차복제가 되고 새마스터가 장애가 발생하면 1차복제가 된 2차복제가 최종적으로 마스터가 될 수 있기 때문입니다.

 

클러스터

마찬가지로 완전 HA로 무중단 서비스가 가능해집니다.

샤딩을 제공하는데, 마스터가 3대면 데이터를 3대에 나누어 저장하는 방식입다.

 

키에 hash함수를 적용해서 값을 추출해서 이 값을 마스터서버에 할당한 다음, 해시함수가 1~100까지 나오면 1~33은 1번 마스터, 34~66은 2번 마스터, 67~100은 3번 마스터 이런식으로 할당합니다.

 

그러면 클라이언트는 이 해시를 동일하게 가져와서, 키가 입력되면 hash를 적용해 어느 마스터에 저장할 지 판단하고 보냅니다.

 

최소 3대로 구성되어서 각 마스터는 데이터처리와 센티널역할을 동시에 수행합나다.

마스터 중 리더가 있는데, 리더가 다운되면 살아있는 마스터 중에 하나가 리더가 되고 전리더의 슬레이브르르 마스터로 승격시킵니다.

  • Redis Cluster의 장점/단점
    • 장점
      • 자체적인 Primary, Secondary Failover.
      • Slot 단위의 데이터 관리.
    • 단점
      • 메모리 사용량이 더 많음
      • Migration 자체는 관리자가 시점을 결정해야 함.
      • Library 구현이 필요함.

 

멀티스레드

버전 3.2까지는 aof관련 처리를 서브쓰레드에서 해서 레디스를 싱글스레드라 했는데, 4.0부터는 unlink 명령을 서브스레드에서 하면서 이제 멀티스레드라고 부르기도합니다.

 

다만, 디스크 I/O와 관련된 느린 I/O 작업을 백그라운드에서 수행하기 위해 여러 개의 스레드를 사용하지만 Redis가 단일 스레드를 사용하여 모든 요청을 처리한다는 사실은 바뀌지 않습니다.

모든 요청이 순차적으로 처리되며, 이는 Node.js의 작동 방식과 매우 유사합니다.

 

그래서 Multi Thread를 지원하면서 2.5배 성능을 빠르게 되었지만 여전히 명령의 실행은 Single Thread로 실행되기 때문에 Atomic이 깨지지 않습니다.

 

Single Thread로 빠른데 Multi Thread를 도입한 이유는 Redis의 성능 병목 현상중 하나인 네트워크 IO 작업 때문입니다. 프로젝트에서 일부 큰 키-값 쌍을 삭제해야 하는 경우 단시간에 삭제할 수 없으면 단일 스레드의 경우 후속 작업이 차단됩니다.

 

메인스레드

아래 서브스레드에서 하는 거 빼고 다 처리 (클라이언트 요청은 여전히 싱글스레드로 처리된다고 볼 수 있음)

 

서브스레드1번

aof 리라이트할 때 새파일에 리라이팅하고 기존파일을 클로즈하는 역할, aof활성화 안해도 스레드는 생성함

 

서브스레드2번

1초마다 aof에 쓸 때 동작

 

서브스레드 3번

unlink, 비동기 flush all(레디스서버의 모든 데이터 삭제), flushdb(현재사용중인 db의 모든 데이터 삭제) 명령을 처리

 

 

 

 

다음에는 레디스에서 자주 사용되는 자료형과 함수에 대해 정리해보겠습니다.